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