text: /* Copyright (c) 1997-2019 Free Software Foundation, Inc.
     This file is part of the GNU C Library.
     Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
  
     The GNU C Library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
     License as published by the Free Software Foundation; either
     version 2.1 of the License, or (at your option) any later version.
  
     The GNU C Library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Lesser General Public License for more details.
  
     You should have received a copy of the GNU Lesser General Public
     License along with the GNU C Library; if not, see
     <http://www.gnu.org/licenses/>.  */
  
  #include <assert.h>
  #include <libc-diag.h>
  #include <rpcsvc/nis.h>
  #include <shlib-compat.h>
  #include <string.h>
  
  #include "libnsl.h"
  #include "nis_intern.h"
  #include "nis_xdr.h"
  
  struct ib_request* __create_ib_request(const_nis_name name, unsigned int flags)
  {
      struct ib_request* ibreq = calloc(1, sizeof(struct ib_request));
      nis_attr* search_val = NULL;
      size_t search_len = 0;
      size_t size = 0;
  
      if (ibreq == NULL)
          return NULL;
  
      ibreq->ibr_flags = flags;
  
      char* cptr = strdupa(name);
  
      /* Not of "[key=value,key=value,...],foo.." format? */
      if (cptr[0] != '[')
      {
          ibreq->ibr_name = strdup(cptr);
          if (ibreq->ibr_name == NULL)
          {
              free(ibreq);
              return NULL;
          }
          return ibreq;
      }
  
      /* "[key=value,...],foo" format */
      ibreq->ibr_name = strchr(cptr, ']');
      if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
      {
          /* The object has not really been built yet so we use free.  */
          free(ibreq);
          return NULL;
      }
  
      /* Check if we have an entry of "[key=value,],bar".  If, remove the "," */
      if (ibreq->ibr_name[-1] == ',')
          ibreq->ibr_name[-1] = '\0';
      else
          ibreq->ibr_name[0] = '\0';
      ibreq->ibr_name += 2;
      ibreq->ibr_name = strdup(ibreq->ibr_name);
      if (ibreq->ibr_name == NULL)
      {
      free_null:
          while (search_len-- > 0)
          {
              free(search_val[search_len].zattr_ndx);
              free(search_val[search_len].zattr_val.zattr_val_val);
          }
          free(search_val);
          nis_free_request(ibreq);
          return NULL;
      }
  
      ++cptr; /* Remove "[" */
  
      while (cptr != NULL && cptr[0] != '\0')
      {
          char* key = cptr;
          char* val = strchr(cptr, '=');
  
          cptr = strchr(key, ',');
          if (cptr != NULL)
              *cptr++ = '\0';
  
          if (__glibc_unlikely(val == NULL))
          {
              nis_free_request(ibreq);
              return NULL;
          }
          *val++ = '\0';
          if (search_len + 1 >= size)
          {
              size += 1;
              nis_attr* newp = realloc(search_val, size * sizeof(nis_attr));
              if (newp == NULL)
                  goto free_null;
              search_val = newp;
          }
          search_val[search_len].zattr_ndx = strdup(key);
          if (search_val[search_len].zattr_ndx == NULL)
              goto free_null;
  
          search_val[search_len].zattr_val.zattr_val_len = strlen(val) + 1;
          search_val[search_len].zattr_val.zattr_val_val = strdup(val);
          if (search_val[search_len].zattr_val.zattr_val_val == NULL)
          {
              free(search_val[search_len].zattr_ndx);
              goto free_null;
          }
  
          ++search_len;
      }
  
      ibreq->ibr_srch.ibr_srch_val = search_val;
      ibreq->ibr_srch.ibr_srch_len = search_len;
  
      return ibreq;
  }
  libnsl_hidden_nolink_def(__create_ib_request, GLIBC_PRIVATE)
  
      static const struct timeval RPCTIMEOUT = {10, 0};
  
  static char* get_tablepath(char* name, dir_binding* bptr)
  {
      enum clnt_stat result;
      nis_result res;
      struct ns_request req;
  
      memset(&res, '\0', sizeof(res));
  
      req.ns_name = name;
      req.ns_object.ns_object_len = 0;
      req.ns_object.ns_object_val = NULL;
  
      result = clnt_call(bptr->clnt, NIS_LOOKUP, (xdrproc_t)_xdr_ns_request,
                         (caddr_t)&req, (xdrproc_t)_xdr_nis_result, (caddr_t)&res,
                         RPCTIMEOUT);
  
      const char* cptr;
      if (result == RPC_SUCCESS && NIS_RES_STATUS(&res) == NIS_SUCCESS &&
          __type_of(NIS_RES_OBJECT(&res)) == NIS_TABLE_OBJ)
          cptr = NIS_RES_OBJECT(&res)->TA_data.ta_path;
      else
          cptr = "";
  
      char* str = strdup(cptr);
  
      if (result == RPC_SUCCESS)
          xdr_free((xdrproc_t)_xdr_nis_result, (char*)&res);
  
      return str;
  }
  
  nis_error __follow_path(char** tablepath, char** tableptr,
                          struct ib_request* ibreq, dir_binding* bptr)
  {
      if (*tablepath == NULL)
      {
          *tablepath = get_tablepath(ibreq->ibr_name, bptr);
          if (*tablepath == NULL)
              return NIS_NOMEMORY;
  
          *tableptr = *tablepath;
      }
  
      /* Since tableptr is only set here, and it's set when tablepath is NULL,
         which it is initially defined as, we know it will always be set here.  */
      DIAG_PUSH_NEEDS_COMMENT;
      DIAG_IGNORE_NEEDS_COMMENT(4.7, "-Wmaybe-uninitialized");
  
      if (*tableptr == NULL)
          return NIS_NOTFOUND;
  
      char* newname = strsep(tableptr, ":");
      if (newname[0] == '\0')
          return NIS_NOTFOUND;
  
      DIAG_POP_NEEDS_COMMENT;
  
      newname = strdup(newname);
      if (newname == NULL)
          return NIS_NOMEMORY;
  
      free(ibreq->ibr_name);
      ibreq->ibr_name = newname;
  
      return NIS_SUCCESS;
  }
  libnsl_hidden_nolink_def(__follow_path, GLIBC_PRIVATE)
  
      nis_result* nis_list(const_nis_name name, unsigned int flags,
                           int (*callback)(const_nis_name name,
                                           const nis_object* object,
                                           const void* userdata),
                           const void* userdata)
  {
      nis_result* res = malloc(sizeof(nis_result));
      ib_request* ibreq;
      int status;
      enum clnt_stat clnt_status;
      int count_links = 0; /* We will only follow NIS_MAXLINKS links! */
      int done = 0;
      nis_name* names;
      nis_name namebuf[2] = {NULL, NULL};
      int name_nr = 0;
      nis_cb* cb = NULL;
      char* tableptr;
      char* tablepath = NULL;
      int first_try = 0; /* Do we try the old binding at first ? */
      nis_result* allres = NULL;
  
      if (res == NULL)
          return NULL;
  
      if (name == NULL)
      {
          status = NIS_BADNAME;
      err_out:
          nis_freeresult(allres);
          memset(res, '\0', sizeof(nis_result));
          NIS_RES_STATUS(res) = status;
          return res;
      }
  
      ibreq = __create_ib_request(name, flags);
      if (ibreq == NULL)
      {
          status = NIS_BADNAME;
          goto err_out;
      }
  
      if ((flags & EXPAND_NAME) &&
          ibreq->ibr_name[strlen(ibreq->ibr_name) - 1] != '.')
      {
          names = nis_getnames(ibreq->ibr_name);
          free(ibreq->ibr_name);
          ibreq->ibr_name = NULL;
          if (names == NULL)
          {
              nis_free_request(ibreq);
              status = NIS_BADNAME;
              goto err_out;
          }
          ibreq->ibr_name = strdup(names[name_nr]);
          if (ibreq->ibr_name == NULL)
          {
              nis_freenames(names);
              nis_free_request(ibreq);
              status = NIS_NOMEMORY;
              goto err_out;
          }
      }
      else
      {
          names = namebuf;
          names[name_nr] = ibreq->ibr_name;
      }
  
      cb = NULL;
  
      while (!done)
      {
          dir_binding bptr;
          directory_obj* dir = NULL;
  
          memset(res, '\0', sizeof(nis_result));
  
          status = __nisfind_server(ibreq->ibr_name,
                                    ibreq->ibr_srch.ibr_srch_val != NULL, &dir,
                                    &bptr, flags & ~MASTER_ONLY);
          if (status != NIS_SUCCESS)
          {
              NIS_RES_STATUS(res) = status;
              goto fail3;
          }
  
          while (__nisbind_connect(&bptr) != NIS_SUCCESS)
              if (__glibc_unlikely(__nisbind_next(&bptr) != NIS_SUCCESS))
              {
                  NIS_RES_STATUS(res) = NIS_NAMEUNREACHABLE;
                  goto fail;
              }
  
          if (callback != NULL)
          {
              assert(cb == NULL);
              cb = __nis_create_callback(callback, userdata, flags);
              ibreq->ibr_cbhost.ibr_cbhost_len = 1;
              ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
          }
  
      again:
          clnt_status = clnt_call(
              bptr.clnt, NIS_IBLIST, (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
              (xdrproc_t)_xdr_nis_result, (caddr_t)res, RPCTIMEOUT);
  
          if (__glibc_unlikely(clnt_status != RPC_SUCCESS))
              NIS_RES_STATUS(res) = NIS_RPCERROR;
          else
              switch (NIS_RES_STATUS(res))
              { /* start switch */
                  case NIS_PARTIAL:
                  case NIS_SUCCESS:
                  case NIS_S_SUCCESS:
                      if (__type_of(NIS_RES_OBJECT(res)) == NIS_LINK_OBJ &&
                          (flags & FOLLOW_LINKS)) /* We are following links.  */
                      {
                          free(ibreq->ibr_name);
                          ibreq->ibr_name = NULL;
                          /* If we hit the link limit, bail.  */
                          if (__glibc_unlikely(count_links > NIS_MAXLINKS))
                          {
                              NIS_RES_STATUS(res) = NIS_LINKNAMEERROR;
                              ++done;
                              break;
                          }
                          ++count_links;
                          ibreq->ibr_name =
                              strdup(NIS_RES_OBJECT(res)->LI_data.li_name);
                          if (ibreq->ibr_name == NULL)
                          {
                              NIS_RES_STATUS(res) = NIS_NOMEMORY;
                          fail:
                              __nisbind_destroy(&bptr);
                              nis_free_directory(dir);
                          fail3:
                              free(tablepath);
                              if (cb)
                              {
                                  __nis_destroy_callback(cb);
                                  ibreq->ibr_cbhost.ibr_cbhost_len = 0;
                                  ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
                              }
                              if (names != namebuf)
                                  nis_freenames(names);
                              nis_free_request(ibreq);
                              nis_freeresult(allres);
                              return res;
                          }
                          if (NIS_RES_OBJECT(res)->LI_data.li_attrs.li_attrs_len)
                              if (ibreq->ibr_srch.ibr_srch_len == 0)
                              {
                                  ibreq->ibr_srch.ibr_srch_len =
                                      NIS_RES_OBJECT(res)
                                          ->LI_data.li_attrs.li_attrs_len;
                                  ibreq->ibr_srch.ibr_srch_val =
                                      NIS_RES_OBJECT(res)
                                          ->LI_data.li_attrs.li_attrs_val;
                              }
                          /* The following is a non-obvious optimization.  A
                             nis_freeresult call would call xdr_free as the
                             following code.  But it also would unnecessarily
                             free the result structure.  We avoid this here
                             along with the necessary tests.  */
                          xdr_free((xdrproc_t)_xdr_nis_result, (char*)res);
                          memset(res, '\0', sizeof(*res));
                          first_try = 1; /* Try at first the old binding */
                          goto again;
                      }
                      else if ((flags & FOLLOW_PATH) &&
                               NIS_RES_STATUS(res) == NIS_PARTIAL)
                      {
                          enum nis_error err =
                              __follow_path(&tablepath, &tableptr, ibreq, &bptr);
                          if (err != NIS_SUCCESS)
                          {
                              if (err == NIS_NOMEMORY)
                                  NIS_RES_STATUS(res) = err;
                              ++done;
                          }
                          else
                          {
                              /* The following is a non-obvious optimization.  A
                                 nis_freeresult call would call xdr_free as the
                                 following code.  But it also would unnecessarily
                                 free the result structure.  We avoid this here
                                 along with the necessary tests.  */
                              xdr_free((xdrproc_t)_xdr_nis_result, (char*)res);
                              memset(res, '\0', sizeof(*res));
                              first_try = 1;
                              goto again;
                          }
                      }
                      else if ((flags & (FOLLOW_PATH | ALL_RESULTS)) ==
                               (FOLLOW_PATH | ALL_RESULTS))
                      {
                          if (allres == NULL)
                          {
                              allres = res;
                              res = malloc(sizeof(nis_result));
                              if (res == NULL)
                              {
                                  res = allres;
                                  allres = NULL;
                                  NIS_RES_STATUS(res) = NIS_NOMEMORY;
                                  goto fail;
                              }
                              NIS_RES_STATUS(res) = NIS_RES_STATUS(allres);
                          }
                          else
                          {
                              nis_object* objects_val = realloc(
                                  NIS_RES_OBJECT(allres),
                                  (NIS_RES_NUMOBJ(allres) + NIS_RES_NUMOBJ(res)) *
                                      sizeof(nis_object));
                              if (objects_val == NULL)
                              {
                                  NIS_RES_STATUS(res) = NIS_NOMEMORY;
                                  goto fail;
                              }
                              NIS_RES_OBJECT(allres) = objects_val;
                              memcpy(NIS_RES_OBJECT(allres) +
                                         NIS_RES_NUMOBJ(allres),
                                     NIS_RES_OBJECT(res),
                                     NIS_RES_NUMOBJ(res) * sizeof(nis_object));
                              NIS_RES_NUMOBJ(allres) += NIS_RES_NUMOBJ(res);
                              NIS_RES_NUMOBJ(res) = 0;
                              free(NIS_RES_OBJECT(res));
                              NIS_RES_OBJECT(res) = NULL;
                              NIS_RES_STATUS(allres) = NIS_RES_STATUS(res);
                              xdr_free((xdrproc_t)_xdr_nis_result, (char*)res);
                          }
                          enum nis_error err =
                              __follow_path(&tablepath, &tableptr, ibreq, &bptr);
                          if (err != NIS_SUCCESS)
                          {
                              /* Prepare for the nis_freeresult call.  */
                              memset(res, '\0', sizeof(*res));
  
                              if (err == NIS_NOMEMORY)
                                  NIS_RES_STATUS(allres) = err;
                              ++done;
                          }
                      }
                      else
                          ++done;
                      break;
                  case NIS_CBRESULTS:
                      if (cb != NULL)
                      {
                          __nis_do_callback(&bptr, &res->cookie, cb);
                          NIS_RES_STATUS(res) = cb->result;
  
                          if (!(flags & ALL_RESULTS))
                              ++done;
                          else
                          {
                              enum nis_error err = __follow_path(
                                  &tablepath, &tableptr, ibreq, &bptr);
                              if (err != NIS_SUCCESS)
                              {
                                  if (err == NIS_NOMEMORY)
                                      NIS_RES_STATUS(res) = err;
                                  ++done;
                              }
                          }
                      }
                      break;
                  case NIS_SYSTEMERROR:
                  case NIS_NOSUCHNAME:
                  case NIS_NOT_ME:
                      /* If we had first tried the old binding, do nothing, but
                         get a new binding */
                      if (!first_try)
                      {
                          if (__nisbind_next(&bptr) != NIS_SUCCESS)
                          {
                              ++done;
                              break; /* No more servers to search */
                          }
                          while (__nisbind_connect(&bptr) != NIS_SUCCESS)
                          {
                              if (__nisbind_next(&bptr) != NIS_SUCCESS)
                              {
                                  ++done;
                                  break; /* No more servers to search */
                              }
                          }
                          goto again;
                      }
                      break;
                  default:
                      if (!first_try)
                      {
                          /* Try the next domainname if we don't follow a link. */
                          free(ibreq->ibr_name);
                          ibreq->ibr_name = NULL;
                          if (__glibc_unlikely(count_links))
                          {
                              NIS_RES_STATUS(res) = NIS_LINKNAMEERROR;
                              ++done;
                              break;
                          }
                          ++name_nr;
                          if (names[name_nr] == NULL)
                          {
                              ++done;
                              break;
                          }
                          ibreq->ibr_name = strdup(names[name_nr]);
                          if (ibreq->ibr_name == NULL)
                          {
                              NIS_RES_STATUS(res) = NIS_NOMEMORY;
                              goto fail;
                          }
                          first_try = 1; /* Try old binding at first */
                          goto again;
                      }
                      break;
              }
          first_try = 0;
  
          if (cb)
          {
              __nis_destroy_callback(cb);
              ibreq->ibr_cbhost.ibr_cbhost_len = 0;
              ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
              cb = NULL;
          }
  
          __nisbind_destroy(&bptr);
          nis_free_directory(dir);
      }
  
      free(tablepath);
  
      if (names != namebuf)
          nis_freenames(names);
  
      nis_free_request(ibreq);
  
      if (allres)
      {
          nis_freeresult(res);
          return allres;
      }
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_list, GLIBC_2_1)
  
      nis_result* nis_add_entry(const_nis_name name, const nis_object* obj2,
                                unsigned int flags)
  {
      nis_result* res = calloc(1, sizeof(nis_result));
      if (res == NULL)
          return NULL;
  
      if (name == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      ib_request* ibreq = __create_ib_request(name, flags);
      if (ibreq == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      nis_object obj;
      memcpy(&obj, obj2, sizeof(nis_object));
  
      size_t namelen = strlen(name);
      char buf1[namelen + 20];
      char buf4[namelen + 20];
  
      if (obj.zo_name == NULL || strlen(obj.zo_name) == 0)
          obj.zo_name = nis_leaf_of_r(name, buf1, sizeof(buf1));
  
      if (obj.zo_owner == NULL || strlen(obj.zo_owner) == 0)
          obj.zo_owner = nis_local_principal();
  
      if (obj.zo_group == NULL || strlen(obj.zo_group) == 0)
          obj.zo_group = nis_local_group();
  
      obj.zo_domain = nis_domain_of_r(name, buf4, sizeof(buf4));
  
      ibreq->ibr_obj.ibr_obj_val = nis_clone_object(&obj, NULL);
      if (ibreq->ibr_obj.ibr_obj_val == NULL)
      {
          nis_free_request(ibreq);
          NIS_RES_STATUS(res) = NIS_NOMEMORY;
          return res;
      }
      ibreq->ibr_obj.ibr_obj_len = 1;
  
      nis_error status = __do_niscall(
          ibreq->ibr_name, NIS_IBADD, (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
          (xdrproc_t)_xdr_nis_result, (caddr_t)res, 0, NULL);
      if (__glibc_unlikely(status != NIS_SUCCESS))
          NIS_RES_STATUS(res) = status;
  
      nis_free_request(ibreq);
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_add_entry, GLIBC_2_1)
  
      nis_result* nis_modify_entry(const_nis_name name, const nis_object* obj2,
                                   unsigned int flags)
  {
      nis_object obj;
      nis_result* res;
      nis_error status;
      ib_request* ibreq;
      size_t namelen = strlen(name);
      char buf1[namelen + 20];
      char buf4[namelen + 20];
  
      res = calloc(1, sizeof(nis_result));
      if (res == NULL)
          return NULL;
  
      ibreq = __create_ib_request(name, flags);
      if (ibreq == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      memcpy(&obj, obj2, sizeof(nis_object));
  
      if (obj.zo_name == NULL || strlen(obj.zo_name) == 0)
          obj.zo_name = nis_leaf_of_r(name, buf1, sizeof(buf1));
  
      if (obj.zo_owner == NULL || strlen(obj.zo_owner) == 0)
          obj.zo_owner = nis_local_principal();
  
      if (obj.zo_group == NULL || strlen(obj.zo_group) == 0)
          obj.zo_group = nis_local_group();
  
      obj.zo_domain = nis_domain_of_r(name, buf4, sizeof(buf4));
  
      ibreq->ibr_obj.ibr_obj_val = nis_clone_object(&obj, NULL);
      if (ibreq->ibr_obj.ibr_obj_val == NULL)
      {
          nis_free_request(ibreq);
          NIS_RES_STATUS(res) = NIS_NOMEMORY;
          return res;
      }
      ibreq->ibr_obj.ibr_obj_len = 1;
  
      status = __do_niscall(ibreq->ibr_name, NIS_IBMODIFY,
                            (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
                            (xdrproc_t)_xdr_nis_result, (caddr_t)res, 0, NULL);
      if (__glibc_unlikely(status != NIS_SUCCESS))
          NIS_RES_STATUS(res) = status;
  
      nis_free_request(ibreq);
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_modify_entry, GLIBC_2_1)
  
      nis_result* nis_remove_entry(const_nis_name name, const nis_object* obj,
                                   unsigned int flags)
  {
      nis_result* res;
      ib_request* ibreq;
      nis_error status;
  
      res = calloc(1, sizeof(nis_result));
      if (res == NULL)
          return NULL;
  
      if (name == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      ibreq = __create_ib_request(name, flags);
      if (ibreq == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      if (obj != NULL)
      {
          ibreq->ibr_obj.ibr_obj_val = nis_clone_object(obj, NULL);
          if (ibreq->ibr_obj.ibr_obj_val == NULL)
          {
              nis_free_request(ibreq);
              NIS_RES_STATUS(res) = NIS_NOMEMORY;
              return res;
          }
          ibreq->ibr_obj.ibr_obj_len = 1;
      }
  
      if ((status = __do_niscall(ibreq->ibr_name, NIS_IBREMOVE,
                                 (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
                                 (xdrproc_t)_xdr_nis_result, (caddr_t)res, 0,
                                 NULL)) != NIS_SUCCESS)
          NIS_RES_STATUS(res) = status;
  
      nis_free_request(ibreq);
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_remove_entry, GLIBC_2_1)
  
      nis_result* nis_first_entry(const_nis_name name)
  {
      nis_result* res;
      ib_request* ibreq;
      nis_error status;
  
      res = calloc(1, sizeof(nis_result));
      if (res == NULL)
          return NULL;
  
      if (name == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      ibreq = __create_ib_request(name, 0);
      if (ibreq == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      status = __do_niscall(ibreq->ibr_name, NIS_IBFIRST,
                            (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
                            (xdrproc_t)_xdr_nis_result, (caddr_t)res, 0, NULL);
  
      if (__glibc_unlikely(status != NIS_SUCCESS))
          NIS_RES_STATUS(res) = status;
  
      nis_free_request(ibreq);
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_first_entry, GLIBC_2_1)
  
      nis_result* nis_next_entry(const_nis_name name, const netobj* cookie)
  {
      nis_result* res;
      ib_request* ibreq;
      nis_error status;
  
      res = calloc(1, sizeof(nis_result));
      if (res == NULL)
          return NULL;
  
      if (name == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      ibreq = __create_ib_request(name, 0);
      if (ibreq == NULL)
      {
          NIS_RES_STATUS(res) = NIS_BADNAME;
          return res;
      }
  
      if (cookie != NULL)
      {
          ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
          ibreq->ibr_cookie.n_len = cookie->n_len;
      }
  
      status = __do_niscall(ibreq->ibr_name, NIS_IBNEXT,
                            (xdrproc_t)_xdr_ib_request, (caddr_t)ibreq,
                            (xdrproc_t)_xdr_nis_result, (caddr_t)res, 0, NULL);
  
      if (__glibc_unlikely(status != NIS_SUCCESS))
          NIS_RES_STATUS(res) = status;
  
      if (cookie != NULL)
      {
          /* Don't give cookie free, it is not from us */
          ibreq->ibr_cookie.n_bytes = NULL;
          ibreq->ibr_cookie.n_len = 0;
      }
  
      nis_free_request(ibreq);
  
      return res;
  }
  libnsl_hidden_nolink_def(nis_next_entry, GLIBC_2_1)
  