Use internal _xdr_* functions, check for NULL pointers, use NIS+
[kopensolaris-gnu/glibc.git] / nis / nis_table.c
1 /* Copyright (c) 1997, 1998 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
23 #include "nis_xdr.h"
24 #include "nis_intern.h"
25
26 static void
27 splitname (const_nis_name name, nis_name *ibr_name, int *srch_len,
28            nis_attr **srch_val)
29 {
30   char *cptr, *key, *val, *next;
31   int size;
32
33   if (name == NULL)
34     return;
35
36   cptr = strdup (name);
37   if (srch_len)
38     *srch_len = 0;
39   if (srch_val)
40     *srch_val = NULL;
41   size = 0;
42
43   /* Not of "[key=value,key=value,...],foo.." format? */
44   if (cptr[0] != '[')
45     {
46       *ibr_name = cptr;
47       return;
48     }
49
50   *ibr_name = strchr (cptr, ']');
51   if (*ibr_name == NULL || (*ibr_name)[1] != ',')
52     {
53       free (cptr);
54       *ibr_name = NULL;
55       return;
56     }
57
58   *ibr_name[0] = '\0';
59   *ibr_name += 2;
60   *ibr_name = strdup (*ibr_name);
61
62   if (srch_len == NULL || srch_val == NULL)
63     {
64       free (cptr);
65       return;
66     }
67
68   key = (cptr) + 1;
69   do
70     {
71       next = strchr (key, ',');
72       if (next)
73         {
74           next[0] = '\0';
75           ++next;
76         }
77
78       val = strchr (key, '=');
79       if (!val)
80         {
81           free (cptr);
82           *srch_val = malloc (sizeof (nis_attr));
83           if (*srch_val == NULL)
84             {
85               free (cptr);
86               free (*ibr_name);
87               *ibr_name = NULL;
88               return;
89             }
90           (*srch_val)[0].zattr_val.zattr_val_len = 0;
91           (*srch_val)[0].zattr_val.zattr_val_val = NULL;
92           return;
93         }
94
95       val[0] = '\0';
96       ++val;
97
98       if ((*srch_len) + 1 >= size)
99         {
100           size += 10;
101           if (size == 10)
102             *srch_val = malloc (size * sizeof (char *));
103           else
104             *srch_val = realloc (val, size * sizeof (char *));
105           if (*srch_val == NULL)
106             {
107               free (cptr);
108               free (*ibr_name);
109               *ibr_name = NULL;
110               return;
111             }
112         }
113
114       (*srch_val)[*srch_len].zattr_ndx = strdup (key);
115       if (((*srch_val)[*srch_len].zattr_ndx) == NULL)
116         {
117           free (cptr);
118           free (*ibr_name);
119           *ibr_name = NULL;
120           return;
121         }
122       (*srch_val)[*srch_len].zattr_val.zattr_val_len = strlen (val) + 1;
123       (*srch_val)[*srch_len].zattr_val.zattr_val_val = strdup (val);
124       if ((*srch_val)[*srch_len].zattr_val.zattr_val_val == NULL)
125         {
126           free (cptr);
127           free (*ibr_name);
128           *ibr_name = NULL;
129           return;
130         }
131       ++(*srch_len);
132
133       key = next;
134
135     }
136   while (next);
137
138   free (cptr);
139 }
140
141 static struct ib_request *
142 __create_ib_request (const_nis_name name, struct ib_request *ibreq,
143                      u_long flags)
144 {
145   splitname (name, &ibreq->ibr_name, &ibreq->ibr_srch.ibr_srch_len,
146              &ibreq->ibr_srch.ibr_srch_val);
147   if (ibreq->ibr_name == NULL)
148     return NULL;
149
150   ibreq->ibr_flags = flags;
151   ibreq->ibr_obj.ibr_obj_len = 0;
152   ibreq->ibr_obj.ibr_obj_val = NULL;
153   ibreq->ibr_cbhost.ibr_cbhost_len = 0;
154   ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
155   ibreq->ibr_bufsize = 0;
156   ibreq->ibr_cookie.n_len = 0;
157   ibreq->ibr_cookie.n_bytes = NULL;
158
159   return ibreq;
160 }
161
162 nis_result *
163 nis_list (const_nis_name name, u_long flags,
164           int (*callback) (const_nis_name name,
165                            const nis_object *object,
166                            const void *userdata),
167           const void *userdata)
168 {
169   nis_result *res = NULL;
170   ib_request *ibreq = calloc (1, sizeof (ib_request));
171   int status;
172   int count_links = 0;          /* We will only follow NIS_MAXLINKS links! */
173   int done = 0;
174   nis_name *names;
175   nis_name namebuf[2] = {NULL, NULL};
176   int name_nr = 0;
177   nis_cb *cb = NULL;
178
179   res = calloc (1, sizeof (nis_result));
180   if (res == NULL)
181     return NULL;
182
183   if (__create_ib_request (name, ibreq, flags) == NULL)
184     {
185       NIS_RES_STATUS (res) = NIS_BADNAME;
186       return res;
187     }
188
189   if (flags & EXPAND_NAME)
190     {
191       names = nis_getnames (ibreq->ibr_name);
192       free (ibreq->ibr_name);
193       ibreq->ibr_name = NULL;
194       if (names == NULL)
195         {
196           NIS_RES_STATUS (res) = NIS_BADNAME;
197           return res;
198         }
199       ibreq->ibr_name = strdup (names[name_nr]);
200     }
201   else
202     {
203       names = namebuf;
204       names[name_nr] = ibreq->ibr_name;
205     }
206
207   cb = NULL;
208
209   if (flags & FOLLOW_PATH || flags & ALL_RESULTS)
210     {
211       nis_result *lres;
212       u_long newflags = flags & ~FOLLOW_PATH & ~ALL_RESULTS;
213       char table_path[NIS_MAXPATH + 1];
214       char *ntable, *p;
215       u_long done = 0, failures = 0;
216
217       while (names[name_nr] != NULL && !done)
218         {
219           lres = nis_lookup (names[name_nr], newflags);
220           if (lres == NULL || NIS_RES_STATUS (lres) != NIS_SUCCESS)
221             {
222               NIS_RES_STATUS (res) = NIS_RES_STATUS (lres);
223               nis_freeresult (lres);
224               ++name_nr;
225               continue;
226               }
227
228           /* nis_lookup handles FOLLOW_LINKS,
229              so we must have a table object.  */
230           if (__type_of (NIS_RES_OBJECT (lres)) != NIS_TABLE_OBJ)
231             {
232               nis_freeresult (lres);
233               NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
234               break;
235             }
236
237           /* Save the path, discard everything else.  */
238           snprintf (table_path, NIS_MAXPATH, "%s:%s", names[name_nr],
239                     NIS_RES_OBJECT (lres)->TA_data.ta_path);
240           nis_freeresult (lres);
241           free (res);
242           res = NULL;
243
244           p = table_path;
245
246           while (((ntable = strsep (&p, ":")) != NULL) && !done)
247             {
248               char *c;
249
250               if (res != NULL)
251                 nis_freeresult (res);
252
253               /* Do the job recursive here!  */
254               if ((c = strchr(name, ']')) != NULL)
255                 {
256                   /* Have indexed name ! */
257                   int index_len = c - name + 2;
258                   char buf[index_len + strlen (ntable) + 1];
259
260                   c = __stpncpy (buf, name, index_len);
261                   strcpy (c, ntable);
262                   res = nis_list (buf, newflags, callback,userdata);
263                 }
264               else
265                 res = nis_list (ntable, newflags, callback, userdata);
266               if (res == NULL)
267                 return NULL;
268               switch (NIS_RES_STATUS (res))
269                 {
270                 case NIS_SUCCESS:
271                 case NIS_CBRESULTS:
272                   if (!(flags & ALL_RESULTS))
273                     done = 1;
274                   break;
275                 case NIS_PARTIAL: /* The table is correct, we doesn't found
276                                      the entry */
277                   break;
278                 default:
279                   if (flags & ALL_RESULTS)
280                     ++failures;
281                   else
282                     done = 1;
283                   break;
284                 }
285             }
286           if (NIS_RES_STATUS (res) == NIS_SUCCESS && failures)
287             NIS_RES_STATUS (res) = NIS_S_SUCCESS;
288           if (NIS_RES_STATUS (res) == NIS_NOTFOUND && failures)
289             NIS_RES_STATUS (res) = NIS_S_NOTFOUND;
290           break;
291         }
292     }
293   else
294     {
295       if (callback != NULL)
296         {
297           cb = __nis_create_callback (callback, userdata, flags);
298           ibreq->ibr_cbhost.ibr_cbhost_len = 1;
299           ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
300           }
301
302       while (!done)
303         {
304           memset (res, '\0', sizeof (nis_result));
305
306           status = __do_niscall (ibreq->ibr_name, NIS_IBLIST,
307                                  (xdrproc_t) _xdr_ib_request,
308                                  (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
309                                  (caddr_t) res, flags, cb);
310           if (status != NIS_SUCCESS)
311             NIS_RES_STATUS (res) = status;
312
313           switch (NIS_RES_STATUS (res))
314             {
315             case NIS_PARTIAL:
316             case NIS_SUCCESS:
317             case NIS_S_SUCCESS:
318               if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
319                   flags & FOLLOW_LINKS)         /* We are following links.  */
320                 {
321                   /* If we hit the link limit, bail.  */
322                   if (count_links > NIS_MAXLINKS)
323                     {
324                       NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
325                       ++done;
326                       break;
327                     }
328                   if (count_links)
329                     free (ibreq->ibr_name);
330                   ++count_links;
331                   free (ibreq->ibr_name);
332                   ibreq->ibr_name =
333                     strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
334                   if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
335                     if (ibreq->ibr_srch.ibr_srch_len == 0)
336                       {
337                         ibreq->ibr_srch.ibr_srch_len =
338                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
339                         ibreq->ibr_srch.ibr_srch_val =
340                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
341                       }
342                   nis_freeresult (res);
343                   res = calloc (1, sizeof (nis_result));
344                 }
345               else
346                 ++done;
347               break;
348             case NIS_CBRESULTS:
349               /* Calback is handled in nis_call.c (__do_niscall2),
350                  but we have to change the error code */
351               NIS_RES_STATUS (res) = cb->result;
352               ++done;
353               break;
354             case NIS_UNAVAIL:
355               /* NIS+ is not installed, or all servers are down.  */
356               ++done;
357               break;
358             default:
359               /* Try the next domainname if we don't follow a link.  */
360               if (count_links)
361                 {
362                   free (ibreq->ibr_name);
363                   NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
364                   ++done;
365                   break;
366                 }
367               ++name_nr;
368               if (names[name_nr] == NULL)
369                 {
370                   ++done;
371                   break;
372                 }
373               ibreq->ibr_name = names[name_nr];
374               break;
375             }
376         }
377     }                           /* End of not FOLLOW_PATH.  */
378
379   if (names != namebuf)
380     nis_freenames (names);
381
382   if (cb)
383     {
384       __nis_destroy_callback (cb);
385       ibreq->ibr_cbhost.ibr_cbhost_len = 0;
386       ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
387     }
388
389   nis_free_request (ibreq);
390
391   return res;
392 }
393
394 nis_result *
395 nis_add_entry (const_nis_name name, const nis_object *obj2, u_long flags)
396 {
397   nis_object obj;
398   nis_result *res;
399   nis_error status;
400   ib_request *ibreq = calloc (1, sizeof (ib_request));
401   char buf1[strlen (name) + 20];
402   char buf4[strlen (name) + 20];
403
404   res = calloc (1, sizeof (nis_result));
405   if (res == NULL)
406     return NULL;
407
408   if (ibreq == NULL)
409     {
410       NIS_RES_STATUS (res) = NIS_NOMEMORY;
411       return res;
412     }
413
414   if (__create_ib_request (name, ibreq, flags) == NULL)
415     {
416       NIS_RES_STATUS (res) = NIS_BADNAME;
417       return res;
418     }
419
420   memcpy (&obj, obj2, sizeof (nis_object));
421
422   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
423     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
424
425   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
426     obj.zo_owner = nis_local_principal ();
427
428   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
429     obj.zo_group = nis_local_group ();
430
431   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
432
433   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
434   if (ibreq->ibr_obj.ibr_obj_val == NULL)
435     {
436       NIS_RES_STATUS (res) = NIS_NOMEMORY;
437       return res;
438     }
439   ibreq->ibr_obj.ibr_obj_len = 1;
440
441   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
442                               (xdrproc_t) _xdr_ib_request,
443                               (caddr_t) ibreq,
444                               (xdrproc_t) _xdr_nis_result,
445                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
446     NIS_RES_STATUS (res) = status;
447
448   nis_free_request (ibreq);
449
450   return res;
451 }
452
453 nis_result *
454 nis_modify_entry (const_nis_name name, const nis_object *obj2, u_long flags)
455 {
456   nis_object obj;
457   nis_result *res;
458   nis_error status;
459   ib_request *ibreq = calloc (1, sizeof (ib_request));
460   char buf1[strlen (name) + 20];
461   char buf4[strlen (name) + 20];
462
463   res = calloc (1, sizeof (nis_result));
464
465   if (__create_ib_request (name, ibreq, flags) == NULL)
466     {
467       NIS_RES_STATUS (res) = NIS_BADNAME;
468       return res;
469     }
470
471   memcpy (&obj, obj2, sizeof (nis_object));
472
473   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
474     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
475
476   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
477     obj.zo_owner = nis_local_principal ();
478
479   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
480     obj.zo_group = nis_local_group ();
481
482   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
483
484   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
485   if (ibreq->ibr_obj.ibr_obj_val == NULL)
486     {
487       NIS_RES_STATUS (res) = NIS_NOMEMORY;
488       return res;
489     }
490   ibreq->ibr_obj.ibr_obj_len = 1;
491
492   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
493                               (xdrproc_t) _xdr_ib_request,
494                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
495                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
496     NIS_RES_STATUS (res) = status;
497
498   nis_free_request (ibreq);
499
500   return res;
501 }
502
503 nis_result *
504 nis_remove_entry (const_nis_name name, const nis_object *obj,
505                   u_long flags)
506 {
507   nis_result *res;
508   ib_request *ibreq = calloc (1, sizeof (ib_request));
509   nis_error status;
510
511   res = calloc (1, sizeof (nis_result));
512   if (res == NULL)
513     return NULL;
514
515   if (ibreq == NULL)
516     {
517       NIS_RES_STATUS (res) = NIS_NOMEMORY;
518       return res;
519     }
520
521   if (__create_ib_request (name, ibreq, flags) == NULL)
522     {
523       NIS_RES_STATUS (res) = NIS_BADNAME;
524       return res;
525     }
526
527   if (obj != NULL)
528     {
529       ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
530       if (ibreq->ibr_obj.ibr_obj_val == NULL)
531         {
532           NIS_RES_STATUS (res) = NIS_NOMEMORY;
533           return res;
534         }
535       ibreq->ibr_obj.ibr_obj_len = 1;
536     }
537
538   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
539                               (xdrproc_t) _xdr_ib_request,
540                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
541                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
542     NIS_RES_STATUS (res) = status;
543
544   nis_free_request (ibreq);
545
546   return res;
547 }
548
549 nis_result *
550 nis_first_entry (const_nis_name name)
551 {
552   nis_result *res;
553   ib_request *ibreq = calloc (1, sizeof (ib_request));
554   nis_error status;
555
556   res = calloc (1, sizeof (nis_result));
557   if (res == NULL)
558     return NULL;
559
560   if (ibreq == NULL)
561     {
562       NIS_RES_STATUS (res) = NIS_NOMEMORY;
563       return res;
564     }
565
566   if (__create_ib_request (name, ibreq, 0) == NULL)
567     {
568       NIS_RES_STATUS (res) = NIS_BADNAME;
569       return res;
570     }
571
572   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
573                               (xdrproc_t) _xdr_ib_request,
574                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
575                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
576     NIS_RES_STATUS (res) = status;
577
578   nis_free_request (ibreq);
579
580   return res;
581 }
582
583 nis_result *
584 nis_next_entry (const_nis_name name, const netobj *cookie)
585 {
586   nis_result *res;
587   ib_request *ibreq = calloc (1, sizeof (ib_request));
588   nis_error status;
589
590   res = calloc (1, sizeof (nis_result));
591   if (res == NULL)
592     return NULL;
593
594   if (ibreq == NULL)
595     {
596       NIS_RES_STATUS (res) = NIS_NOMEMORY;
597       return res;
598     }
599
600   if (__create_ib_request (name, ibreq, 0) == NULL)
601     {
602       NIS_RES_STATUS (res) = NIS_BADNAME;
603       return res;
604     }
605
606   if (cookie != NULL)
607     {
608       ibreq->ibr_cookie.n_bytes = malloc (cookie->n_len);
609       if (ibreq->ibr_cookie.n_bytes == NULL)
610         {
611           NIS_RES_STATUS (res) = NIS_NOMEMORY;
612           nis_free_request (ibreq);
613           return res;
614         }
615       memcpy (ibreq->ibr_cookie.n_bytes, cookie->n_bytes, cookie->n_len);
616       ibreq->ibr_cookie.n_len = cookie->n_len;
617     }
618
619   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
620                               (xdrproc_t) _xdr_ib_request,
621                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
622                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
623     NIS_RES_STATUS (res) = status;
624
625   nis_free_request (ibreq);
626
627   return res;
628 }