1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright (c) 2001 by Sun Microsystems, Inc.
  24  * All rights reserved.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <string.h>
  30 #include <sys/syslog.h>
  31 #include <sys/types.h>
  32 #include <rpc/types.h>
  33 #include <rpc/xdr.h>
  34 #include <rpcsvc/nis.h>
  35 
  36 #include "db_mindex_c.h"
  37 
  38 #include "ldap_xdr.h"
  39 #include "ldap_util.h"
  40 
  41 extern bool_t xdr_nis_object();
  42 
  43 /*
  44  * In order not to change the on-disk NIS+ DB format, we need make sure
  45  * that XDR does nothing for the new structures added to various C++
  46  * classes.
  47  */
  48 
  49 bool_t
  50 xdr___nis_table_mapping_t(XDR *xdrs, void *t) {
  51         return (TRUE);
  52 }
  53 
  54 bool_t
  55 xdr___nisdb_ptr_t(XDR *xdrs, void *ptr) {
  56         return (TRUE);
  57 }
  58 
  59 bool_t
  60 xdr___nisdb_dictionary_defer_t(XDR *xdrs, void *defer) {
  61         return (TRUE);
  62 }
  63 
  64 bool_t
  65 xdr___nisdb_rwlock_t(XDR *xdrs, void *rw) {
  66         return (TRUE);
  67 }
  68 
  69 bool_t
  70 xdr___nisdb_flag_t(XDR *xdrs, void *flag) {
  71         return (TRUE);
  72 }
  73 
  74 /*
  75  * Imported from rpc.nisd/nis_db.c
  76  *
  77  * Special abbreviated XDR string which knows that the namep parameter (mainly
  78  * owner and group) has a trailing end which matches the last 'n' characters
  79  * in the domainname part.  It makes use of those common characters to
  80  * encode/decode this information.  We append an integer string to the
  81  * name to be encoded which denotes the place in the domainname from where the
  82  * common string starts.  For example, if the name was "foo.my.domain." and the
  83  * domainname was "my.domain.", the name would be encoded as "foo.10" because
  84  * the length of the common part "my.domain." is 10.
  85  */
  86 bool_t
  87 xdr_nis_name_abbrev(
  88         XDR             *xdrs,
  89         nis_name        *namep,
  90         nis_name        domainname)     /* domainname field from the table */
  91 {
  92         size_t  name_len, dom_len, min_len;
  93         char    buf[NIS_MAXNAMELEN];
  94         char    *name;
  95         char    *lenstr, *tmp;
  96         int     i;
  97 
  98         switch (xdrs->x_op) {
  99         case XDR_ENCODE:
 100                 /* Get the start of the common part */
 101                 name = *namep;
 102                 name_len = strlen(name);
 103                 if (name_len == 0)
 104                         return (xdr_nis_name(xdrs, namep));
 105                 dom_len = strlen(domainname);
 106                 min_len = (name_len < dom_len) ? name_len : dom_len;
 107                 for (i = 1; i <= min_len; i++) {
 108                         if (name[name_len - i] != domainname[dom_len - i])
 109                                 break;
 110                 }
 111                 i--;
 112                 memcpy(buf, name, name_len - i);
 113                 sprintf(buf + name_len - i, ".%d", dom_len - i);
 114                 tmp = buf;
 115                 return (xdr_nis_name(xdrs, &tmp));
 116 
 117         case XDR_DECODE:
 118                 tmp = buf;
 119                 if (!xdr_nis_name(xdrs, &tmp))
 120                     return (FALSE);
 121                 if ((buf[0] == NULL) || buf[strlen(buf) - 1] == '.') {
 122                         /* It is either a FQN or a NULL string */
 123                         if (*namep) {
 124                                 strcpy(*namep, buf);
 125                                 return (TRUE);
 126                         } else {
 127                                 if ((*namep = strdup(buf)) == NULL)
 128                                         return (FALSE);
 129                                 else
 130                                         return (TRUE);
 131                         }
 132                 }
 133                 /* Now concoct the new name */
 134                 if ((lenstr = strrchr(buf, '.')) == NULL) {
 135                         /* something went wrong here */
 136                         syslog(LOG_ERR,
 137                                 "xdr_nis_name_abbrev: no dot found in %s", buf);
 138                         return (FALSE);
 139                 }
 140                 i = atoi(lenstr + 1);
 141                 strcpy(lenstr, domainname + i);
 142                 if (*namep) {
 143                         strcpy(*namep, buf);
 144                 } else {
 145                         if ((*namep = strdup(buf)) == NULL)
 146                                 return (FALSE);
 147                 }
 148                 return (TRUE);
 149 
 150         default:
 151                 return (xdr_nis_name(xdrs, namep));
 152         }
 153 }
 154 
 155 /*
 156  * Imported from rpc.nisd/nis_db.c
 157  *
 158  * special XDR for fetus object.  We create the actual object from the
 159  * "forming" object plus the table object.  We create this special object to
 160  * save the following components of the nis_object:
 161  *      zo_name and zo_domain: replaced by just the length field of 0.  We had
 162  *              to keep the length field for backward compatibility.  If we
 163  *              ever change the object format, we should fix this.
 164  *      zo_owner and zo_group: we condensed it by abbreviating the common part
 165  *              shared between the table object and the entry object
 166  *      en_type: Avoided altogether
 167  *      zo_type and other en_data: Avoided altogether.
 168  *
 169  * XXX: If the definition of nis_object ever changes, this should be changed.
 170  */
 171 bool_t
 172 xdr_nis_fetus_object(
 173         XDR             *xdrs,
 174         nis_object      *objp,  /* Entry object */
 175         nis_object      *tobj)  /* Table object */
 176 {
 177         uint_t  size;
 178 
 179         if (xdrs->x_op == XDR_FREE)
 180                 return (xdr_nis_object(xdrs, objp));
 181         if (!xdr_nis_oid(xdrs, &objp->zo_oid))
 182                 return (FALSE);
 183 
 184         /*
 185          * While encoding of zo_name, we put 0 in the length field, while for
 186          * decoding, we get the name from the table object.
 187          */
 188         if (xdrs->x_op == XDR_ENCODE) {
 189                 size = 0;
 190                 if (!xdr_u_int(xdrs, &size))
 191                         return (FALSE);
 192         } else {
 193                 if (!xdr_u_int(xdrs, &size))
 194                         return (FALSE);
 195                 if (size == 0) {        /* shrinked format */
 196                         /* get the name from the table object */
 197                         if ((objp->zo_name = strdup(tobj->zo_name)) == NULL)
 198                                 return (FALSE);
 199                 } else {
 200                         /*
 201                          * We are opening up the xdr_string implementation here
 202                          * because we called xdr_u_int() earlier.
 203                          */
 204                         if ((objp->zo_name = (char *)malloc(size + 1)) == NULL)
 205                                 return (FALSE);
 206                         if (!xdr_opaque(xdrs, objp->zo_name, size))
 207                                 return (FALSE);
 208                 }
 209         }
 210 
 211         /*
 212          * We use the xdr_nis_name_abbrev() function for both owner
 213          * and group which constructs the name from the domain name.
 214          */
 215         if (!xdr_nis_name_abbrev(xdrs, &objp->zo_owner, tobj->zo_domain))
 216                 return (FALSE);
 217         if (!xdr_nis_name_abbrev(xdrs, &objp->zo_group, tobj->zo_domain))
 218                 return (FALSE);
 219 
 220         /*
 221          * While encoding of zo_domain, we put 0 in the length field, while for
 222          * decoding, we get the name from the table object.  Same as above for
 223          * the name.  Could have used a function instead.
 224          */
 225         if (xdrs->x_op == XDR_ENCODE) {
 226                 size = 0;
 227                 if (!xdr_u_int(xdrs, &size))
 228                         return (FALSE);
 229         } else {
 230                 if (!xdr_u_int(xdrs, &size))
 231                         return (FALSE);
 232                 if (size == 0) {        /* shrinked format */
 233                         /* get the name from the table object */
 234                         if ((objp->zo_domain = strdup(tobj->zo_domain)) == NULL)
 235                                 return (FALSE);
 236                 } else {
 237                         /*
 238                          * We are opening up the xdr_string implementation here
 239                          * because we called xdr_u_int() earlier.
 240                          */
 241                         if ((objp->zo_domain = (char *)malloc(size + 1))
 242                                 == NULL)
 243                                 return (FALSE);
 244                         if (!xdr_opaque(xdrs, objp->zo_domain, size))
 245                                 return (FALSE);
 246                 }
 247         }
 248 
 249         if (!xdr_u_int(xdrs, &objp->zo_access))
 250                 return (FALSE);
 251         if (!xdr_u_int(xdrs, &objp->zo_ttl))
 252                 return (FALSE);
 253 
 254         /*
 255          * We know that this is an entry object, so we'll save all the entry_obj
 256          * space because we can recreate it later.
 257          */
 258         if (xdrs->x_op == XDR_ENCODE)
 259                 return (TRUE);
 260         /* Now for the DECODE case, just handcraft the entries and ignore XDR */
 261         objp->zo_data.zo_type = NIS_ENTRY_OBJ;
 262         if ((objp->zo_data.objdata_u.en_data.en_type =
 263                 strdup(tobj->zo_data.objdata_u.ta_data.ta_type)) == NULL)
 264                 return (FALSE);
 265         objp->zo_data.objdata_u.en_data.en_cols.en_cols_val = NULL;
 266         objp->zo_data.objdata_u.en_data.en_cols.en_cols_len = 0;
 267         return (TRUE);
 268 }
 269 
 270 static const char       *in_directory = "IN_DIRECTORY";
 271 
 272 /*
 273  * Given an input NIS+ object, create the kind
 274  * of pseudo-entry_obj (with an XDR-encoded nis_object in the
 275  * first column) that's stored in the DB. Note that:
 276  *
 277  *      If the input object is an entry, it's assumed to have the
 278  *      columns moved up one step (col 0 in en_cols.en_cols_val[1],
 279  *      etc.). en_cols.en_cols_val[0] will be overwritten. The
 280  *      input object will be changed (some pointers set to zero,
 281  *      etc.) on exit.
 282  *
 283  *      'eo' is assumed to be a pointer to an empty entry_obj (or,
 284  *      at least, one that can be overwritten). It must not be a
 285  *      pointer to the entry_obj in 'obj'. If the input object is
 286  *      of a type other than entry, the 'eo' pointer must have
 287  *      en_cols.en_cols_val appropriately initialized to an array of
 288  *      (at least) length one.
 289  *
 290  *      'tobj' is a pointer to the table object for the table for
 291  *      which the entry_obj is destined. It's needed for entry objects,
 292  *      but unused for other object types.
 293  */
 294 entry_obj *
 295 makePseudoEntryObj(nis_object *obj, entry_obj *eo, nis_object *tobj) {
 296         int             bufsize;
 297         char            *buf;
 298         XDR             xdrs;
 299         bool_t          xret;
 300         uint_t          ecl;
 301         entry_col       *ecv;
 302         char            *myself = "makePseudoEntryObj";
 303 
 304         if (obj == 0 || eo == 0)
 305                 return (0);
 306 
 307         if (obj->zo_data.zo_type == NIS_ENTRY_OBJ) {
 308                 *eo = obj->zo_data.objdata_u.en_data;
 309                 eo->en_type = 0;
 310 
 311                 /*
 312                  * To prevent the XDR function from making a copy of
 313                  * the entry columns, we set the columns structure to
 314                  * 0 (ie no column data)
 315                  */
 316                 ecl = obj->EN_data.en_cols.en_cols_len;
 317                 ecv = obj->EN_data.en_cols.en_cols_val;
 318                 obj->EN_data.en_cols.en_cols_len  = 0;
 319                 obj->EN_data.en_cols.en_cols_val  = 0;
 320         } else {
 321                 eo->en_type = (char *)in_directory;
 322         }
 323 
 324         bufsize = xdr_sizeof(xdr_nis_object, obj);
 325         buf = am(myself, bufsize);
 326         if (buf == 0) {
 327                 if (obj->zo_data.zo_type == NIS_ENTRY_OBJ) {
 328                         obj->EN_data.en_cols.en_cols_len = ecl;
 329                         obj->EN_data.en_cols.en_cols_val = ecv;
 330                 }
 331                 return (0);
 332         }
 333 
 334         xdrmem_create(&xdrs, (char *)buf, bufsize, XDR_ENCODE);
 335 
 336         if (obj->zo_data.zo_type == NIS_ENTRY_OBJ) {
 337                 xret = xdr_nis_fetus_object(&xdrs, obj, tobj);
 338         } else {
 339                 xret = xdr_nis_object(&xdrs, obj);
 340         }
 341 
 342         /* Restore the 'obj' */
 343         if (obj->zo_data.zo_type == NIS_ENTRY_OBJ) {
 344                 obj->EN_data.en_cols.en_cols_len = ecl;
 345                 obj->EN_data.en_cols.en_cols_val = ecv;
 346         }
 347 
 348         if (!xret) {
 349                 logmsg(MSG_NOTIMECHECK, LOG_ERR,
 350                         "%s: XDR encode failure", myself);
 351                 sfree(buf);
 352                 return (0);
 353         }
 354 
 355         eo->en_cols.en_cols_val[0].ec_value.ec_value_val = buf;
 356         eo->en_cols.en_cols_val[0].ec_value.ec_value_len = xdr_getpos(&xdrs);
 357         eo->en_cols.en_cols_val[0].ec_flags = EN_BINARY+EN_XDR;
 358 
 359         return (eo);
 360 }
 361 
 362 nis_object *
 363 unmakePseudoEntryObj(entry_obj *e, nis_object *tobj) {
 364         nis_object      *o;
 365         XDR             xdrs;
 366         bool_t          stat;
 367         char            *myself = "unmakePseudoEntryObj";
 368 
 369         if (e == 0 || e->en_cols.en_cols_val == 0 ||
 370                         e->en_cols.en_cols_len == 0)
 371                 return (0);
 372 
 373         o = am(myself, sizeof (*o));
 374         if (o == 0)
 375                 return (0);
 376 
 377         xdrmem_create(&xdrs, e->en_cols.en_cols_val[0].ec_value.ec_value_val,
 378                         e->en_cols.en_cols_val[0].ec_value.ec_value_len,
 379                         XDR_DECODE);
 380 
 381         if (tobj != 0 && (e->en_type == 0 || e->en_type[0] == '\0')) {
 382                 stat = xdr_nis_fetus_object(&xdrs, o, tobj);
 383         } else {
 384                 stat = xdr_nis_object(&xdrs, o);
 385         }
 386 
 387         if (!stat) {
 388                 sfree(o);
 389                 o = 0;
 390         }
 391 
 392         /*
 393          * If it's an entry object, construct the column information.
 394          * We make this a copy, so that 'o' can be freed using
 395          * nis_destroy_object().
 396          */
 397         if (o != 0 && o->zo_data.zo_type == NIS_ENTRY_OBJ &&
 398                         o->zo_data.objdata_u.en_data.en_cols.en_cols_val == 0 &&
 399                         e->en_cols.en_cols_len > 1) {
 400                 entry_col       *ec, *oec;
 401                 uint_t          i, *ocl;
 402 
 403                 ec = am(myself, (e->en_cols.en_cols_len - 1) * sizeof (ec[0]));
 404                 if (ec == 0) {
 405                         nis_destroy_object(o);
 406                         return (0);
 407                 }
 408 
 409                 o->zo_data.objdata_u.en_data.en_cols.en_cols_val = ec;
 410                 o->zo_data.objdata_u.en_data.en_cols.en_cols_len = 0;
 411                 ocl = &o->zo_data.objdata_u.en_data.en_cols.en_cols_len;
 412                 oec = e->en_cols.en_cols_val;
 413 
 414                 for (i = 1; i < e->en_cols.en_cols_len; i++) {
 415                         uint_t  len;
 416 
 417                         if (oec[i].ec_value.ec_value_val != 0) {
 418                                 len = oec[i].ec_value.ec_value_len;
 419                                 if (len == 0)
 420                                         len++;
 421                                 ec[i-1].ec_value.ec_value_val = am(myself, len);
 422                                 if (ec[i-1].ec_value.ec_value_val == 0) {
 423                                         nis_destroy_object(o);
 424                                         return (0);
 425                                 }
 426                                 (void) memcpy(ec[i-1].ec_value.ec_value_val,
 427                                                 oec[i].ec_value.ec_value_val,
 428                                                 oec[i].ec_value.ec_value_len);
 429                                 ec[i-1].ec_value.ec_value_len =
 430                                                 oec[i].ec_value.ec_value_len;
 431                         } else {
 432                                 ec[i-1].ec_value.ec_value_val = 0;
 433                                 ec[i-1].ec_value.ec_value_len = 0;
 434                         }
 435                         *ocl += 1;
 436                 }
 437         }
 438 
 439         /*
 440          * If it's an entry, and we have the table object, make sure
 441          * zo_name and en_type either already are set, or get them
 442          * from the table.
 443          */
 444         if (o != 0 && o->zo_data.zo_type == NIS_ENTRY_OBJ && tobj != 0) {
 445                 if (o->zo_name == 0)
 446                         o->zo_name = sdup(myself, T, tobj->zo_name);
 447                 if (o->zo_data.objdata_u.en_data.en_type == 0)
 448                         o->zo_data.objdata_u.en_data.en_type = sdup(myself, T,
 449                                 tobj->zo_data.objdata_u.ta_data.ta_type);
 450         }
 451 
 452         return (o);
 453 }
 454 
 455 /*
 456  * Input:  A (nis_object *), and (optionally) an (entry_obj *) array.
 457  * Output: Pointer to an XDR:ed version of an (xdr_nis_object_t).
 458  */
 459 void *
 460 xdrNisObject(nis_object *obj, entry_obj **ea, int numEa, int *xdrLenP) {
 461         xdr_nis_object_t        xno;
 462         void                    *buf;
 463         int                     xdrLen;
 464         XDR                     xdrs;
 465         bool_t                  xret;
 466         char                    *myself = "xdrNisObject";
 467 
 468         if (obj == 0)
 469                 return (0);
 470 
 471         /*
 472          * The version tells us what the XDR:ed buffer contains.
 473          * Should be incremented whenever xdr_nis_object_t changes
 474          * incompatibly.
 475          */
 476         xno.xversion = 1;
 477 
 478         xno.obj = obj;
 479 
 480         if (obj->zo_data.zo_type == NIS_DIRECTORY_OBJ &&
 481                         ea != 0 && numEa > 0) {
 482                 int     i;
 483 
 484                 /*
 485                  * The ea[] array is expected to contain the kind of
 486                  * pseudo-entry object stored in the nisdb incarnation
 487                  * of a NIS+ directory. Column zero contains the XDR:ed
 488                  * directory entry object (which we ignore), while column
 489                  * one contains the name of said entry. It's the latter
 490                  * that we borrow for use in the dirEntry[] list of the
 491                  * xdr_nis_object_t.
 492                  */
 493 
 494                 xno.dirEntry.dirEntry_len = 0;
 495                 xno.dirEntry.dirEntry_val = am(myself, numEa *
 496                         sizeof (xno.dirEntry.dirEntry_val[0]));
 497                 if (xno.dirEntry.dirEntry_val == 0)
 498                         return (0);
 499 
 500                 for (i = 0; i < numEa; i++) {
 501                         if (ea[i] == 0 || ea[i]->en_cols.en_cols_val == 0 ||
 502                                         ea[i]->en_cols.en_cols_len != 2 ||
 503                                         ea[i]->en_cols.en_cols_val[1].
 504                                                 ec_value.ec_value_len == 0)
 505                                 continue;
 506                         /*
 507                          * Yes, there's a NUL at the end of the dir entry
 508                          * name.
 509                          */
 510                         xno.dirEntry.dirEntry_val[xno.dirEntry.dirEntry_len] =
 511                                 ea[i]->en_cols.en_cols_val[1].
 512                                         ec_value.ec_value_val;
 513                         xno.dirEntry.dirEntry_len++;
 514                 }
 515         } else {
 516                 /* No directory entries */
 517                 xno.dirEntry.dirEntry_len = 0;
 518                 xno.dirEntry.dirEntry_val = 0;
 519         }
 520 
 521         xdrLen = xdr_sizeof(xdr_xdr_nis_object_t, &xno);
 522         buf = am(myself, xdrLen);
 523         if (buf == 0)
 524                 return (0);
 525 
 526         xdrmem_create(&xdrs, (char *)buf, xdrLen, XDR_ENCODE);
 527 
 528         xret = xdr_xdr_nis_object_t(&xdrs, &xno);
 529 
 530         sfree(xno.dirEntry.dirEntry_val);
 531 
 532         if (!xret) {
 533                 sfree(buf);
 534                 return (0);
 535         }
 536 
 537         if (xdrLenP != 0)
 538                 *xdrLenP = xdrLen;
 539 
 540         return (buf);
 541 }
 542 
 543 /*
 544  * Input:  Pointer to an XDR:ed version of an (xdr_nis_object_t).
 545  * Output: Pointer to a (nis_object *) and (if the object is a
 546  *         directory) a pointer to an array of (entry_obj *).
 547  */
 548 nis_object *
 549 unXdrNisObject(void *buf, int bufLen, entry_obj ***eaP, int *numEaP) {
 550         xdr_nis_object_t        *xno;
 551         XDR                     xdrs;
 552         bool_t                  xret;
 553         entry_obj               **ea;
 554         int                     numEa;
 555         nis_object              *o;
 556         char                    *myself = "unXdrNisObject";
 557 
 558         if (buf == 0 || bufLen <= 0)
 559                 return (0);
 560 
 561         xno = am(myself, sizeof (*xno));
 562         if (xno == 0)
 563                 return (0);
 564 
 565         xdrmem_create(&xdrs, buf, bufLen, XDR_DECODE);
 566         xret = xdr_xdr_nis_object_t(&xdrs, xno);
 567 
 568         if (!xret) {
 569                 sfree(xno);
 570                 return (0);
 571         }
 572 
 573         switch (xno->xversion) {
 574         case 1:
 575                 break;
 576         default:
 577                 xdr_free(xdr_xdr_nis_object_t, (char *)xno);
 578                 sfree(xno);
 579                 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
 580                         "%s: Unknown xdr_nis_object_t version %d",
 581                         myself, xno->xversion);
 582                 return (0);
 583         }
 584 
 585         if (eaP != 0 && numEaP != 0 && xno->dirEntry.dirEntry_len > 0 &&
 586                         xno->dirEntry.dirEntry_val != 0) {
 587                 ea = am(myself, xno->dirEntry.dirEntry_len * sizeof (ea[0]));
 588                 if (ea == 0) {
 589                         xdr_free(xdr_xdr_nis_object_t, (char *)xno);
 590                         sfree(xno);
 591                         return (0);
 592                 }
 593                 for (numEa = 0; numEa < xno->dirEntry.dirEntry_len; numEa++) {
 594                         ea[numEa] = am(myself, sizeof (*ea[numEa]));
 595                         if (ea[numEa] != 0) {
 596                                 ea[numEa]->en_cols.en_cols_len = 2;
 597                                 ea[numEa]->en_cols.en_cols_val = am(myself,
 598                                         ea[numEa]->en_cols.en_cols_len *
 599                                 sizeof (ea[numEa]->en_cols.en_cols_val[0]));
 600                         }
 601                         if (ea[numEa] == 0 ||
 602                                         ea[numEa]->en_cols.en_cols_val == 0) {
 603                                 int     i;
 604                                 for (i = 0; i < numEa; i++) {
 605                                         sfree(ea[i]->en_cols.en_cols_val);
 606                                         sfree(ea[i]);
 607                                 }
 608                                 sfree(ea);
 609                                 xdr_free(xdr_xdr_nis_object_t, (char *)xno);
 610                                 sfree(xno);
 611                                 return (0);
 612                         }
 613                         /* Leave column 0 (XDR:ed object) empty */
 614                         ea[numEa]->en_cols.en_cols_val[0].
 615                                 ec_value.ec_value_len = 0;
 616                         ea[numEa]->en_cols.en_cols_val[0].
 617                                 ec_value.ec_value_val = 0;
 618                         /*
 619                          * Fill in name of dir entry. The DB counts the NUL
 620                          * as part of the dir entry name; hence, add one
 621                          * to the string length.
 622                          */
 623                         ea[numEa]->en_cols.en_cols_val[1].
 624                                 ec_value.ec_value_len = slen(xno->dirEntry.
 625                                         dirEntry_val[numEa]) + 1;
 626                         ea[numEa]->en_cols.en_cols_val[1].
 627                                 ec_value.ec_value_val =
 628                                         xno->dirEntry.dirEntry_val[numEa];
 629                 }
 630                 *eaP = ea;
 631                 *numEaP = numEa;
 632                 /*
 633                  * The xno->dirEntry.dirEntry_val[] pointers are duplicated
 634                  * in 'ea'. Set the xno pointers to zero, so that the xdr_free
 635                  * doesn't free the 'ea' data.
 636                  */
 637                 if (numEa > 0) {
 638                         int     i;
 639                         for (i = 0; i < numEa; i++) {
 640                                 xno->dirEntry.dirEntry_val[i] = 0;
 641                         }
 642                 }
 643         } else {
 644                 if (eaP != 0)
 645                         *eaP = 0;
 646                 if (numEaP != 0)
 647                         *numEaP = 0;
 648         }
 649 
 650         o = xno->obj;
 651         xno->obj = 0;
 652         xdr_free(xdr_xdr_nis_object_t, (char *)xno);
 653         sfree(xno);
 654 
 655         return (o);
 656 }
 657 
 658 void
 659 freeEntryObjArray(entry_obj **ea, int numEa) {
 660         int     i;
 661 
 662         if (ea == 0)
 663                 return;
 664 
 665         for (i = 0; i < numEa; i++) {
 666                 int     j;
 667 
 668                 for (j = 0; j < ea[i]->en_cols.en_cols_len; j++) {
 669                         sfree(ea[i]->en_cols.en_cols_val[j].
 670                                 ec_value.ec_value_val);
 671                 }
 672 
 673                 sfree(ea[i]->en_cols.en_cols_val);
 674         }
 675 
 676         sfree(ea);
 677 }
 678 
 679 /*
 680  * Return TRUE if 'o1' and 'o2' are the same, FALSE otherwise.
 681  * We perform the comparison by XDR encoding the objects, and then
 682  * checking the XDR buffers for equality. However, we don't want to
 683  * include the zo_oid (i.e., ctime and mtime) in the comparison.
 684  */
 685 bool_t
 686 sameNisPlusObj(nis_object *o1, nis_object *o2) {
 687         XDR             x1, x2;
 688         void            *b1, *b2;
 689         int             l1, l2;
 690         bool_t          ret;
 691         nis_object      obj1, obj2;
 692         char            *myself = "sameNisPlusObj";
 693 
 694         if (o1 == o2)
 695                 return (TRUE);
 696         else if (o1 == 0 || o2 == 0)
 697                 return (FALSE);
 698 
 699         /*
 700          * We want to exclude the zo_oid from the comparison. In order
 701          * not to modify the objects (even very briefly), we do this by
 702          * making copies (nis_object itself only, not the underlying
 703          * structures accessed through pointers), and setting the zo_oid
 704          * to zero in the copies.
 705          */
 706         obj1 = *o1;
 707         obj2 = *o2;
 708         obj1.zo_oid.ctime = obj1.zo_oid.mtime = 0;
 709         obj2.zo_oid.ctime = obj2.zo_oid.mtime = 0;
 710 
 711         l1 = xdr_sizeof(xdr_nis_object, &obj1);
 712         l2 = xdr_sizeof(xdr_nis_object, &obj2);
 713         if (l1 != l2)
 714                 return (FALSE);
 715 
 716         b1 = am(myself, l1);
 717         b2 = am(myself, l2);
 718         if (b1 == 0 || b2 == 0) {
 719                 sfree(b1);
 720                 sfree(b2);
 721                 return (FALSE);
 722         }
 723 
 724         xdrmem_create(&x1, (char *)b1, l1, XDR_ENCODE);
 725         xdrmem_create(&x2, (char *)b2, l2, XDR_ENCODE);
 726 
 727         if (xdr_nis_object(&x1, &obj1) && xdr_nis_object(&x2, &obj2)) {
 728                 ret = (memcmp(b1, b2, l1) == 0);
 729         } else {
 730                 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
 731                         "%s: xdr_nis_object() error",
 732                         myself);
 733                 ret = FALSE;
 734         }
 735 
 736         sfree(b1);
 737         sfree(b2);
 738 
 739         return (ret);
 740 }
 741 
 742 /*
 743  * A wrapper/convenience function for sameNisPlusObj() that extracts
 744  * the object in column zero of 'e2'.
 745  */
 746 bool_t
 747 sameNisPlusPseudoObj(nis_object *o1, entry_obj *e2) {
 748         nis_object      *o2;
 749         bool_t          res;
 750 
 751         if (o1 == 0 && e2 == 0)
 752                 return (TRUE);
 753         else if (e2 == 0)
 754                 return (FALSE);
 755 
 756         o2 = unmakePseudoEntryObj(e2, 0);
 757         if (o2 == 0)
 758                 return ((o1 == 0) ? TRUE : FALSE);
 759 
 760         res = sameNisPlusObj(o1, o2);
 761 
 762         nis_destroy_object(o2);
 763 
 764         return (res);
 765 }