Support for initgroups in NIS+ module.
[kopensolaris-gnu/glibc.git] / nis / nis_table.c
1 /* Copyright (c) 1997-1999,2003,2004,2005,2006 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 <assert.h>
21 #include <string.h>
22 #include <rpcsvc/nis.h>
23
24 #include "nis_xdr.h"
25 #include "nis_intern.h"
26 #include "libnsl.h"
27
28
29 struct ib_request *
30 __create_ib_request (const_nis_name name, unsigned int flags)
31 {
32   struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
33   nis_attr *search_val = NULL;
34   size_t search_len = 0;
35   size_t size = 0;
36
37   if (ibreq == NULL)
38     return NULL;
39
40   ibreq->ibr_flags = flags;
41
42   char *cptr = strdupa (name);
43
44   /* Not of "[key=value,key=value,...],foo.." format? */
45   if (cptr[0] != '[')
46     {
47       ibreq->ibr_name = strdup (cptr);
48       if (ibreq->ibr_name == NULL)
49         {
50           free (ibreq);
51           return NULL;
52         }
53       return ibreq;
54     }
55
56   /* "[key=value,...],foo" format */
57   ibreq->ibr_name = strchr (cptr, ']');
58   if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
59     {
60       /* The object has not really been built yet so we use free.  */
61       free (ibreq);
62       return NULL;
63     }
64
65   /* Check if we have an entry of "[key=value,],bar".  If, remove the "," */
66   if (ibreq->ibr_name[-1] == ',')
67     ibreq->ibr_name[-1] = '\0';
68   else
69     ibreq->ibr_name[0] = '\0';
70   ibreq->ibr_name += 2;
71   ibreq->ibr_name = strdup (ibreq->ibr_name);
72   if (ibreq->ibr_name == NULL)
73     {
74     free_null:
75       while (search_len-- > 0)
76         {
77           free (search_val[search_len].zattr_ndx);
78           free (search_val[search_len].zattr_val.zattr_val_val);
79         }
80       free (search_val);
81       nis_free_request (ibreq);
82       return NULL;
83     }
84
85   ++cptr; /* Remove "[" */
86
87   while (cptr != NULL && cptr[0] != '\0')
88     {
89       char *key = cptr;
90       char *val = strchr (cptr, '=');
91
92       cptr = strchr (key, ',');
93       if (cptr != NULL)
94         *cptr++ = '\0';
95
96       if (__builtin_expect (val == NULL, 0))
97         {
98           nis_free_request (ibreq);
99           return NULL;
100         }
101       *val++ = '\0';
102       if (search_len + 1 >= size)
103         {
104           size += 1;
105           nis_attr *newp = realloc (search_val, size * sizeof (nis_attr));
106           if (newp == NULL)
107             goto free_null;
108           search_val = newp;
109         }
110       search_val[search_len].zattr_ndx = strdup (key);
111       if (search_val[search_len].zattr_ndx == NULL)
112         goto free_null;
113
114       search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1;
115       search_val[search_len].zattr_val.zattr_val_val = strdup (val);
116       if (search_val[search_len].zattr_val.zattr_val_val == NULL)
117         {
118           free (search_val[search_len].zattr_ndx);
119           goto free_null;
120         }
121
122       ++search_len;
123     }
124
125   ibreq->ibr_srch.ibr_srch_val = search_val;
126   ibreq->ibr_srch.ibr_srch_len = search_len;
127
128   return ibreq;
129 }
130 libnsl_hidden_def (__create_ib_request)
131
132 static const struct timeval RPCTIMEOUT = {10, 0};
133
134 static char *
135 get_tablepath (char *name, dir_binding *bptr)
136 {
137   enum clnt_stat result;
138   nis_result res;
139   struct ns_request req;
140
141   memset (&res, '\0', sizeof (res));
142
143   req.ns_name = name;
144   req.ns_object.ns_object_len = 0;
145   req.ns_object.ns_object_val = NULL;
146
147   result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
148                       (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
149                       (caddr_t) &res, RPCTIMEOUT);
150
151   const char *cptr;
152   if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS
153       && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ)
154     cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path;
155   else
156     cptr = "";
157
158   char *str = strdup (cptr);
159
160   if (result == RPC_SUCCESS)
161     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res);
162
163   return str;
164 }
165
166
167 nis_error
168 __follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq,
169                dir_binding *bptr)
170 {
171   if (*tablepath == NULL)
172     {
173       *tablepath = get_tablepath (ibreq->ibr_name, bptr);
174       if (*tablepath == NULL)
175         return NIS_NOMEMORY;
176
177       *tableptr = *tablepath;
178     }
179   if (*tableptr == NULL)
180     return NIS_NOTFOUND;
181
182   char *newname = strsep (tableptr, ":");
183   if (newname[0] == '\0')
184     return NIS_NOTFOUND;
185
186   newname = strdup (newname);
187   if (newname == NULL)
188     return NIS_NOMEMORY;
189
190   free (ibreq->ibr_name);
191   ibreq->ibr_name = newname;
192
193   return NIS_SUCCESS;
194 }
195 libnsl_hidden_def (__follow_path)
196
197
198 nis_result *
199 nis_list (const_nis_name name, unsigned int flags,
200           int (*callback) (const_nis_name name,
201                            const nis_object *object,
202                            const void *userdata),
203           const void *userdata)
204 {
205   nis_result *res = malloc (sizeof (nis_result));
206   ib_request *ibreq;
207   int status;
208   enum clnt_stat clnt_status;
209   int count_links = 0;          /* We will only follow NIS_MAXLINKS links! */
210   int done = 0;
211   nis_name *names;
212   nis_name namebuf[2] = {NULL, NULL};
213   int name_nr = 0;
214   nis_cb *cb = NULL;
215   char *tableptr;
216   char *tablepath = NULL;
217   int first_try = 0; /* Do we try the old binding at first ? */
218   nis_result *allres = NULL;
219
220   if (res == NULL)
221     return NULL;
222
223   if (name == NULL)
224     {
225       status = NIS_BADNAME;
226     err_out:
227       nis_freeresult (allres);
228       memset (res, '\0', sizeof (nis_result));
229       NIS_RES_STATUS (res) = status;
230       return res;
231     }
232
233   ibreq = __create_ib_request (name, flags);
234   if (ibreq == NULL)
235     {
236       status = NIS_BADNAME;
237       goto err_out;
238     }
239
240   if ((flags & EXPAND_NAME)
241       && ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.')
242     {
243       names = nis_getnames (ibreq->ibr_name);
244       free (ibreq->ibr_name);
245       ibreq->ibr_name = NULL;
246       if (names == NULL)
247         {
248           nis_free_request (ibreq);
249           status = NIS_BADNAME;
250           goto err_out;
251         }
252       ibreq->ibr_name = strdup (names[name_nr]);
253       if (ibreq->ibr_name == NULL)
254         {
255           nis_freenames (names);
256           nis_free_request (ibreq);
257           status = NIS_NOMEMORY;
258           goto err_out;
259         }
260     }
261   else
262     {
263       names = namebuf;
264       names[name_nr] = ibreq->ibr_name;
265     }
266
267   cb = NULL;
268
269   while (!done)
270     {
271       dir_binding bptr;
272       directory_obj *dir = NULL;
273
274       memset (res, '\0', sizeof (nis_result));
275
276       status = __nisfind_server (ibreq->ibr_name,
277                                  ibreq->ibr_srch.ibr_srch_val != NULL, &dir);
278       if (status != NIS_SUCCESS)
279         {
280           NIS_RES_STATUS (res) = status;
281           goto fail3;
282         }
283
284       status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
285                                  dir->do_servers.do_servers_len, flags);
286       if (__builtin_expect (status != NIS_SUCCESS, 0))
287         {
288           NIS_RES_STATUS (res) = status;
289           goto fail2;
290         }
291
292       while (__nisbind_connect (&bptr) != NIS_SUCCESS)
293         if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0))
294           {
295             NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
296             goto fail;
297           }
298
299       if (callback != NULL)
300         {
301           assert (cb == NULL);
302           cb = __nis_create_callback (callback, userdata, flags);
303           ibreq->ibr_cbhost.ibr_cbhost_len = 1;
304           ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
305         }
306
307     again:
308       clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
309                                (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
310                                (xdrproc_t) _xdr_nis_result,
311                                (caddr_t) res, RPCTIMEOUT);
312
313       if (__builtin_expect (clnt_status != RPC_SUCCESS, 0))
314         NIS_RES_STATUS (res) = NIS_RPCERROR;
315       else
316         switch (NIS_RES_STATUS (res))
317           { /* start switch */
318           case NIS_PARTIAL:
319           case NIS_SUCCESS:
320           case NIS_S_SUCCESS:
321             if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
322                 && (flags & FOLLOW_LINKS))      /* We are following links.  */
323               {
324                 free (ibreq->ibr_name);
325                 ibreq->ibr_name = NULL;
326                 /* If we hit the link limit, bail.  */
327                 if (__builtin_expect (count_links > NIS_MAXLINKS, 0))
328                   {
329                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
330                     ++done;
331                     break;
332                   }
333                 ++count_links;
334                 ibreq->ibr_name =
335                   strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
336                 if (ibreq->ibr_name == NULL)
337                   {
338                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
339                   fail:
340                     __nisbind_destroy (&bptr);
341                   fail2:
342                     nis_free_directory (dir);
343                   fail3:
344                     free (tablepath);
345                     if (cb)
346                       {
347                         __nis_destroy_callback (cb);
348                         ibreq->ibr_cbhost.ibr_cbhost_len = 0;
349                         ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
350                       }
351                     if (names != namebuf)
352                       nis_freenames (names);
353                     nis_free_request (ibreq);
354                     nis_freeresult (allres);
355                     return res;
356                   }
357                 if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
358                   if (ibreq->ibr_srch.ibr_srch_len == 0)
359                     {
360                       ibreq->ibr_srch.ibr_srch_len =
361                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
362                       ibreq->ibr_srch.ibr_srch_val =
363                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
364                     }
365                 /* The following is a non-obvious optimization.  A
366                    nis_freeresult call would call xdr_free as the
367                    following code.  But it also would unnecessarily
368                    free the result structure.  We avoid this here
369                    along with the necessary tests.  */
370                 xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
371                 memset (res, '\0', sizeof (*res));
372                 first_try = 1; /* Try at first the old binding */
373                 goto again;
374               }
375             else if ((flags & FOLLOW_PATH)
376                      && NIS_RES_STATUS (res) == NIS_PARTIAL)
377               {
378                 clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
379                                              &bptr);
380                 if (clnt_status != NIS_SUCCESS)
381                   {
382                     NIS_RES_STATUS (res) = clnt_status;
383                     ++done;
384                   }
385                 else
386                   {
387                     /* The following is a non-obvious optimization.  A
388                        nis_freeresult call would call xdr_free as the
389                        following code.  But it also would unnecessarily
390                        free the result structure.  We avoid this here
391                        along with the necessary tests.  */
392                     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
393                     memset (res, '\0', sizeof (*res));
394                     first_try = 1;
395                     goto again;
396                   }
397               }
398             else if ((flags & (FOLLOW_PATH | ALL_RESULTS))
399                      == (FOLLOW_PATH | ALL_RESULTS))
400               {
401                 if (allres == NULL)
402                   {
403                     allres = res;
404                     res = malloc (sizeof (nis_result));
405                     if (res == NULL)
406                       {
407                         res = allres;
408                         allres = NULL;
409                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
410                         goto fail;
411                       }
412                     NIS_RES_STATUS (res) = NIS_RES_STATUS (allres);
413                   }
414                 else
415                   {
416                     nis_object *objects_val
417                       = realloc (NIS_RES_OBJECT (allres),
418                                  (NIS_RES_NUMOBJ (allres)
419                                   + NIS_RES_NUMOBJ (res))
420                                  * sizeof (nis_object));
421                     if (objects_val == NULL)
422                       {
423                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
424                         goto fail;
425                       }
426                     NIS_RES_OBJECT (allres) = objects_val;
427                     memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres),
428                             NIS_RES_OBJECT (res),
429                             NIS_RES_NUMOBJ (res) * sizeof (nis_object));
430                     NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res);
431                     NIS_RES_NUMOBJ (res) = 0;
432                     free (NIS_RES_OBJECT (res));
433                     NIS_RES_OBJECT (res) = NULL;
434                     NIS_RES_STATUS (allres) = NIS_RES_STATUS (res);
435                     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
436                   }
437                 clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
438                                              &bptr);
439                 if (clnt_status != NIS_SUCCESS)
440                   {
441                     NIS_RES_STATUS (res) = clnt_status;
442                     ++done;
443                   }
444               }
445             else
446               ++done;
447             break;
448           case NIS_CBRESULTS:
449             if (cb != NULL)
450               {
451                 __nis_do_callback (&bptr, &res->cookie, cb);
452                 NIS_RES_STATUS (res) = cb->result;
453
454                 if (!(flags & ALL_RESULTS))
455                   ++done;
456                 else
457                   {
458                     NIS_RES_STATUS (res)
459                       = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
460                     if (NIS_RES_STATUS (res) != NIS_SUCCESS)
461                       ++done;
462                   }
463               }
464             break;
465           case NIS_SYSTEMERROR:
466           case NIS_NOSUCHNAME:
467           case NIS_NOT_ME:
468             /* If we had first tried the old binding, do nothing, but
469                get a new binding */
470             if (!first_try)
471               {
472                 if (__nisbind_next (&bptr) != NIS_SUCCESS)
473                   {
474                     ++done;
475                     break; /* No more servers to search */
476                   }
477                 while (__nisbind_connect (&bptr) != NIS_SUCCESS)
478                   {
479                     if (__nisbind_next (&bptr) != NIS_SUCCESS)
480                       {
481                         ++done;
482                         break; /* No more servers to search */
483                       }
484                   }
485                 goto again;
486               }
487             break;
488           default:
489             if (!first_try)
490               {
491                 /* Try the next domainname if we don't follow a link.  */
492                 free (ibreq->ibr_name);
493                 ibreq->ibr_name = NULL;
494                 if (__builtin_expect (count_links, 0))
495                   {
496                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
497                     ++done;
498                     break;
499                   }
500                 ++name_nr;
501                 if (names[name_nr] == NULL)
502                   {
503                     ++done;
504                     break;
505                   }
506                 ibreq->ibr_name = strdup (names[name_nr]);
507                 if (ibreq->ibr_name == NULL)
508                   {
509                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
510                     goto fail;
511                   }
512                 first_try = 1; /* Try old binding at first */
513                 goto again;
514               }
515             break;
516           }
517       first_try = 0;
518
519       if (cb)
520         {
521           __nis_destroy_callback (cb);
522           ibreq->ibr_cbhost.ibr_cbhost_len = 0;
523           ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
524           cb = NULL;
525         }
526
527       __nisbind_destroy (&bptr);
528       nis_free_directory (dir);
529     }
530
531   free (tablepath);
532
533   if (names != namebuf)
534     nis_freenames (names);
535
536   nis_free_request (ibreq);
537
538   if (allres)
539     {
540       nis_freeresult (res);
541       return allres;
542     }
543
544   return res;
545 }
546 libnsl_hidden_def (nis_list)
547
548 nis_result *
549 nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
550 {
551   nis_result *res = calloc (1, sizeof (nis_result));
552   if (res == NULL)
553     return NULL;
554
555   if (name == NULL)
556     {
557       NIS_RES_STATUS (res) = NIS_BADNAME;
558       return res;
559     }
560
561   ib_request *ibreq = __create_ib_request (name, flags);
562   if (ibreq == NULL)
563     {
564       NIS_RES_STATUS (res) = NIS_BADNAME;
565       return res;
566     }
567
568   nis_object obj;
569   memcpy (&obj, obj2, sizeof (nis_object));
570
571   size_t namelen = strlen (name);
572   char buf1[namelen + 20];
573   char buf4[namelen + 20];
574
575   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
576     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
577
578   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
579     obj.zo_owner = nis_local_principal ();
580
581   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
582     obj.zo_group = nis_local_group ();
583
584   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
585
586   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
587   if (ibreq->ibr_obj.ibr_obj_val == NULL)
588     {
589       nis_free_request (ibreq);
590       NIS_RES_STATUS (res) = NIS_NOMEMORY;
591       return res;
592     }
593   ibreq->ibr_obj.ibr_obj_len = 1;
594
595   nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
596                                    (xdrproc_t) _xdr_ib_request,
597                                    (caddr_t) ibreq,
598                                    (xdrproc_t) _xdr_nis_result,
599                                    (caddr_t) res, 0, NULL);
600   if (__builtin_expect (status != NIS_SUCCESS, 0))
601     NIS_RES_STATUS (res) = status;
602
603   nis_free_request (ibreq);
604
605   return res;
606 }
607
608 nis_result *
609 nis_modify_entry (const_nis_name name, const nis_object *obj2,
610                   unsigned int flags)
611 {
612   nis_object obj;
613   nis_result *res;
614   nis_error status;
615   ib_request *ibreq;
616   size_t namelen = strlen (name);
617   char buf1[namelen + 20];
618   char buf4[namelen + 20];
619
620   res = calloc (1, sizeof (nis_result));
621   if (res == NULL)
622     return NULL;
623
624   ibreq = __create_ib_request (name, flags);
625   if (ibreq == NULL)
626     {
627       NIS_RES_STATUS (res) = NIS_BADNAME;
628       return res;
629     }
630
631   memcpy (&obj, obj2, sizeof (nis_object));
632
633   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
634     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
635
636   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
637     obj.zo_owner = nis_local_principal ();
638
639   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
640     obj.zo_group = nis_local_group ();
641
642   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
643
644   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
645   if (ibreq->ibr_obj.ibr_obj_val == NULL)
646     {
647       nis_free_request (ibreq);
648       NIS_RES_STATUS (res) = NIS_NOMEMORY;
649       return res;
650     }
651   ibreq->ibr_obj.ibr_obj_len = 1;
652
653   status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
654                          (xdrproc_t) _xdr_ib_request,
655                          (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
656                          (caddr_t) res, 0, NULL);
657   if (__builtin_expect (status != NIS_SUCCESS, 0))
658     NIS_RES_STATUS (res) = status;
659
660   nis_free_request (ibreq);
661
662   return res;
663 }
664
665 nis_result *
666 nis_remove_entry (const_nis_name name, const nis_object *obj,
667                   unsigned int flags)
668 {
669   nis_result *res;
670   ib_request *ibreq;
671   nis_error status;
672
673   res = calloc (1, sizeof (nis_result));
674   if (res == NULL)
675     return NULL;
676
677   if (name == NULL)
678     {
679       NIS_RES_STATUS (res) = NIS_BADNAME;
680       return res;
681     }
682
683   ibreq = __create_ib_request (name, flags);
684   if (ibreq == NULL)
685     {
686       NIS_RES_STATUS (res) = NIS_BADNAME;
687       return res;
688     }
689
690   if (obj != NULL)
691     {
692       ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
693       if (ibreq->ibr_obj.ibr_obj_val == NULL)
694         {
695           nis_free_request (ibreq);
696           NIS_RES_STATUS (res) = NIS_NOMEMORY;
697           return res;
698         }
699       ibreq->ibr_obj.ibr_obj_len = 1;
700     }
701
702   if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
703                               (xdrproc_t) _xdr_ib_request,
704                               (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
705                               (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
706     NIS_RES_STATUS (res) = status;
707
708   nis_free_request (ibreq);
709
710   return res;
711 }
712
713 nis_result *
714 nis_first_entry (const_nis_name name)
715 {
716   nis_result *res;
717   ib_request *ibreq;
718   nis_error status;
719
720   res = calloc (1, sizeof (nis_result));
721   if (res == NULL)
722     return NULL;
723
724   if (name == NULL)
725     {
726       NIS_RES_STATUS (res) = NIS_BADNAME;
727       return res;
728     }
729
730   ibreq = __create_ib_request (name, 0);
731   if (ibreq == NULL)
732     {
733       NIS_RES_STATUS (res) = NIS_BADNAME;
734       return res;
735     }
736
737   status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
738                          (xdrproc_t) _xdr_ib_request,
739                          (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
740                          (caddr_t) res, 0, NULL);
741
742   if (__builtin_expect (status != NIS_SUCCESS, 0))
743     NIS_RES_STATUS (res) = status;
744
745   nis_free_request (ibreq);
746
747   return res;
748 }
749
750 nis_result *
751 nis_next_entry (const_nis_name name, const netobj *cookie)
752 {
753   nis_result *res;
754   ib_request *ibreq;
755   nis_error status;
756
757   res = calloc (1, sizeof (nis_result));
758   if (res == NULL)
759     return NULL;
760
761   if (name == NULL)
762     {
763       NIS_RES_STATUS (res) = NIS_BADNAME;
764       return res;
765     }
766
767   ibreq = __create_ib_request (name, 0);
768   if (ibreq == NULL)
769     {
770       NIS_RES_STATUS (res) = NIS_BADNAME;
771       return res;
772     }
773
774   if (cookie != NULL)
775     {
776       ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
777       ibreq->ibr_cookie.n_len = cookie->n_len;
778     }
779
780   status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
781                          (xdrproc_t) _xdr_ib_request,
782                          (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
783                          (caddr_t) res, 0, NULL);
784
785   if (__builtin_expect (status != NIS_SUCCESS, 0))
786     NIS_RES_STATUS (res) = status;
787
788   if (cookie != NULL)
789     {
790       /* Don't give cookie free, it is not from us */
791       ibreq->ibr_cookie.n_bytes = NULL;
792       ibreq->ibr_cookie.n_len = 0;
793     }
794
795   nis_free_request (ibreq);
796
797   return res;
798 }