(_nss_nis_getservbyname_r): If protocol
[kopensolaris-gnu/glibc.git] / nis / nis_table.c
1 /* Copyright (c) 1997, 1998, 1999, 2003 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    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   size_t 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       if (ibreq->ibr_name == NULL)
193         {
194           nis_free_request (ibreq);
195           NIS_RES_STATUS (res) = NIS_NOMEMORY;
196           return res;
197         }
198     }
199   else
200     {
201       names = namebuf;
202       names[name_nr] = ibreq->ibr_name;
203     }
204
205   cb = NULL;
206
207   while (!done)
208     {
209       dir_binding bptr;
210       directory_obj *dir = NULL;
211
212       memset (res, '\0', sizeof (nis_result));
213
214       status = __nisfind_server (ibreq->ibr_name, &dir);
215       if (status != NIS_SUCCESS)
216         {
217           nis_free_request (ibreq);
218           NIS_RES_STATUS (res) = status;
219           return res;
220         }
221
222       status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
223                                  dir->do_servers.do_servers_len, flags);
224       if (status != NIS_SUCCESS)
225         {
226           nis_free_request (ibreq);
227           NIS_RES_STATUS (res) = status;
228           nis_free_directory (dir);
229           return res;
230         }
231
232       while (__nisbind_connect (&bptr) != NIS_SUCCESS)
233         if (__nisbind_next (&bptr) != NIS_SUCCESS)
234           {
235             __nisbind_destroy (&bptr);
236             nis_free_directory (dir);
237             nis_free_request (ibreq);
238             NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
239             return res;
240           }
241
242       if (callback != NULL)
243         {
244           cb = __nis_create_callback (callback, userdata, flags);
245           ibreq->ibr_cbhost.ibr_cbhost_len = 1;
246           ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
247         }
248
249     again:
250       clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
251                                (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
252                                (xdrproc_t) _xdr_nis_result,
253                                (caddr_t) res, RPCTIMEOUT);
254
255       if (clnt_status != RPC_SUCCESS)
256         NIS_RES_STATUS (res) = NIS_RPCERROR;
257       else
258         switch (NIS_RES_STATUS (res))
259           { /* start switch */
260           case NIS_PARTIAL:
261           case NIS_SUCCESS:
262           case NIS_S_SUCCESS:
263             if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
264                 flags & FOLLOW_LINKS)           /* We are following links.  */
265               {
266                 free (ibreq->ibr_name);
267                 ibreq->ibr_name = NULL;
268                 /* If we hit the link limit, bail.  */
269                 if (count_links > NIS_MAXLINKS)
270                   {
271                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
272                     ++done;
273                     break;
274                   }
275                 ++count_links;
276                 ibreq->ibr_name =
277                   strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
278                 if (ibreq->ibr_name == NULL)
279                   {
280                     nis_free_request (ibreq);
281                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
282                     return res;
283                   }
284                 if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
285                   if (ibreq->ibr_srch.ibr_srch_len == 0)
286                     {
287                       ibreq->ibr_srch.ibr_srch_len =
288                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
289                       ibreq->ibr_srch.ibr_srch_val =
290                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
291                     }
292                 nis_freeresult (res);
293                 res = calloc (1, sizeof (nis_result));
294                 if (res == NULL)
295                   {
296                     if (have_tablepath)
297                       free (tablepath);
298                     __nisbind_destroy (&bptr);
299                     nis_free_directory (dir);
300                     return NULL;
301                   }
302                 first_try = 1; /* Try at first the old binding */
303                 goto again;
304               }
305             else if ((flags & FOLLOW_PATH) &&
306                      NIS_RES_STATUS (res) == NIS_PARTIAL)
307               {
308                 if (!have_tablepath)
309                   {
310                     tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
311                     tableptr = tablepath;
312                     have_tablepath = 1;
313                   }
314                 if (tableptr == NULL)
315                   {
316                     ++done;
317                     break;
318                   }
319                 free (ibreq->ibr_name);
320                 ibreq->ibr_name = strsep (&tableptr, ":");
321                 if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
322                   {
323                     ibreq->ibr_name = strdup ("");
324                     if (ibreq->ibr_name == NULL)
325                       {
326                         nis_free_request (ibreq);
327                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
328                         return res;
329                       }
330                     ++done;
331                   }
332                 else
333                   {
334                     ibreq->ibr_name = strdup (ibreq->ibr_name);
335                     nis_freeresult (res);
336                     res = calloc (1, sizeof (nis_result));
337                     if (res == NULL || ibreq->ibr_name == NULL)
338                       {
339                         free (res);
340                         nis_free_request (ibreq);
341                         if (have_tablepath)
342                           free (tablepath);
343                         __nisbind_destroy (&bptr);
344                         nis_free_directory (dir);
345                         return NULL;
346                       }
347                     first_try = 1;
348                     goto again;
349                   }
350               }
351             else
352               ++done;
353             break;
354           case NIS_CBRESULTS:
355             if (cb != NULL)
356               {
357                 __nis_do_callback (&bptr, &res->cookie, cb);
358                 NIS_RES_STATUS (res) = cb->result;
359
360                 if (!(flags & ALL_RESULTS))
361                   ++done;
362                 else
363                   {
364                     if (!have_tablepath)
365                       {
366                         tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
367                         tableptr = tablepath;
368                         have_tablepath = 1;
369                       }
370                     if (tableptr == NULL)
371                       {
372                         ++done;
373                         break;
374                       }
375                     free (ibreq->ibr_name);
376                     ibreq->ibr_name = strsep (&tableptr, ":");
377                     if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
378                       {
379                         ibreq->ibr_name = strdup ("");
380                         ++done;
381                       }
382                     else
383                       ibreq->ibr_name = strdup (ibreq->ibr_name);
384                     if (ibreq->ibr_name == NULL)
385                       {
386                         nis_free_request (ibreq);
387                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
388                         return res;
389                       }
390                   }
391               }
392             break;
393           case NIS_SYSTEMERROR:
394           case NIS_NOSUCHNAME:
395           case NIS_NOT_ME:
396             /* If we had first tried the old binding, do nothing, but
397                get a new binding */
398             if (!first_try)
399               {
400                 if (__nisbind_next (&bptr) != NIS_SUCCESS)
401                   {
402                     ++done;
403                     break; /* No more servers to search */
404                   }
405                 while (__nisbind_connect (&bptr) != NIS_SUCCESS)
406                   {
407                     if (__nisbind_next (&bptr) != NIS_SUCCESS)
408                       {
409                         ++done;
410                         break; /* No more servers to search */
411                       }
412                   }
413                 goto again;
414               }
415             break;
416           default:
417             if (!first_try)
418               {
419                 /* Try the next domainname if we don't follow a link.  */
420                 free (ibreq->ibr_name);
421                 ibreq->ibr_name = NULL;
422                 if (count_links)
423                   {
424                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
425                     ++done;
426                     break;
427                   }
428                 ++name_nr;
429                 if (names[name_nr] == NULL)
430                   {
431                     ++done;
432                     break;
433                   }
434                 ibreq->ibr_name = strdup (names[name_nr]);
435                 if (ibreq->ibr_name == NULL)
436                   {
437                     nis_free_request (ibreq);
438                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
439                     return res;
440                   }
441                 first_try = 1; /* Try old binding at first */
442                 goto again;
443               }
444             break;
445           }
446       first_try = 0;
447
448       if (cb)
449         {
450           __nis_destroy_callback (cb);
451           ibreq->ibr_cbhost.ibr_cbhost_len = 0;
452           ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
453         }
454
455       __nisbind_destroy (&bptr);
456       nis_free_directory (dir);
457     }
458
459   if (names != namebuf)
460     nis_freenames (names);
461
462   nis_free_request (ibreq);
463
464   return res;
465 }
466
467 nis_result *
468 nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
469 {
470   nis_object obj;
471   nis_result *res;
472   nis_error status;
473   ib_request *ibreq;
474   size_t namelen = strlen (name);
475   char buf1[namelen + 20];
476   char buf4[namelen + 20];
477
478   res = calloc (1, sizeof (nis_result));
479   if (res == NULL)
480     return NULL;
481
482   if (name == NULL)
483     {
484       NIS_RES_STATUS (res) = NIS_BADNAME;
485       return res;
486     }
487
488   if ((ibreq = __create_ib_request (name, flags)) == NULL)
489     {
490       NIS_RES_STATUS (res) = NIS_BADNAME;
491       return res;
492     }
493
494   memcpy (&obj, obj2, sizeof (nis_object));
495
496   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
497     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
498
499   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
500     obj.zo_owner = nis_local_principal ();
501
502   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
503     obj.zo_group = nis_local_group ();
504
505   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
506
507   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
508   if (ibreq->ibr_obj.ibr_obj_val == NULL)
509     {
510       nis_free_request (ibreq);
511       NIS_RES_STATUS (res) = NIS_NOMEMORY;
512       return res;
513     }
514   ibreq->ibr_obj.ibr_obj_len = 1;
515
516   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
517                               (xdrproc_t) _xdr_ib_request,
518                               (caddr_t) ibreq,
519                               (xdrproc_t) _xdr_nis_result,
520                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
521     NIS_RES_STATUS (res) = status;
522
523   nis_free_request (ibreq);
524
525   return res;
526 }
527
528 nis_result *
529 nis_modify_entry (const_nis_name name, const nis_object *obj2,
530                   unsigned int flags)
531 {
532   nis_object obj;
533   nis_result *res;
534   nis_error status;
535   ib_request *ibreq;
536   size_t namelen = strlen (name);
537   char buf1[namelen + 20];
538   char buf4[namelen + 20];
539
540   res = calloc (1, sizeof (nis_result));
541   if (res == NULL)
542     return NULL;
543
544   if (( ibreq =__create_ib_request (name, flags)) == NULL)
545     {
546       NIS_RES_STATUS (res) = NIS_BADNAME;
547       return res;
548     }
549
550   memcpy (&obj, obj2, sizeof (nis_object));
551
552   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
553     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
554
555   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
556     obj.zo_owner = nis_local_principal ();
557
558   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
559     obj.zo_group = nis_local_group ();
560
561   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
562
563   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
564   if (ibreq->ibr_obj.ibr_obj_val == NULL)
565     {
566       nis_free_request (ibreq);
567       NIS_RES_STATUS (res) = NIS_NOMEMORY;
568       return res;
569     }
570   ibreq->ibr_obj.ibr_obj_len = 1;
571
572   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
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_remove_entry (const_nis_name name, const nis_object *obj,
585                   unsigned int flags)
586 {
587   nis_result *res;
588   ib_request *ibreq;
589   nis_error status;
590
591   res = calloc (1, sizeof (nis_result));
592   if (res == NULL)
593     return NULL;
594
595   if (name == NULL)
596     {
597       NIS_RES_STATUS (res) = NIS_BADNAME;
598       return res;
599     }
600
601   if ((ibreq =__create_ib_request (name, flags)) == NULL)
602     {
603       NIS_RES_STATUS (res) = NIS_BADNAME;
604       return res;
605     }
606
607   if (obj != NULL)
608     {
609       ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
610       if (ibreq->ibr_obj.ibr_obj_val == NULL)
611         {
612           nis_free_request (ibreq);
613           NIS_RES_STATUS (res) = NIS_NOMEMORY;
614           return res;
615         }
616       ibreq->ibr_obj.ibr_obj_len = 1;
617     }
618
619   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
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 }
629
630 nis_result *
631 nis_first_entry (const_nis_name name)
632 {
633   nis_result *res;
634   ib_request *ibreq;
635   nis_error status;
636
637   res = calloc (1, sizeof (nis_result));
638   if (res == NULL)
639     return NULL;
640
641   if (name == NULL)
642     {
643       NIS_RES_STATUS (res) = NIS_BADNAME;
644       return res;
645     }
646
647   ibreq = __create_ib_request (name, 0);
648   if (ibreq == NULL)
649     {
650       NIS_RES_STATUS (res) = NIS_BADNAME;
651       return res;
652     }
653
654   status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
655                          (xdrproc_t) _xdr_ib_request,
656                          (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
657                          (caddr_t) res, 0, NULL);
658
659   if (status != NIS_SUCCESS)
660     NIS_RES_STATUS (res) = status;
661
662   nis_free_request (ibreq);
663
664   return res;
665 }
666
667 nis_result *
668 nis_next_entry (const_nis_name name, const netobj *cookie)
669 {
670   nis_result *res;
671   ib_request *ibreq;
672   nis_error status;
673
674   res = calloc (1, sizeof (nis_result));
675   if (res == NULL)
676     return NULL;
677
678   if (name == NULL)
679     {
680       NIS_RES_STATUS (res) = NIS_BADNAME;
681       return res;
682     }
683
684   ibreq = __create_ib_request (name, 0);
685   if (ibreq == NULL)
686     {
687       NIS_RES_STATUS (res) = NIS_BADNAME;
688       return res;
689     }
690
691   if (cookie != NULL)
692     {
693       ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
694       ibreq->ibr_cookie.n_len = cookie->n_len;
695     }
696
697   status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
698                          (xdrproc_t) _xdr_ib_request,
699                          (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
700                          (caddr_t) res, 0, NULL);
701
702   if (status != NIS_SUCCESS)
703     NIS_RES_STATUS (res) = status;
704
705   if (cookie != NULL)
706     {
707       /* Don't give cookie free, it is not from us */
708       ibreq->ibr_cookie.n_bytes = NULL;
709       ibreq->ibr_cookie.n_len = 0;
710     }
711
712   nis_free_request (ibreq);
713
714   return res;
715 }