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