Rewrite __create_ib_request.
[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 nis_result *
114 nis_list (const_nis_name name, u_long flags,
115           int (*callback) (const_nis_name name,
116                            const nis_object *object,
117                            const void *userdata),
118           const void *userdata)
119 {
120   nis_result *res = NULL;
121   ib_request *ibreq;
122   int status;
123   int count_links = 0;          /* We will only follow NIS_MAXLINKS links! */
124   int done = 0;
125   nis_name *names;
126   nis_name namebuf[2] = {NULL, NULL};
127   int name_nr = 0;
128   nis_cb *cb = NULL;
129
130   res = calloc (1, sizeof (nis_result));
131   if (res == NULL)
132     return NULL;
133
134   if (name == NULL)
135     {
136       NIS_RES_STATUS (res) = NIS_BADNAME;
137       return res;
138     }
139
140   if ((ibreq = __create_ib_request (name, flags)) == NULL)
141     {
142       NIS_RES_STATUS (res) = NIS_BADNAME;
143       return res;
144     }
145
146   if ((flags & EXPAND_NAME) &&
147       ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.')
148     {
149       names = nis_getnames (ibreq->ibr_name);
150       free (ibreq->ibr_name);
151       ibreq->ibr_name = NULL;
152       if (names == NULL)
153         {
154           NIS_RES_STATUS (res) = NIS_BADNAME;
155           return res;
156         }
157       ibreq->ibr_name = strdup (names[name_nr]);
158     }
159   else
160     {
161       names = namebuf;
162       names[name_nr] = ibreq->ibr_name;
163     }
164
165   cb = NULL;
166
167   if (flags & FOLLOW_PATH || flags & ALL_RESULTS)
168     {
169       nis_result *lres;
170       u_long newflags = flags & ~FOLLOW_PATH & ~ALL_RESULTS;
171       char table_path[NIS_MAXPATH + 3];
172       char *ntable, *p;
173       u_long done = 0, failures = 0;
174
175       while (names[name_nr] != NULL && !done)
176         {
177           lres = nis_lookup (names[name_nr], newflags | NO_AUTHINFO);
178           if (lres == NULL || NIS_RES_STATUS (lres) != NIS_SUCCESS)
179             {
180               NIS_RES_STATUS (res) = NIS_RES_STATUS (lres);
181               nis_freeresult (lres);
182               ++name_nr;
183               continue;
184             }
185
186           /* nis_lookup handles FOLLOW_LINKS,
187              so we must have a table object.*/
188           if (__type_of (NIS_RES_OBJECT (lres)) != NIS_TABLE_OBJ)
189             {
190               nis_freeresult (lres);
191               NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
192               break;
193             }
194
195           /* Save the path, discard everything else.  */
196           p = __stpncpy (table_path, names[name_nr], NIS_MAXPATH);
197           *p++ = ':';
198           p = __stpncpy (p, NIS_RES_OBJECT (lres)->TA_data.ta_path,
199                          NIS_MAXPATH - (p - table_path));
200           *p = '\0';
201           nis_freeresult (lres);
202           free (res);
203           res = NULL;
204
205           p = table_path;
206
207           while (((ntable = strsep (&p, ":")) != NULL) && !done)
208             {
209               char *c;
210
211               if (res != NULL)
212                 nis_freeresult (res);
213
214               /* Do the job recursive here!  */
215               if ((c = strchr(name, ']')) != NULL)
216                 {
217                   /* Have indexed name ! */
218                   int index_len = c - name + 2;
219                   char buf[index_len + strlen (ntable) + 1];
220
221                   c = __stpncpy (buf, name, index_len);
222                   strcpy (c, ntable);
223                   res = nis_list (buf, newflags, callback,userdata);
224                 }
225               else
226                 res = nis_list (ntable, newflags, callback, userdata);
227               if (res == NULL)
228                 return NULL;
229               switch (NIS_RES_STATUS (res))
230                 {
231                 case NIS_SUCCESS:
232                 case NIS_CBRESULTS:
233                   if (!(flags & ALL_RESULTS))
234                     done = 1;
235                   break;
236                 case NIS_PARTIAL: /* The table is correct, we doesn't found
237                                      the entry */
238                   break;
239                 default:
240                   if (flags & ALL_RESULTS)
241                     ++failures;
242                   else
243                     done = 1;
244                   break;
245                 }
246             }
247           if (NIS_RES_STATUS (res) == NIS_SUCCESS && failures)
248             NIS_RES_STATUS (res) = NIS_S_SUCCESS;
249           if (NIS_RES_STATUS (res) == NIS_NOTFOUND && failures)
250             NIS_RES_STATUS (res) = NIS_S_NOTFOUND;
251           break;
252         }
253     }
254   else
255     {
256       if (callback != NULL)
257         {
258           cb = __nis_create_callback (callback, userdata, flags);
259           ibreq->ibr_cbhost.ibr_cbhost_len = 1;
260           ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
261           }
262
263       while (!done)
264         {
265           memset (res, '\0', sizeof (nis_result));
266
267           status = __do_niscall (ibreq->ibr_name, NIS_IBLIST,
268                                  (xdrproc_t) _xdr_ib_request,
269                                  (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
270                                  (caddr_t) res, flags, cb);
271           if (status != NIS_SUCCESS)
272             NIS_RES_STATUS (res) = status;
273
274           switch (NIS_RES_STATUS (res))
275             {
276             case NIS_PARTIAL:
277             case NIS_SUCCESS:
278             case NIS_S_SUCCESS:
279               if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
280                   flags & FOLLOW_LINKS)         /* We are following links.  */
281                 {
282                   /* If we hit the link limit, bail.  */
283                   if (count_links > NIS_MAXLINKS)
284                     {
285                       NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
286                       ++done;
287                       break;
288                     }
289                   if (count_links)
290                     free (ibreq->ibr_name);
291                   ++count_links;
292                   free (ibreq->ibr_name);
293                   ibreq->ibr_name =
294                     strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
295                   if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
296                     if (ibreq->ibr_srch.ibr_srch_len == 0)
297                       {
298                         ibreq->ibr_srch.ibr_srch_len =
299                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
300                         ibreq->ibr_srch.ibr_srch_val =
301                           NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
302                       }
303                   nis_freeresult (res);
304                   res = calloc (1, sizeof (nis_result));
305                 }
306               else
307                 ++done;
308               break;
309             case NIS_CBRESULTS:
310               /* Calback is handled in nis_call.c (__do_niscall2),
311                  but we have to change the error code */
312               NIS_RES_STATUS (res) = cb->result;
313               ++done;
314               break;
315             case NIS_UNAVAIL:
316               /* NIS+ is not installed, or all servers are down.  */
317               ++done;
318               break;
319             default:
320               /* Try the next domainname if we don't follow a link.  */
321               if (count_links)
322                 {
323                   free (ibreq->ibr_name);
324                   NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
325                   ++done;
326                   break;
327                 }
328               ++name_nr;
329               if (names[name_nr] == NULL)
330                 {
331                   ++done;
332                   break;
333                 }
334               ibreq->ibr_name = names[name_nr];
335               break;
336             }
337         }
338     }                           /* End of not FOLLOW_PATH.  */
339
340   if (names != namebuf)
341     nis_freenames (names);
342
343   if (cb)
344     {
345       __nis_destroy_callback (cb);
346       ibreq->ibr_cbhost.ibr_cbhost_len = 0;
347       ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
348     }
349
350   nis_free_request (ibreq);
351
352   return res;
353 }
354
355 nis_result *
356 nis_add_entry (const_nis_name name, const nis_object *obj2, u_long flags)
357 {
358   nis_object obj;
359   nis_result *res;
360   nis_error status;
361   ib_request *ibreq;
362   size_t namelen = strlen (name);
363   char buf1[namelen + 20];
364   char buf4[namelen + 20];
365
366   res = calloc (1, sizeof (nis_result));
367   if (res == NULL)
368     return NULL;
369
370   if (name == NULL)
371     {
372       NIS_RES_STATUS (res) = NIS_BADNAME;
373       return res;
374     }
375
376   if ((ibreq = __create_ib_request (name, flags)) == NULL)
377     {
378       NIS_RES_STATUS (res) = NIS_BADNAME;
379       return res;
380     }
381
382   memcpy (&obj, obj2, sizeof (nis_object));
383
384   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
385     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
386
387   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
388     obj.zo_owner = nis_local_principal ();
389
390   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
391     obj.zo_group = nis_local_group ();
392
393   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
394
395   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
396   if (ibreq->ibr_obj.ibr_obj_val == NULL)
397     {
398       NIS_RES_STATUS (res) = NIS_NOMEMORY;
399       return res;
400     }
401   ibreq->ibr_obj.ibr_obj_len = 1;
402
403   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
404                               (xdrproc_t) _xdr_ib_request,
405                               (caddr_t) ibreq,
406                               (xdrproc_t) _xdr_nis_result,
407                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
408     NIS_RES_STATUS (res) = status;
409
410   nis_free_request (ibreq);
411
412   return res;
413 }
414
415 nis_result *
416 nis_modify_entry (const_nis_name name, const nis_object *obj2, u_long flags)
417 {
418   nis_object obj;
419   nis_result *res;
420   nis_error status;
421   ib_request *ibreq;
422   size_t namelen = strlen (name);
423   char buf1[namelen + 20];
424   char buf4[namelen + 20];
425
426   res = calloc (1, sizeof (nis_result));
427   if (res == NULL)
428     return NULL;
429
430   if (( ibreq =__create_ib_request (name, flags)) == NULL)
431     {
432       NIS_RES_STATUS (res) = NIS_BADNAME;
433       return res;
434     }
435
436   memcpy (&obj, obj2, sizeof (nis_object));
437
438   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
439     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
440
441   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
442     obj.zo_owner = nis_local_principal ();
443
444   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
445     obj.zo_group = nis_local_group ();
446
447   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
448
449   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
450   if (ibreq->ibr_obj.ibr_obj_val == NULL)
451     {
452       NIS_RES_STATUS (res) = NIS_NOMEMORY;
453       return res;
454     }
455   ibreq->ibr_obj.ibr_obj_len = 1;
456
457   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
458                               (xdrproc_t) _xdr_ib_request,
459                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
460                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
461     NIS_RES_STATUS (res) = status;
462
463   nis_free_request (ibreq);
464
465   return res;
466 }
467
468 nis_result *
469 nis_remove_entry (const_nis_name name, const nis_object *obj,
470                   u_long flags)
471 {
472   nis_result *res;
473   ib_request *ibreq;
474   nis_error status;
475
476   res = calloc (1, sizeof (nis_result));
477   if (res == NULL)
478     return NULL;
479
480   if (name == NULL)
481     {
482       NIS_RES_STATUS (res) = NIS_BADNAME;
483       return res;
484     }
485
486   if ((ibreq =__create_ib_request (name, flags)) == NULL)
487     {
488       NIS_RES_STATUS (res) = NIS_BADNAME;
489       return res;
490     }
491
492   if (obj != NULL)
493     {
494       ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
495       if (ibreq->ibr_obj.ibr_obj_val == NULL)
496         {
497           NIS_RES_STATUS (res) = NIS_NOMEMORY;
498           return res;
499         }
500       ibreq->ibr_obj.ibr_obj_len = 1;
501     }
502
503   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
504                               (xdrproc_t) _xdr_ib_request,
505                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
506                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
507     NIS_RES_STATUS (res) = status;
508
509   nis_free_request (ibreq);
510
511   return res;
512 }
513
514 nis_result *
515 nis_first_entry (const_nis_name name)
516 {
517   nis_result *res;
518   ib_request *ibreq;
519   nis_error status;
520
521   res = calloc (1, sizeof (nis_result));
522   if (res == NULL)
523     return NULL;
524
525   if (name == NULL)
526     {
527       NIS_RES_STATUS (res) = NIS_BADNAME;
528       return res;
529     }
530
531   if ((ibreq =__create_ib_request (name, 0)) == NULL)
532     {
533       NIS_RES_STATUS (res) = NIS_BADNAME;
534       return res;
535     }
536
537   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
538                               (xdrproc_t) _xdr_ib_request,
539                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
540                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
541     NIS_RES_STATUS (res) = status;
542
543   nis_free_request (ibreq);
544
545   return res;
546 }
547
548 nis_result *
549 nis_next_entry (const_nis_name name, const netobj *cookie)
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, 0)) == NULL)
566     {
567       NIS_RES_STATUS (res) = NIS_BADNAME;
568       return res;
569     }
570
571   if (cookie != NULL)
572     {
573       ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
574       ibreq->ibr_cookie.n_len = cookie->n_len;
575     }
576
577   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
578                               (xdrproc_t) _xdr_ib_request,
579                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
580                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
581     NIS_RES_STATUS (res) = status;
582
583   if (cookie != NULL)
584     {
585       /* Don't give cookie free, it is not from us */
586       ibreq->ibr_cookie.n_bytes = NULL;
587       ibreq->ibr_cookie.n_len = 0;
588     }
589
590   nis_free_request (ibreq);
591
592   return res;
593 }