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