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