1  /* Copyright (c) 1997-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <assert.h>
      19  #include <string.h>
      20  #include <rpcsvc/nis.h>
      21  #include <libc-diag.h>
      22  #include <shlib-compat.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 (__glibc_unlikely (val == NULL))
      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_nolink_def (__create_ib_request, GLIBC_PRIVATE)
     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  
     180    /* Since tableptr is only set here, and it's set when tablepath is NULL,
     181       which it is initially defined as, we know it will always be set here.  */
     182    DIAG_PUSH_NEEDS_COMMENT;
     183    DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized");
     184  
     185    if (*tableptr == NULL)
     186      return NIS_NOTFOUND;
     187  
     188    char *newname = strsep (tableptr, ":");
     189    if (newname[0] == '\0')
     190      return NIS_NOTFOUND;
     191  
     192    DIAG_POP_NEEDS_COMMENT;
     193  
     194    newname = strdup (newname);
     195    if (newname == NULL)
     196      return NIS_NOMEMORY;
     197  
     198    free (ibreq->ibr_name);
     199    ibreq->ibr_name = newname;
     200  
     201    return NIS_SUCCESS;
     202  }
     203  libnsl_hidden_nolink_def (__follow_path, GLIBC_PRIVATE)
     204  
     205  
     206  nis_result *
     207  nis_list (const_nis_name name, unsigned int flags,
     208  	  int (*callback) (const_nis_name name,
     209  			   const nis_object *object,
     210  			   const void *userdata),
     211  	  const void *userdata)
     212  {
     213    nis_result *res = malloc (sizeof (nis_result));
     214    ib_request *ibreq;
     215    int status;
     216    enum clnt_stat clnt_status;
     217    int count_links = 0;		/* We will only follow NIS_MAXLINKS links! */
     218    int done = 0;
     219    nis_name *names;
     220    nis_name namebuf[2] = {NULL, NULL};
     221    int name_nr = 0;
     222    nis_cb *cb = NULL;
     223    char *tableptr;
     224    char *tablepath = NULL;
     225    int first_try = 0; /* Do we try the old binding at first ? */
     226    nis_result *allres = NULL;
     227  
     228    if (res == NULL)
     229      return NULL;
     230  
     231    if (name == NULL)
     232      {
     233        status = NIS_BADNAME;
     234      err_out:
     235        nis_freeresult (allres);
     236        memset (res, '\0', sizeof (nis_result));
     237        NIS_RES_STATUS (res) = status;
     238        return res;
     239      }
     240  
     241    ibreq = __create_ib_request (name, flags);
     242    if (ibreq == NULL)
     243      {
     244        status = NIS_BADNAME;
     245        goto err_out;
     246      }
     247  
     248    if ((flags & EXPAND_NAME)
     249        && ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.')
     250      {
     251        names = nis_getnames (ibreq->ibr_name);
     252        free (ibreq->ibr_name);
     253        ibreq->ibr_name = NULL;
     254        if (names == NULL)
     255  	{
     256  	  nis_free_request (ibreq);
     257  	  status = NIS_BADNAME;
     258  	  goto err_out;
     259  	}
     260        ibreq->ibr_name = strdup (names[name_nr]);
     261        if (ibreq->ibr_name == NULL)
     262  	{
     263  	  nis_freenames (names);
     264  	  nis_free_request (ibreq);
     265  	  status = NIS_NOMEMORY;
     266  	  goto err_out;
     267  	}
     268      }
     269    else
     270      {
     271        names = namebuf;
     272        names[name_nr] = ibreq->ibr_name;
     273      }
     274  
     275    cb = NULL;
     276  
     277    while (!done)
     278      {
     279        dir_binding bptr;
     280        directory_obj *dir = NULL;
     281  
     282        memset (res, '\0', sizeof (nis_result));
     283  
     284        status = __nisfind_server (ibreq->ibr_name,
     285  				 ibreq->ibr_srch.ibr_srch_val != NULL,
     286  				 &dir, &bptr, flags & ~MASTER_ONLY);
     287        if (status != NIS_SUCCESS)
     288  	{
     289  	  NIS_RES_STATUS (res) = status;
     290  	  goto fail3;
     291  	}
     292  
     293        while (__nisbind_connect (&bptr) != NIS_SUCCESS)
     294  	if (__glibc_unlikely (__nisbind_next (&bptr) != NIS_SUCCESS))
     295  	  {
     296  	    NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
     297  	    goto fail;
     298  	  }
     299  
     300        if (callback != NULL)
     301  	{
     302  	  assert (cb == NULL);
     303  	  cb = __nis_create_callback (callback, userdata, flags);
     304  	  ibreq->ibr_cbhost.ibr_cbhost_len = 1;
     305  	  ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
     306  	}
     307  
     308      again:
     309        clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
     310  			       (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
     311  			       (xdrproc_t) _xdr_nis_result,
     312  			       (caddr_t) res, RPCTIMEOUT);
     313  
     314        if (__glibc_unlikely (clnt_status != RPC_SUCCESS))
     315  	NIS_RES_STATUS (res) = NIS_RPCERROR;
     316        else
     317  	switch (NIS_RES_STATUS (res))
     318  	  { /* start switch */
     319  	  case NIS_PARTIAL:
     320  	  case NIS_SUCCESS:
     321  	  case NIS_S_SUCCESS:
     322  	    if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
     323  		&& (flags & FOLLOW_LINKS))	/* We are following links.  */
     324  	      {
     325  		free (ibreq->ibr_name);
     326  		ibreq->ibr_name = NULL;
     327  		/* If we hit the link limit, bail.  */
     328  		if (__glibc_unlikely (count_links > NIS_MAXLINKS))
     329  		  {
     330  		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
     331  		    ++done;
     332  		    break;
     333  		  }
     334  		++count_links;
     335  		ibreq->ibr_name =
     336  		  strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
     337  		if (ibreq->ibr_name == NULL)
     338  		  {
     339  		    NIS_RES_STATUS (res) = NIS_NOMEMORY;
     340  		  fail:
     341  		    __nisbind_destroy (&bptr);
     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  		enum nis_error err = __follow_path (&tablepath, &tableptr,
     379  						    ibreq, &bptr);
     380  		if (err != NIS_SUCCESS)
     381  		  {
     382  		    if (err == NIS_NOMEMORY)
     383  		      NIS_RES_STATUS (res) = err;
     384  		    ++done;
     385  		  }
     386  		else
     387  		  {
     388  		    /* The following is a non-obvious optimization.  A
     389  		       nis_freeresult call would call xdr_free as the
     390  		       following code.  But it also would unnecessarily
     391  		       free the result structure.  We avoid this here
     392  		       along with the necessary tests.  */
     393  		    xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
     394  		    memset (res, '\0', sizeof (*res));
     395  		    first_try = 1;
     396  		    goto again;
     397  		  }
     398  	      }
     399  	    else if ((flags & (FOLLOW_PATH | ALL_RESULTS))
     400  		     == (FOLLOW_PATH | ALL_RESULTS))
     401  	      {
     402  		if (allres == NULL)
     403  		  {
     404  		    allres = res;
     405  		    res = malloc (sizeof (nis_result));
     406  		    if (res == NULL)
     407  		      {
     408  			res = allres;
     409  			allres = NULL;
     410  			NIS_RES_STATUS (res) = NIS_NOMEMORY;
     411  			goto fail;
     412  		      }
     413  		    NIS_RES_STATUS (res) = NIS_RES_STATUS (allres);
     414  		  }
     415  		else
     416  		  {
     417  		    nis_object *objects_val
     418  		      = realloc (NIS_RES_OBJECT (allres),
     419  				 (NIS_RES_NUMOBJ (allres)
     420  				  + NIS_RES_NUMOBJ (res))
     421  				 * sizeof (nis_object));
     422  		    if (objects_val == NULL)
     423  		      {
     424  			NIS_RES_STATUS (res) = NIS_NOMEMORY;
     425  			goto fail;
     426  		      }
     427  		    NIS_RES_OBJECT (allres) = objects_val;
     428  		    memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres),
     429  			    NIS_RES_OBJECT (res),
     430  			    NIS_RES_NUMOBJ (res) * sizeof (nis_object));
     431  		    NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res);
     432  		    NIS_RES_NUMOBJ (res) = 0;
     433  		    free (NIS_RES_OBJECT (res));
     434  		    NIS_RES_OBJECT (res) = NULL;
     435  		    NIS_RES_STATUS (allres) = NIS_RES_STATUS (res);
     436  		    xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
     437  		  }
     438  		enum nis_error err = __follow_path (&tablepath, &tableptr,
     439  						    ibreq, &bptr);
     440  		if (err != NIS_SUCCESS)
     441  		  {
     442  		    /* Prepare for the nis_freeresult call.  */
     443  		    memset (res, '\0', sizeof (*res));
     444  
     445  		    if (err == NIS_NOMEMORY)
     446  		      NIS_RES_STATUS (allres) = err;
     447  		    ++done;
     448  		  }
     449  	      }
     450  	    else
     451  	      ++done;
     452  	    break;
     453  	  case NIS_CBRESULTS:
     454  	    if (cb != NULL)
     455  	      {
     456  		__nis_do_callback (&bptr, &res->cookie, cb);
     457  		NIS_RES_STATUS (res) = cb->result;
     458  
     459  		if (!(flags & ALL_RESULTS))
     460  		  ++done;
     461  		else
     462  		  {
     463  		    enum nis_error err
     464  		      = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
     465  		    if (err != NIS_SUCCESS)
     466  		      {
     467  			if (err == NIS_NOMEMORY)
     468  			  NIS_RES_STATUS (res) = err;
     469  			++done;
     470  		      }
     471  		  }
     472  	      }
     473  	    break;
     474  	  case NIS_SYSTEMERROR:
     475  	  case NIS_NOSUCHNAME:
     476  	  case NIS_NOT_ME:
     477  	    /* If we had first tried the old binding, do nothing, but
     478  	       get a new binding */
     479  	    if (!first_try)
     480  	      {
     481  		if (__nisbind_next (&bptr) != NIS_SUCCESS)
     482  		  {
     483  		    ++done;
     484  		    break; /* No more servers to search */
     485  		  }
     486  		while (__nisbind_connect (&bptr) != NIS_SUCCESS)
     487  		  {
     488  		    if (__nisbind_next (&bptr) != NIS_SUCCESS)
     489  		      {
     490  			++done;
     491  			break; /* No more servers to search */
     492  		      }
     493  		  }
     494  		goto again;
     495  	      }
     496  	    break;
     497  	  default:
     498  	    if (!first_try)
     499  	      {
     500  		/* Try the next domainname if we don't follow a link.  */
     501  		free (ibreq->ibr_name);
     502  		ibreq->ibr_name = NULL;
     503  		if (__glibc_unlikely (count_links))
     504  		  {
     505  		    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
     506  		    ++done;
     507  		    break;
     508  		  }
     509  		++name_nr;
     510  		if (names[name_nr] == NULL)
     511  		  {
     512  		    ++done;
     513  		    break;
     514  		  }
     515  		ibreq->ibr_name = strdup (names[name_nr]);
     516  		if (ibreq->ibr_name == NULL)
     517  		  {
     518  		    NIS_RES_STATUS (res) = NIS_NOMEMORY;
     519  		    goto fail;
     520  		  }
     521  		first_try = 1; /* Try old binding at first */
     522  		goto again;
     523  	      }
     524  	    break;
     525  	  }
     526        first_try = 0;
     527  
     528        if (cb)
     529  	{
     530  	  __nis_destroy_callback (cb);
     531  	  ibreq->ibr_cbhost.ibr_cbhost_len = 0;
     532  	  ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
     533  	  cb = NULL;
     534  	}
     535  
     536        __nisbind_destroy (&bptr);
     537        nis_free_directory (dir);
     538      }
     539  
     540    free (tablepath);
     541  
     542    if (names != namebuf)
     543      nis_freenames (names);
     544  
     545    nis_free_request (ibreq);
     546  
     547    if (allres)
     548      {
     549        nis_freeresult (res);
     550        return allres;
     551      }
     552  
     553    return res;
     554  }
     555  libnsl_hidden_nolink_def (nis_list, GLIBC_2_1)
     556  
     557  nis_result *
     558  nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
     559  {
     560    nis_result *res = calloc (1, sizeof (nis_result));
     561    if (res == NULL)
     562      return NULL;
     563  
     564    if (name == NULL)
     565      {
     566        NIS_RES_STATUS (res) = NIS_BADNAME;
     567        return res;
     568      }
     569  
     570    ib_request *ibreq = __create_ib_request (name, flags);
     571    if (ibreq == NULL)
     572      {
     573        NIS_RES_STATUS (res) = NIS_BADNAME;
     574        return res;
     575      }
     576  
     577    nis_object obj;
     578    memcpy (&obj, obj2, sizeof (nis_object));
     579  
     580    size_t namelen = strlen (name);
     581    char buf1[namelen + 20];
     582    char buf4[namelen + 20];
     583  
     584    if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
     585      obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
     586  
     587    if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
     588      obj.zo_owner = nis_local_principal ();
     589  
     590    if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
     591      obj.zo_group = nis_local_group ();
     592  
     593    obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
     594  
     595    ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
     596    if (ibreq->ibr_obj.ibr_obj_val == NULL)
     597      {
     598        nis_free_request (ibreq);
     599        NIS_RES_STATUS (res) = NIS_NOMEMORY;
     600        return res;
     601      }
     602    ibreq->ibr_obj.ibr_obj_len = 1;
     603  
     604    nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
     605  				   (xdrproc_t) _xdr_ib_request,
     606  				   (caddr_t) ibreq,
     607  				   (xdrproc_t) _xdr_nis_result,
     608  				   (caddr_t) res, 0, NULL);
     609    if (__glibc_unlikely (status != NIS_SUCCESS))
     610      NIS_RES_STATUS (res) = status;
     611  
     612    nis_free_request (ibreq);
     613  
     614    return res;
     615  }
     616  libnsl_hidden_nolink_def (nis_add_entry, GLIBC_2_1)
     617  
     618  nis_result *
     619  nis_modify_entry (const_nis_name name, const nis_object *obj2,
     620  		  unsigned int flags)
     621  {
     622    nis_object obj;
     623    nis_result *res;
     624    nis_error status;
     625    ib_request *ibreq;
     626    size_t namelen = strlen (name);
     627    char buf1[namelen + 20];
     628    char buf4[namelen + 20];
     629  
     630    res = calloc (1, sizeof (nis_result));
     631    if (res == NULL)
     632      return NULL;
     633  
     634    ibreq = __create_ib_request (name, flags);
     635    if (ibreq == NULL)
     636      {
     637        NIS_RES_STATUS (res) = NIS_BADNAME;
     638        return res;
     639      }
     640  
     641    memcpy (&obj, obj2, sizeof (nis_object));
     642  
     643    if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
     644      obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
     645  
     646    if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
     647      obj.zo_owner = nis_local_principal ();
     648  
     649    if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
     650      obj.zo_group = nis_local_group ();
     651  
     652    obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
     653  
     654    ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
     655    if (ibreq->ibr_obj.ibr_obj_val == NULL)
     656      {
     657        nis_free_request (ibreq);
     658        NIS_RES_STATUS (res) = NIS_NOMEMORY;
     659        return res;
     660      }
     661    ibreq->ibr_obj.ibr_obj_len = 1;
     662  
     663    status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
     664  			 (xdrproc_t) _xdr_ib_request,
     665  			 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
     666  			 (caddr_t) res, 0, NULL);
     667    if (__glibc_unlikely (status != NIS_SUCCESS))
     668      NIS_RES_STATUS (res) = status;
     669  
     670    nis_free_request (ibreq);
     671  
     672    return res;
     673  }
     674  libnsl_hidden_nolink_def (nis_modify_entry, GLIBC_2_1)
     675  
     676  nis_result *
     677  nis_remove_entry (const_nis_name name, const nis_object *obj,
     678  		  unsigned int flags)
     679  {
     680    nis_result *res;
     681    ib_request *ibreq;
     682    nis_error status;
     683  
     684    res = calloc (1, sizeof (nis_result));
     685    if (res == NULL)
     686      return NULL;
     687  
     688    if (name == NULL)
     689      {
     690        NIS_RES_STATUS (res) = NIS_BADNAME;
     691        return res;
     692      }
     693  
     694    ibreq = __create_ib_request (name, flags);
     695    if (ibreq == NULL)
     696      {
     697        NIS_RES_STATUS (res) = NIS_BADNAME;
     698        return res;
     699      }
     700  
     701    if (obj != NULL)
     702      {
     703        ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL);
     704        if (ibreq->ibr_obj.ibr_obj_val == NULL)
     705  	{
     706  	  nis_free_request (ibreq);
     707  	  NIS_RES_STATUS (res) = NIS_NOMEMORY;
     708  	  return res;
     709  	}
     710        ibreq->ibr_obj.ibr_obj_len = 1;
     711      }
     712  
     713    if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE,
     714  			      (xdrproc_t) _xdr_ib_request,
     715  			      (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
     716  			      (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
     717      NIS_RES_STATUS (res) = status;
     718  
     719    nis_free_request (ibreq);
     720  
     721    return res;
     722  }
     723  libnsl_hidden_nolink_def (nis_remove_entry, GLIBC_2_1)
     724  
     725  nis_result *
     726  nis_first_entry (const_nis_name name)
     727  {
     728    nis_result *res;
     729    ib_request *ibreq;
     730    nis_error status;
     731  
     732    res = calloc (1, sizeof (nis_result));
     733    if (res == NULL)
     734      return NULL;
     735  
     736    if (name == NULL)
     737      {
     738        NIS_RES_STATUS (res) = NIS_BADNAME;
     739        return res;
     740      }
     741  
     742    ibreq = __create_ib_request (name, 0);
     743    if (ibreq == NULL)
     744      {
     745        NIS_RES_STATUS (res) = NIS_BADNAME;
     746        return res;
     747      }
     748  
     749    status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST,
     750  			 (xdrproc_t) _xdr_ib_request,
     751  			 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
     752  			 (caddr_t) res, 0, NULL);
     753  
     754    if (__glibc_unlikely (status != NIS_SUCCESS))
     755      NIS_RES_STATUS (res) = status;
     756  
     757    nis_free_request (ibreq);
     758  
     759    return res;
     760  }
     761  libnsl_hidden_nolink_def (nis_first_entry, GLIBC_2_1)
     762  
     763  nis_result *
     764  nis_next_entry (const_nis_name name, const netobj *cookie)
     765  {
     766    nis_result *res;
     767    ib_request *ibreq;
     768    nis_error status;
     769  
     770    res = calloc (1, sizeof (nis_result));
     771    if (res == NULL)
     772      return NULL;
     773  
     774    if (name == NULL)
     775      {
     776        NIS_RES_STATUS (res) = NIS_BADNAME;
     777        return res;
     778      }
     779  
     780    ibreq = __create_ib_request (name, 0);
     781    if (ibreq == NULL)
     782      {
     783        NIS_RES_STATUS (res) = NIS_BADNAME;
     784        return res;
     785      }
     786  
     787    if (cookie != NULL)
     788      {
     789        ibreq->ibr_cookie.n_bytes = cookie->n_bytes;
     790        ibreq->ibr_cookie.n_len = cookie->n_len;
     791      }
     792  
     793    status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT,
     794  			 (xdrproc_t) _xdr_ib_request,
     795  			 (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
     796  			 (caddr_t) res, 0, NULL);
     797  
     798    if (__glibc_unlikely (status != NIS_SUCCESS))
     799      NIS_RES_STATUS (res) = status;
     800  
     801    if (cookie != NULL)
     802      {
     803        /* Don't give cookie free, it is not from us */
     804        ibreq->ibr_cookie.n_bytes = NULL;
     805        ibreq->ibr_cookie.n_len = 0;
     806      }
     807  
     808    nis_free_request (ibreq);
     809  
     810    return res;
     811  }
     812  libnsl_hidden_nolink_def (nis_next_entry, GLIBC_2_1)