| /* Copyright (c) 1997-2016 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 <string.h> | 
 | #include <rpcsvc/nis.h> | 
 | #include <libc-internal.h> | 
 |  | 
 | #include "nis_xdr.h" | 
 | #include "nis_intern.h" | 
 | #include "libnsl.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_def (__create_ib_request) | 
 |  | 
 | 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_def (__follow_path) | 
 |  | 
 |  | 
 | 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_def (nis_list) | 
 |  | 
 | 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; | 
 | } | 
 |  | 
 | 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; | 
 | } | 
 |  | 
 | 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; | 
 | } | 
 |  | 
 | 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; | 
 | } | 
 |  | 
 | 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; | 
 | } |