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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <lber.h>
  28 #include <ldap.h>
  29 #include <strings.h>
  30 #include <errno.h>
  31 
  32 #include "nisdb_mt.h"
  33 
  34 #include "ldap_util.h"
  35 #include "ldap_op.h"
  36 #include "ldap_ruleval.h"
  37 #include "ldap_attr.h"
  38 #include "ldap_val.h"
  39 #include "ldap_ldap.h"
  40 
  41 extern int yp2ldap;
  42 
  43 
  44 __nis_mapping_format_t *
  45 cloneMappingFormat(__nis_mapping_format_t *m) {
  46         __nis_mapping_format_t  *new;
  47         int                     i, nf, err;
  48         char                    *myself = "cloneMappingFormat";
  49 
  50         if (m == 0)
  51                 return (0);
  52 
  53         for (nf = 0; m[nf].type != mmt_end; nf++);
  54         nf++;
  55 
  56         new = am(myself, nf * sizeof (new[0]));
  57         if (new == 0)
  58                 return (0);
  59 
  60         /* Copy the whole array */
  61         memcpy(new, m, nf * sizeof (new[0]));
  62 
  63         /* Make copies of allocated stuff */
  64         for (i = 0, err = 0; i < nf; i++) {
  65                 switch (m[i].type) {
  66                 case mmt_string:
  67                         new[i].match.string = sdup(myself, T,
  68                                                         m[i].match.string);
  69                         if (new[i].match.string == 0 && m[i].match.string != 0)
  70                                 err++;
  71                         break;
  72                 case mmt_single:
  73                         new[i].match.single.lo =
  74                                 am(myself, m[i].match.single.numRange *
  75                                         sizeof (new[i].match.single.lo[0]));
  76                         new[i].match.single.hi =
  77                                 am(myself, m[i].match.single.numRange *
  78                                         sizeof (new[i].match.single.hi[0]));
  79                         if (new[i].match.single.lo != 0)
  80                                 memcpy(new[i].match.single.lo,
  81                                         m[i].match.single.lo,
  82                                         m[i].match.single.numRange);
  83                         else if (m[i].match.single.lo != 0)
  84                                 err++;
  85                         if (new[i].match.single.hi != 0)
  86                                 memcpy(new[i].match.single.hi,
  87                                         m[i].match.single.hi,
  88                                         m[i].match.single.numRange);
  89                         else if (m[i].match.single.hi != 0)
  90                                 err++;
  91                         break;
  92                 case mmt_berstring:
  93                         new[i].match.berString = sdup(myself, T,
  94                                                         m[i].match.berString);
  95                         if (new[i].match.berString == 0 &&
  96                                         m[i].match.berString != 0)
  97                                 err++;
  98                         break;
  99                 case mmt_item:
 100                 case mmt_limit:
 101                 case mmt_any:
 102                 case mmt_begin:
 103                 case mmt_end:
 104                 default:
 105                         break;
 106                 }
 107         }
 108 
 109         /* If there were memory allocation errors, free the copy */
 110         if (err > 0) {
 111                 freeMappingFormat(new);
 112                 new = 0;
 113         }
 114 
 115         return (new);
 116 }
 117 
 118 void
 119 freeMappingFormat(__nis_mapping_format_t *m) {
 120         int     i;
 121 
 122         if (m == 0)
 123                 return;
 124 
 125         for (i = 0; m[i].type != mmt_end; i++) {
 126                 switch (m[i].type) {
 127                 case mmt_string:
 128                         sfree(m[i].match.string);
 129                         break;
 130                 case mmt_single:
 131                         sfree(m[i].match.single.lo);
 132                         sfree(m[i].match.single.hi);
 133                         break;
 134                 case mmt_berstring:
 135                         sfree(m[i].match.berString);
 136                         break;
 137                 case mmt_item:
 138                 case mmt_limit:
 139                 case mmt_any:
 140                 case mmt_begin:
 141                 case mmt_end:
 142                 default:
 143                         break;
 144                 }
 145         }
 146 
 147         free(m);
 148 }
 149 
 150 
 151 void
 152 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) {
 153         int     i;
 154         char    *myself = "copyIndex";
 155 
 156         if (old == 0 || new == 0) {
 157                 *err = EINVAL;
 158                 return;
 159         }
 160 
 161         for (i = 0; i < old->numIndexes; i++) {
 162                 new->name[i] = sdup(myself, T, old->name[i]);
 163                 if (new->name[i] == 0 && old->name[i] != 0) {
 164                         *err = ENOMEM;
 165                         return;
 166                 }
 167                 new->value[i] = cloneMappingFormat(old->value[i]);
 168                 if (new->value[i] == 0 && old->value[i] != 0) {
 169                         *err = ENOMEM;
 170                         return;
 171                 }
 172         }
 173 
 174         new->numIndexes = old->numIndexes;
 175 }
 176 
 177 __nis_index_t *
 178 cloneIndex(__nis_index_t *old) {
 179         char            *myself = "cloneIndex";
 180         int             err = 0;
 181         __nis_index_t   *new = am(myself, sizeof (*new));
 182 
 183         if (old == 0)
 184                 return (0);
 185 
 186         if (new != 0) {
 187                 copyIndex(old, new, &err);
 188                 if (err != 0) {
 189                         freeIndex(new, 1);
 190                         new = 0;
 191                 }
 192         }
 193 
 194         return (new);
 195 }
 196 
 197 void
 198 freeIndex(__nis_index_t *old, bool_t doFree) {
 199         int     i;
 200 
 201         if (old == 0)
 202                 return;
 203 
 204         for (i = 0; i < old->numIndexes; i++) {
 205                 sfree(old->name[i]);
 206                 freeMappingFormat(old->value[i]);
 207         }
 208 
 209         if (doFree)
 210                 free(old);
 211 }
 212 
 213 char **
 214 cloneName(char **name, int numNames) {
 215         char    **new;
 216         int     i;
 217         char    *myself = "cloneName";
 218 
 219         if (name == 0 || numNames <= 0)
 220                 return (0);
 221 
 222         new = am(myself, numNames * sizeof (new[0]));
 223         if (new == 0)
 224                 return (0);
 225 
 226         for (i = 0; i < numNames; i++) {
 227                 if (name[i] != 0) {
 228                         new[i] = sdup(myself, T, name[i]);
 229                         if (new[i] == 0) {
 230                                 for (i--; i >= 0; i--) {
 231                                         sfree(new[i]);
 232                                 }
 233                                 sfree(new);
 234                                 return (0);
 235                         }
 236                 } else {
 237                         new[i] = 0;
 238                 }
 239         }
 240 
 241         return (new);
 242 }
 243 
 244 void
 245 freeValue(__nis_value_t *val, int count) {
 246         int     c, i;
 247 
 248         if (val == 0)
 249                 return;
 250 
 251         for (c = 0; c < count; c++) {
 252                 if (val[c].val != 0) {
 253                         for (i = 0; i < val[c].numVals; i++) {
 254                                 sfree(val[c].val[i].value);
 255                         }
 256                         free(val[c].val);
 257                 }
 258         }
 259 
 260         free(val);
 261 }
 262 
 263 __nis_value_t *
 264 cloneValue(__nis_value_t *val, int count) {
 265         __nis_value_t   *n;
 266         int             c, i;
 267         char            *myself = "cloneValue";
 268 
 269         if (count <= 0 || val == 0)
 270                 return (0);
 271 
 272         n = am(myself, count * sizeof (*n));
 273         if (n == 0)
 274                 return (0);
 275 
 276         for (c = 0; c < count; c++) {
 277                 n[c].type = val[c].type;
 278                 n[c].repeat = val[c].repeat;
 279                 n[c].numVals = val[c].numVals;
 280                 if (n[c].numVals > 0) {
 281                         n[c].val = am(myself, n[c].numVals *
 282                                                 sizeof (n[c].val[0]));
 283                         if (n[c].val == 0) {
 284                                 freeValue(n, c);
 285                                 return (0);
 286                         }
 287                 } else {
 288                         n[c].val = 0;
 289                 }
 290                 for (i = 0; i < n[c].numVals; i++) {
 291                         int     amlen = val[c].val[i].length;
 292 
 293                         /*
 294                          * The functions that create string values try to
 295                          * make sure that there's a NUL at the end. However,
 296                          * both NIS+ and LDAP have a tendency to store strings
 297                          * without a NUL, so the value length may not include
 298                          * the NUL (even though it's there). In order to
 299                          * preserve that NUL, we add a byte to the length if
 300                          * the type is vt_string, and there isn't already a
 301                          * NUL at the end. The memory allocation function
 302                          * (am()) will take care of actually putting the NUL
 303                          * in place, since it allocates zero-initialized
 304                          * memory.
 305                          */
 306                         n[c].val[i].length = val[c].val[i].length;
 307                         if (n[c].type == vt_string && amlen > 0 &&
 308                                 ((char *)val[c].val[i].value)[amlen-1] !=
 309                                         '\0') {
 310                                 amlen++;
 311                         }
 312                         n[c].val[i].value = am(myself, amlen);
 313                         if (amlen > 0 && n[c].val[i].value == 0) {
 314                                 freeValue(n, c);
 315                                 return (0);
 316                         }
 317                         memcpy(n[c].val[i].value, val[c].val[i].value,
 318                                 n[c].val[i].length);
 319                 }
 320         }
 321 
 322         return (n);
 323 }
 324 
 325 /* Define LBER_USE_DER per ber_decode(3LDAP) */
 326 #ifndef LBER_USE_DER
 327 #define LBER_USE_DER    0x01
 328 #endif  /* LBER_USE_DER */
 329 
 330 /*
 331  * Return a copy of 'valIn' where each value has been replaced by the
 332  * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged.
 333  */
 334 __nis_value_t *
 335 berEncode(__nis_value_t *valIn, char *berstring) {
 336         char            *myself = "berEncode";
 337         __nis_value_t   *val;
 338         int             i;
 339 
 340         if (valIn == 0 || berstring == 0)
 341                 return (0);
 342 
 343         val = cloneValue(valIn, 1);
 344         if (val == 0)
 345                 return (0);
 346 
 347         for (i = 0; i < val->numVals; i++) {
 348                 BerElement      *ber = ber_alloc();
 349                 struct berval   *bv = 0;
 350                 int             ret;
 351 
 352                 if (ber == 0) {
 353                         logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL",
 354                                 myself);
 355                         freeValue(val, 1);
 356                         return (0);
 357                 }
 358 
 359                 if ((strcmp("b", berstring) == 0 ||
 360                                 strcmp("i", berstring) == 0)) {
 361                         if (val->val[i].length >= sizeof (int)) {
 362                                 ret = ber_printf(ber, berstring,
 363                                         *((int *)(val->val[i].value)));
 364                         } else {
 365                                 ret = -1;
 366                         }
 367                 } else if (strcmp("B", berstring) == 0) {
 368                         ret = ber_printf(ber, berstring,
 369                                 val->val[i].value,
 370                                 val->val[i].length * 8);
 371                 } else if (strcmp("n", berstring) == 0) {
 372                         ret = ber_printf(ber, berstring);
 373                 } else if (strcmp("o", berstring) == 0) {
 374                         ret = ber_printf(ber, berstring,
 375                                 val->val[i].value, val->val[i].length);
 376                 } else if (strcmp("s", berstring) == 0) {
 377                         char    *str = am(myself, val->val[i].length + 1);
 378 
 379                         if (str != 0) {
 380                                 ret = ber_printf(ber, berstring, str);
 381                                 free(str);
 382                         } else {
 383                                 ret = -1;
 384                         }
 385                 } else {
 386                         ret = -1;
 387                 }
 388 
 389                 if (ret == -1) {
 390                         reportError(NPL_BERENCODE, "%s: BER encoding error",
 391                                         myself);
 392                         ber_free(ber, 1);
 393                         freeValue(val, 1);
 394                         return (0);
 395                 }
 396 
 397                 if (ber_flatten(ber, &bv) != 0 || bv == 0) {
 398                         reportError(NPL_BERENCODE, "%s: ber_flatten() error",
 399                                         myself);
 400                         ber_free(ber, 1);
 401                         freeValue(val, 1);
 402                         return (0);
 403                 }
 404 
 405                 sfree(val->val[i].value);
 406                 val->val[i].length = bv->bv_len;
 407                 val->val[i].value = bv->bv_val;
 408 
 409                 ber_free(ber, 1);
 410         }
 411 
 412         val->type = vt_ber;
 413 
 414         return (val);
 415 }
 416 
 417 __nis_value_t *
 418 berDecode(__nis_value_t *valIn, char *berstring) {
 419         __nis_value_t   *val;
 420         int             i;
 421         char            *myself = "berDecode";
 422 
 423         if (valIn == 0 || berstring == 0)
 424                 return (0);
 425 
 426         val = cloneValue(valIn, 1);
 427         if (val == 0)
 428                 return (0);
 429 
 430         for (i = 0; i < val->numVals; i++) {
 431                 void            *v = 0;
 432                 int             ret, len = 0;
 433                 struct berval   bv;
 434                 BerElement      *ber;
 435 
 436                 if (val->val[i].value == 0 || val->val[i].length <= 0)
 437                         continue;
 438 
 439                 bv.bv_val = val->val[i].value;
 440                 bv.bv_len = val->val[i].length;
 441                 ber = ber_init(&bv);
 442                 if (ber == 0) {
 443                         reportError(NPL_BERDECODE, "%s: ber_init() error",
 444                                 myself);
 445                         freeValue(val, 1);
 446                         return (0);
 447                 }
 448 
 449                 if ((strcmp("b", berstring) == 0 ||
 450                                 strcmp("i", berstring) == 0)) {
 451                         len = sizeof (int);
 452                         v = am(myself, len);
 453                         if (v != 0) {
 454                                 ret = ber_scanf(ber, berstring, v);
 455                         } else {
 456                                 ret = -1;
 457                         }
 458                 } else if (strcmp("B", berstring) == 0) {
 459                         long    llen;
 460 
 461                         ret = ber_scanf(ber, berstring, &v, &llen);
 462                         if (ret != -1) {
 463                                 len = llen/8;
 464                         }
 465                 } else if (strcmp("n", berstring) == 0) {
 466                         ret = 0;
 467                 } else if (strcmp("o", berstring) == 0) {
 468                         struct berval   *bv = am(myself, sizeof (*bv));
 469 
 470                         if (bv != 0) {
 471                                 ret = ber_scanf(ber, "O", &bv);
 472                                 if (ret != -1 && bv != 0) {
 473                                         v = bv->bv_val;
 474                                         len = bv->bv_len;
 475                                 } else {
 476                                         ret = -1;
 477                                 }
 478                                 /* Only free 'bv' itself */
 479                                 free(bv);
 480                         } else {
 481                                 ret = -1;
 482                         }
 483                 } else if (strcmp("s", berstring) == 0) {
 484                         ret = ber_scanf(ber, "a", &v);
 485                         if (ret != -1) {
 486                                 len = slen(v);
 487                         }
 488                 } else {
 489                         ret = -1;
 490                 }
 491 
 492                 if (ret == -1) {
 493                         reportError(NPL_BERDECODE, "%s: BER decoding error",
 494                                         myself);
 495                         freeValue(val, 1);
 496                         return (0);
 497                 }
 498 
 499                 /* Free the old value, and replace it with the decoded one */
 500                 sfree(val->val[i].value);
 501                 val->val[i].value = v;
 502                 val->val[i].length = len;
 503         }
 504 
 505         return (val);
 506 }
 507 
 508 /*
 509  * Return the value of the specified item.
 510  */
 511 __nis_value_t *
 512 getMappingItemVal(__nis_mapping_item_t *item, __nis_mapping_item_type_t native,
 513                 __nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
 514         __nis_value_t                           *val = 0, *nameVal, *exVal = 0;
 515         int                                     numName, caseInsens, cmp;
 516         int                                     i, j, k;
 517         char                                    **name;
 518         enum {rvOnly, rvThenLookup, lookupOnly} check;
 519         unsigned char                           fromldap = '\0';
 520 
 521         if (item == 0)
 522                 return (0);
 523 
 524         /*
 525          * First, we decide if we should look for the value in 'rv',
 526          * directly from NIS+/LDAP, or both.
 527          */
 528         switch (item->type) {
 529         case mit_nisplus:
 530                 /* Do we have a valid index/object spec ? */
 531                 if (item->searchSpec.obj.index.numIndexes <= 0 &&
 532                                 item->searchSpec.obj.name == 0) {
 533                         /*
 534                          * No valid index/object. If we have a rule-value,
 535                          * use it. Otherwise, return error.
 536                          */
 537                         if (rv != 0) {
 538                                 name = rv->colName;
 539                                 nameVal = rv->colVal;
 540                                 numName = rv->numColumns;
 541                                 caseInsens = 0;
 542                                 check = rvOnly;
 543                         } else {
 544                                 return (0);
 545                         }
 546                 } else {
 547                         /*
 548                          * Valid index, so skip the rule-value and do
 549                          * a direct NIS+ lookup.
 550                          */
 551                         check = lookupOnly;
 552                 }
 553                 break;
 554         case mit_ldap:
 555                 if (rv != 0) {
 556                         name = rv->attrName;
 557                         nameVal = rv->attrVal;
 558                         numName = rv->numAttrs;
 559                         caseInsens = 1;
 560                         fromldap = '1';
 561                 }
 562                 /* Do we have a valid triple ? */
 563                 if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) {
 564                         /*
 565                          * No valid triple. If we have a rule-value, use it.
 566                          * Otherwise, return error.
 567                          */
 568                         if (rv != 0) {
 569                                 check = rvOnly;
 570                         } else {
 571                                 return (0);
 572                         }
 573                 } else if (item->searchSpec.triple.base == 0 &&
 574                                 item->searchSpec.triple.scope ==
 575                                         LDAP_SCOPE_ONELEVEL &&
 576                                 item->searchSpec.triple.attrs == 0 &&
 577                                 item->searchSpec.triple.element == 0) {
 578                         /*
 579                          * We have a valid triple, but it points to the
 580                          * current LDAP container. Thus, first look in
 581                          * the rule-value; if that fails, perform a direct
 582                          * LDAP lookup.
 583                          */
 584                         if (rv != 0) {
 585                                 check = rvThenLookup;
 586                         } else {
 587                                 check = lookupOnly;
 588                         }
 589                 } else {
 590                         /*
 591                          * Valid triple, and it's not the current container
 592                          * (at least not in the trivial sense). Hence, do
 593                          * a direct LDAP lookup.
 594                          */
 595                         check = lookupOnly;
 596                 }
 597                 break;
 598         default:
 599                 return (0);
 600         }
 601 
 602         /* Check the rule-value */
 603         if (check == rvOnly || check == rvThenLookup) {
 604                 for (i = 0; i < numName; i++) {
 605                         if (caseInsens)
 606                                 cmp = strcasecmp(item->name, name[i]);
 607                         else
 608                                 cmp = strcmp(item->name, name[i]);
 609                         if (cmp == 0) {
 610                                 if (nameVal[i].numVals <= 0)
 611                                         break;
 612                                 if (berstring == 0) {
 613                                         val = cloneValue(&nameVal[i], 1);
 614                                 } else if (yp2ldap && berstring[0] == 'a') {
 615                                         val = cloneValue(&nameVal[i], 1);
 616                                 } else {
 617                                         val = berDecode(&nameVal[i],
 618                                                 berstring);
 619                                 }
 620                                 if (val != 0) {
 621                                         val->repeat = item->repeat;
 622                                         /*
 623                                          * If value for nis+ column is
 624                                          * passed with value, val is
 625                                          * manipulated in cloneValue().
 626                                          * To decide whether there are
 627                                          * enough nis+ column values
 628                                          * for rule to produce a value,
 629                                          * we need nis+ column values
 630                                          * as well as nis_mapping_element
 631                                          * from the rule. If we are here,
 632                                          * it indicates that the 'val has
 633                                          * an valid value for the column
 634                                          * item-> name. So set
 635                                          * NP_LDAP_MAP_SUCCESS
 636                                          * to np_ldap-stat.
 637                                          */
 638 
 639                                         if (np_ldap_stat != NULL)
 640                                                 *np_ldap_stat =
 641                                                         NP_LDAP_MAP_SUCCESS;
 642                                 }
 643                                 break;
 644                         }
 645                 }
 646         }
 647 
 648         /* Do a direct lookup ? */
 649         if (val == 0 && (check == rvThenLookup || check == lookupOnly)) {
 650                 if (item->type == mit_ldap) {
 651                         int     err = 0;
 652                         __nis_search_triple_t   triple;
 653                         char                    *baseDN;
 654 
 655                         /*
 656                          * If item->searchSpec.triple.base is NULL, or ends
 657                          * in a comma, append the current search base from
 658                          * the TSD (put there by an upper layer).
 659                          *
 660                          * Special case for N2L mode:
 661                          * if item->searchSpec.triple.base ends in a comma,
 662                          * the current domain Context is used.
 663                          */
 664                         if (yp2ldap && item->searchSpec.triple.base &&
 665                                 strlen(item->searchSpec.triple.base) > 0) {
 666                                 baseDN = __nisdb_get_tsd()->domainContext;
 667                         } else {
 668                                 baseDN = __nisdb_get_tsd()->searchBase;
 669                         }
 670                         triple.base = appendBase(item->searchSpec.triple.base,
 671                                 baseDN, &err, 0);
 672                         if (err == 0) {
 673                                 triple.scope = item->searchSpec.triple.scope;
 674                                 triple.attrs = item->searchSpec.triple.attrs;
 675                                 triple.element =
 676                                         item->searchSpec.triple.element;
 677                                 val = lookupLDAP(&triple, item->name, rv, 0,
 678                                         np_ldap_stat);
 679                                 fromldap = '1';
 680                         } else {
 681                                 val = 0;
 682                         }
 683                         sfree(triple.base);
 684                 }
 685         }
 686 
 687 
 688         /* Special processing for NIS to LDAP mode */
 689         if (yp2ldap && val != 0) {
 690 
 691                 /*
 692                  * Escape special chars from dn before sending to DIT,
 693                  * provided val is not ldap-based
 694                  */
 695                 if (fromldap == '\0' && __nisdb_get_tsd()->escapeFlag == '1') {
 696                         if (escapeSpecialChars(val) < 0) {
 697                                 freeValue(val, 1);
 698                                 return (0);
 699                         }
 700                 } else if (__nisdb_get_tsd()->escapeFlag == '2') {
 701                         /* Remove escape chars from data received from DIT */
 702                         (void) removeEscapeChars(val);
 703                 }
 704 
 705                 /*
 706                  * Remove from 'val', any values obtained using
 707                  * the 'removespec' syntax
 708                  */
 709 
 710                 /* Obtain exVal */
 711                 if (item->exItem)
 712                         exVal = getMappingItemVal(item->exItem, native, rv,
 713                             berstring, NULL);
 714 
 715                 /* delete */
 716                 if (exVal != 0) {
 717                         for (i = 0; i < val->numVals; ) {
 718                                 for (j = 0; j < exVal->numVals; j++) {
 719                                         if (sstrncmp(val->val[i].value,
 720                                                         exVal->val[j].value,
 721                                                         MAX(val->val[i].length,
 722                                                         exVal->val[j].length))
 723                                                         == 0)
 724                                                 break;
 725                                 }
 726                                 if (j < exVal->numVals) {
 727                                         sfree(val->val[i].value);
 728                                         val->val[i].value = 0;
 729                                         val->val[i].length = 0;
 730                                         for (k = i; k < val->numVals - 1; k++) {
 731                                                 val->val[k] = val->val[k + 1];
 732                                                 val->val[k + 1].value = 0;
 733                                                 val->val[k + 1].length = 0;
 734                                         }
 735                                         val->numVals--;
 736                                 } else
 737                                         i++;
 738                         }
 739 
 740                         freeValue(exVal, 1);
 741 
 742                         /*
 743                          * If val->numVals <= 0, then we have no val to
 744                          * return. So free up stuff.
 745                          */
 746                         if (val->numVals <= 0) {
 747                                 free(val->val);
 748                                 val->val = 0;
 749                                 free(val);
 750                                 return (0);
 751                         }
 752                 }
 753         }
 754 
 755         return (val);
 756 }
 757 
 758 __nis_value_t *
 759 getMappingFormat(__nis_mapping_format_t *f, __nis_rule_value_t *rv,
 760                         __nis_format_arg_t at, void *a, int *numArg) {
 761         char            *myself = "getMappingFormat";
 762         __nis_value_t   *val = 0;
 763         __nis_buffer_t  b = {0, 0};
 764         int             i;
 765 
 766         if (f == 0)
 767                 return (0);
 768 
 769         if (rv == 0) {
 770                 val = am(myself, sizeof (*val));
 771                 if (val == 0)
 772                         return (0);
 773 
 774                 switch (f->type) {
 775                 case mmt_item:
 776                         bp2buf(myself, &b, "%%s");
 777                         break;
 778                 case mmt_string:
 779                         bp2buf(myself, &b, "%s", NIL(f->match.string));
 780                         break;
 781                 case mmt_single:
 782                         bp2buf(myself, &b, "[");
 783                         for (i = 0; i < f->match.single.numRange; i++) {
 784                                 if (f->match.single.lo[i] ==
 785                                                 f->match.single.hi[i])
 786                                         bp2buf(myself, &b, "%c",
 787                                                 f->match.single.lo[i]);
 788                                 else
 789                                         bp2buf(myself, &b, "%c-%c",
 790                                                 f->match.single.lo[i],
 791                                                 f->match.single.hi[i]);
 792                         }
 793                         bp2buf(myself, &b, "]");
 794                         break;
 795                 case mmt_limit:
 796                         break;
 797                 case mmt_any:
 798                         bp2buf(myself, &b, "*");
 799                         break;
 800                 case mmt_berstring:
 801                         bp2buf(myself, &b, "%s", NIL(f->match.berString));
 802                         break;
 803                 case mmt_begin:
 804                 case mmt_end:
 805                         bp2buf(myself, &b, "\"");
 806                         break;
 807                 default:
 808                         bp2buf(myself, &b, "<unknown>");
 809                 }
 810                 val->type = vt_string;
 811                 val->numVals = 1;
 812                 val->val = am(myself, sizeof (val->val[0]));
 813                 if (val->val == 0) {
 814                         sfree(val);
 815                         return (0);
 816                 }
 817                 val->val[0].value = b.buf;
 818                 val->val[0].length = b.len;
 819         } else {
 820                 switch (f->type) {
 821                 case mmt_item:
 822                 case mmt_berstring:
 823                         if (a != 0) {
 824                                 if (at == fa_item) {
 825                                         val = getMappingItemVal(
 826                                                 (__nis_mapping_item_t *)a,
 827                                                 mit_any, rv,
 828                 (f->type == mmt_berstring) ? f->match.berString : 0, NULL);
 829                                         if (numArg != 0)
 830                                                 (*numArg)++;
 831                                 } else {
 832                                         val = cloneValue(
 833                                                 (__nis_value_t *)a, 1);
 834                                         if (numArg != 0)
 835                                                 (*numArg)++;
 836                                 }
 837                         }
 838                         break;
 839                 case mmt_string:
 840                         val = am(myself, sizeof (*val));
 841                         if (val == 0)
 842                                 return (0);
 843                         val->type = vt_string;
 844                         val->numVals = 1;
 845                         val->val = am(myself, sizeof (val->val[0]));
 846                         if (val->val == 0) {
 847                                 sfree(val);
 848                                 return (0);
 849                         }
 850                         val->val[0].value = sdup(myself, T, f->match.string);
 851                         val->val[0].length = strlen(val->val[0].value);
 852                         break;
 853                 case mmt_single:
 854                 case mmt_limit:
 855                 case mmt_any:
 856                 case mmt_begin:
 857                 case mmt_end:
 858                         /* Not an error, so return an empty value */
 859                         val = am(myself, sizeof (*val));
 860                         if (val == 0)
 861                                 return (0);
 862                         val->type = vt_string;
 863                         val->numVals = 0;
 864                         val->val = 0;
 865                         break;
 866                 default:
 867                         /* Do nothing */
 868                         val = 0;
 869                         break;
 870                 }
 871         }
 872         return (val);
 873 }
 874 
 875 /*
 876  * Used when evaluating an expression. Typically, the value of the
 877  * expression so far will be kept in 'v1', and 'v2' is the value
 878  * of the current component of the expression. In the general case,
 879  * both will be multi-valued, and the result is an "explosion"
 880  * resulting in N*M new values (if 'v1' had N values, and 'v2'
 881  * M ditto).
 882  *
 883  * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"},
 884  * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl",
 885  * "efgh", "efij", "efkl"}.
 886  *
 887  * There are special cases when v1->repeat and/or v2->repeat are set.
 888  * Repeat mostly makes sense with single values; for example, if
 889  * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result
 890  * is {"x=1", "x=2", "x=3"}.
 891  *
 892  * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's
 893  * not clear if there's a useful application for this, but the code's
 894  * there for the sake of orthogonality.
 895  */
 896 __nis_value_t *
 897 explodeValues(__nis_value_t *v1, __nis_value_t *v2) {
 898         int             i1, i2, n, nv;
 899         __nis_value_t   *v;
 900         __nis_buffer_t  b = {0, 0};
 901         char            *myself = "explodeValues";
 902 
 903         if (v1 == 0 || v1->numVals <= 0)
 904                 return (cloneValue(v2, 1));
 905         if (v2 == 0 || v2->numVals <= 0)
 906                 return (cloneValue(v1, 1));
 907 
 908         /*
 909          * XXX What should we do if (v1->type != v2->type) ?
 910          * Policy: Just explode anyway, even though the result is
 911          * unlikely to be very useful.
 912          */
 913 
 914         v = am(myself, sizeof (*v));
 915         if (v == 0)
 916                 return (0);
 917 
 918         if (!v1->repeat && !v2->repeat)
 919                 nv = v1->numVals * v2->numVals;
 920         else if (v1->repeat && !v2->repeat)
 921                 nv = v2->numVals;
 922         else if (!v1->repeat && v2->repeat)
 923                 nv = v1->numVals;
 924         else /* v1->repeat && v2->repeat */
 925                 nv = 1;
 926 
 927         v->val = am(myself, nv * sizeof (v->val[0]));
 928         if (v->val == 0) {
 929                 free(v);
 930                 return (0);
 931         }
 932 
 933         /*
 934          * Four different cases, depending on the 'repeat' flags.
 935          */
 936         if (!v1->repeat && !v2->repeat) {
 937                 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
 938                         for (i2 = 0; i2 < v2->numVals; i2++) {
 939                                 if (v1->type == vt_string)
 940                                         sbc2buf(myself, v1->val[i1].value,
 941                                                 v1->val[i1].length,
 942                                                 &b);
 943                                 else
 944                                         bc2buf(myself, v1->val[i1].value,
 945                                                 v1->val[i1].length,
 946                                                 &b);
 947                                 if (v2->type == vt_string)
 948                                         sbc2buf(myself, v2->val[i2].value,
 949                                                 v2->val[i2].length,
 950                                                 &b);
 951                                 else
 952                                         bc2buf(myself, v2->val[i2].value,
 953                                                 v2->val[i2].length,
 954                                                 &b);
 955                                 v->val[n].value = b.buf;
 956                                 v->val[n].length = b.len;
 957                                 n++;
 958                                 b.buf = 0;
 959                                 b.len = 0;
 960                         }
 961                 }
 962         } else if (v1->repeat && !v2->repeat) {
 963                 for (i2 = 0; i2 < v2->numVals; i2++) {
 964                         for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
 965                                 if (v1->type == vt_string)
 966                                         sbc2buf(myself, v1->val[i1].value,
 967                                                 v1->val[i1].length,
 968                                                 &b);
 969                                 else
 970                                         bc2buf(myself, v1->val[i1].value,
 971                                                 v1->val[i1].length,
 972                                                 &b);
 973                                 if (v2->type == vt_string)
 974                                         sbc2buf(myself, v2->val[i2].value,
 975                                                 v2->val[i2].length,
 976                                                 &b);
 977                                 else
 978                                         bc2buf(myself, v2->val[i2].value,
 979                                                 v2->val[i2].length,
 980                                                 &b);
 981                         }
 982                         v->val[n].value = b.buf;
 983                         v->val[n].length = b.len;
 984                         n++;
 985                         b.buf = 0;
 986                         b.len = 0;
 987                 }
 988         } else if (!v1->repeat && v2->repeat) {
 989                 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
 990                         for (i2 = 0; i2 < v2->numVals; i2++) {
 991                                 if (v1->type == vt_string)
 992                                         sbc2buf(myself, v1->val[i1].value,
 993                                                 v1->val[i1].length,
 994                                                 &b);
 995                                 else
 996                                         bc2buf(myself, v1->val[i1].value,
 997                                                 v1->val[i1].length,
 998                                                 &b);
 999                                 if (v2->type == vt_string)
1000                                         sbc2buf(myself, v2->val[i2].value,
1001                                                 v2->val[i2].length,
1002                                                 &b);
1003                                 else
1004                                         bc2buf(myself, v2->val[i2].value,
1005                                                 v2->val[i2].length,
1006                                                 &b);
1007                         }
1008                         v->val[n].value = b.buf;
1009                         v->val[n].length = b.len;
1010                         n++;
1011                         b.buf = 0;
1012                         b.len = 0;
1013                 }
1014         } else { /* v1->repeat && v2->repeat */
1015                 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
1016                         for (i2 = 0; i2 < v2->numVals; i2++) {
1017                                 if (v1->type == vt_string)
1018                                         sbc2buf(myself, v1->val[i1].value,
1019                                                 v1->val[i1].length,
1020                                                 &b);
1021                                 else
1022                                         bc2buf(myself, v1->val[i1].value,
1023                                                 v1->val[i1].length,
1024                                                 &b);
1025                                 if (v2->type == vt_string)
1026                                         sbc2buf(myself, v2->val[i2].value,
1027                                                 v2->val[i2].length,
1028                                                 &b);
1029                                 else
1030                                         bc2buf(myself, v2->val[i2].value,
1031                                                 v2->val[i2].length,
1032                                                 &b);
1033                         }
1034                 }
1035                 v->val[n].value = b.buf;
1036                 v->val[n].length = b.len;
1037                 n++;
1038                 b.buf = 0;
1039                 b.len = 0;
1040         }
1041 
1042 #ifdef  NISDB_LDAP_DEBUG
1043         /* Sanity check */
1044         if (n != nv)
1045                 abort();
1046 #endif  /* NISD__LDAP_DEBUG */
1047 
1048         v->type = (v1->type == vt_string) ?
1049                         ((v2->type == vt_string) ?
1050                                 vt_string : vt_ber) : vt_ber;
1051         v->repeat = 0;
1052         v->numVals = n;
1053 
1054         return (v);
1055 }
1056 
1057 __nis_value_t *
1058 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv,
1059                         __nis_format_arg_t at, int numArgs, void *arg) {
1060         int                     i, ia = 0;
1061         __nis_value_t           *val, *v = 0;
1062         bool_t                  moreFormat = (a != 0);
1063         bool_t                  moreArgs = (numArgs > 0);
1064 
1065         while (moreFormat && (arg == 0 || ia < numArgs)) {
1066                 for (i = 0; moreFormat; i++) {
1067                         moreFormat = (a[i].type != mmt_end);
1068                         if (at == fa_item) {
1069                                 __nis_mapping_item_t *item = arg;
1070                                 val = getMappingFormat(&a[i], rv, at,
1071                                         ((item != 0) ? &item[ia] : 0), &ia);
1072                         } else {
1073                                 __nis_value_t **ival = arg;
1074                                 val = getMappingFormat(&a[i], rv, at,
1075                                         ((ival != 0) ? ival[ia] : 0), &ia);
1076                         }
1077                         if (val != 0) {
1078                                 __nis_value_t   *new = explodeValues(v, val);
1079 
1080                                 freeValue(v, 1);
1081                                 freeValue(val, 1);
1082                                 if (new == 0)
1083                                         return (0);
1084 
1085                                 v = new;
1086                         } else {
1087                                 freeValue(v, 1);
1088                                 return (0);
1089                         }
1090                         /*
1091                          * If we run out of arguments, but still have format
1092                          * remaining, repeat the last argument. Keep track of
1093                          * the fact that we've really consumed all arguments.
1094                          */
1095                         if (moreFormat && ia >= numArgs) {
1096                                 ia = (numArgs > 0) ? numArgs - 1 : 0;
1097                                 moreArgs = FALSE;
1098                         }
1099                 }
1100                 /*
1101                  * We've run out of format, so if we still have arguments
1102                  * left, start over on the format.
1103                  */
1104                 if (ia < numArgs && moreArgs) {
1105                         /*
1106                          * However, if we didn't consume any arguments going
1107                          * through the format once, abort to avoid an infinite
1108                          * loop.
1109                          */
1110                         if (numArgs > 0 && ia <= 0) {
1111                                 freeValue(v, 1);
1112                                 return (0);
1113                         }
1114                         moreFormat = 1;
1115                 }
1116         }
1117 
1118         return (v);
1119 }
1120 
1121 /*
1122  * Returns a string representation (such as "[name=foo, value=bar]")
1123  * of a nis_index_t.
1124  */
1125 char *
1126 getIndex(__nis_index_t *i, int *len) {
1127         int             n;
1128         __nis_buffer_t  b = {0, 0};
1129         char            *myself = "getIndex";
1130 
1131         if (i == 0)
1132                 return (0);
1133 
1134         if (i->numIndexes > 0) {
1135                 bp2buf(myself, &b, "[");
1136                 for (n = 0; n < i->numIndexes; n++) {
1137                         __nis_value_t   *val;
1138                         int             j;
1139 
1140                         val = getMappingFormatArray(i->value[n],
1141                                                 0, fa_any, 0, 0);
1142                         if (n > 0)
1143                                 bp2buf(myself, &b, ", ");
1144                         bp2buf(myself, &b, "%s=", i->name[n]);
1145                         if (val != 0) {
1146                                 for (j = 0; j < val->numVals; j++) {
1147                                         bc2buf(myself, val->val[j].value,
1148                                                 val->val[j].length, &b);
1149                                 }
1150                         } else {
1151                                 bp2buf(myself, &b, "<no-vals>");
1152                         }
1153                         freeValue(val, 1);
1154                 }
1155                 bp2buf(myself, &b, "]");
1156         }
1157         if (len != 0)
1158                 *len = b.len;
1159         return (b.buf);
1160 }
1161 
1162 char *
1163 getObjSpec(__nis_obj_spec_t *o, int *len) {
1164         __nis_buffer_t  b = {0, 0};
1165         char            *myself = "getObjSpec";
1166 
1167         if (o == 0)
1168                 return (0);
1169 
1170         b.buf = getIndex(&o->index, &b.len);
1171         sbc2buf(myself, o->name, slen(o->name), &b);
1172         if (len != 0)
1173                 *len = b.len;
1174         return (b.buf);
1175 }
1176 
1177 /*
1178  * Returns a string representation of the LDAP scope. Note that the
1179  * returned value is a static entity, and must be copied by the
1180  * caller (but, obviously, must not be freed).
1181  */
1182 char *
1183 getScope(int scope) {
1184         switch (scope) {
1185         case LDAP_SCOPE_BASE:
1186                 return ("base");
1187         case LDAP_SCOPE_ONELEVEL:
1188                 return ("one");
1189         case LDAP_SCOPE_SUBTREE:
1190                 return ("sub");
1191         default:
1192                 return ("one");
1193         }
1194 }
1195 
1196 /*
1197  * Return a string representation of an LDAP search triple (such as
1198  * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1199  */
1200 char *
1201 getSearchTriple(__nis_search_triple_t *s, int *len) {
1202         __nis_buffer_t  b = {0, 0};
1203         char            *a;
1204         int             l;
1205         char            *myself = "getSearchTriple";
1206 
1207         /* If the scope is LDAP_SCOPE_UNKNOWN, the search triple is unused */
1208         if (s == 0 || s->scope == LDAP_SCOPE_UNKNOWN) {
1209                 if (len != 0)
1210                         *len = 0;
1211                 return (0);
1212         }
1213 
1214         if (s->base != 0)
1215                 sbc2buf(myself, s->base, slen(s->base), &b);
1216         if (!(s->scope == LDAP_SCOPE_ONELEVEL &&
1217                         (s->base == 0 || s->base[0] == '\0'))) {
1218                 bp2buf(myself, &b, "?%s?", getScope(s->scope));
1219         }
1220         if ((l = slen(s->attrs)) > 0) {
1221                 /*
1222                  * Remove white space from the filter/attribute list.
1223                  * The parser usually keeps any white space from the
1224                  * config file (or LDAP/command line), but we don't
1225                  * want it.
1226                  */
1227                 a = am(myself, l+1);
1228                 if (a != 0) {
1229                         int     i, la;
1230 
1231                         for (i = 0, la = 0; i < l; i++) {
1232                                 if (s->attrs[i] != ' ' &&
1233                                                 s->attrs[i] != '\t')
1234                                         a[la++] = s->attrs[i];
1235                         }
1236                         sbc2buf(myself, a, la, &b);
1237                         sfree(a);
1238                 } else {
1239                         sbc2buf(myself, s->attrs, slen(s->attrs), &b);
1240                 }
1241         }
1242 
1243         if (len != 0)
1244                 *len = b.len;
1245         return (b.buf);
1246 }
1247 
1248 __nis_value_t *
1249 getMappingItem(__nis_mapping_item_t *i, __nis_mapping_item_type_t native,
1250                 __nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
1251         char            *myself = "getMappingItem";
1252         __nis_value_t   *val = 0;
1253         __nis_buffer_t  b = {0, 0};
1254         int             len = 0;
1255         char            *buf;
1256 
1257         if (i == 0)
1258                 return (0);
1259 
1260         if (rv != 0)
1261                 return (getMappingItemVal(i, native, rv, berstring,
1262                         np_ldap_stat));
1263 
1264         val = am(myself, sizeof (*val));
1265         if (val == 0)
1266                 return (0);
1267 
1268         switch (i->type) {
1269         case mit_nisplus:
1270                 if (native != mit_nisplus)
1271                         bp2buf(myself, &b, "nis+:");
1272                 bp2buf(myself, &b, "%s", NIL(i->name));
1273                 buf = getObjSpec(&i->searchSpec.obj, &len);
1274                 if (buf != 0 && len > 0) {
1275                         bc2buf(myself, ":", 1, &b);
1276                         sbc2buf(myself, buf, len, &b);
1277                 }
1278                 sfree(buf);
1279                 val->type = vt_string;
1280                 val->repeat = i->repeat;
1281                 val->numVals = 1;
1282                 val->val = am(myself, sizeof (val->val[0]));
1283                 if (val->val == 0) {
1284                         sfree(b.buf);
1285                         free(val);
1286                         return (0);
1287                 }
1288                 val->val[0].value = b.buf;
1289                 val->val[0].length = b.len;
1290                 break;
1291         case mit_ldap:
1292                 if (native != mit_ldap)
1293                         bp2buf(myself, &b, "ldap:");
1294                 bp2buf(myself, &b, "%s", NIL(i->name));
1295                 buf = getSearchTriple(&i->searchSpec.triple, &len);
1296                 if (buf != 0 && len > 0) {
1297                         bc2buf(myself, ":", 1, &b);
1298                         sbc2buf(myself, buf, len, &b);
1299                 }
1300                 sfree(buf);
1301                 val->type = vt_string;
1302                 val->repeat = i->repeat;
1303                 val->numVals = 1;
1304                 val->val = am(myself, sizeof (val->val[0]));
1305                 if (val->val == 0) {
1306                         sfree(b.buf);
1307                         free(val);
1308                         return (0);
1309                 }
1310                 val->val[0].value = b.buf;
1311                 val->val[0].length = b.len;
1312                 break;
1313         default:
1314                 p2buf(myself, "<unknown>:");
1315                 p2buf(myself, "%s", NIL(i->name));
1316                 break;
1317         }
1318 
1319         return (val);
1320 }
1321 
1322 void
1323 copyObjSpec(__nis_obj_spec_t *old, __nis_obj_spec_t *new, int *err) {
1324         char    *myself = "copyObjSpec";
1325 
1326         if (old == 0 || new == 0) {
1327                 *err = EINVAL;
1328                 return;
1329         }
1330 
1331         if (new->index.name == 0) {
1332                 new->index.name = am(myself, old->index.numIndexes *
1333                                                 sizeof (new->index.name[0]));
1334                 if (old->index.numIndexes > 0 && new->index.name == 0) {
1335                         *err = ENOMEM;
1336                         return;
1337                 }
1338                 new->index.value = am(myself, old->index.numIndexes *
1339                                                 sizeof (new->index.value[0]));
1340                 if (old->index.numIndexes > 0 && new->index.value == 0) {
1341                         *err = ENOMEM;
1342                         return;
1343                 }
1344         }
1345         new->name = sdup(myself, T, old->name);
1346         if (new->name == 0 && old->name != 0) {
1347                 *err = ENOMEM;
1348                 return;
1349         }
1350         copyIndex(&old->index, &new->index, err);
1351 }
1352 
1353 __nis_obj_spec_t *
1354 cloneObjSpec(__nis_obj_spec_t *old) {
1355         char                    *myself = "cloneObjSpec";
1356         int                     err = 0;
1357         __nis_obj_spec_t        *new = am(myself, sizeof (*new));
1358 
1359         if (new != 0) {
1360                 copyObjSpec(old, new, &err);
1361                 if (err != 0) {
1362                         freeObjSpec(new, 1);
1363                         new = 0;
1364                 }
1365         }
1366 
1367         return (new);
1368 }
1369 
1370 void
1371 freeObjSpec(__nis_obj_spec_t *old, bool_t doFree) {
1372 
1373         if (old == 0)
1374                 return;
1375 
1376         sfree(old->name);
1377         freeIndex(&old->index, FALSE);
1378         if (doFree)
1379                 free(old);
1380 }
1381 
1382 void
1383 copySearchTriple(__nis_search_triple_t *old, __nis_search_triple_t *new,
1384                 int *err) {
1385         char                    *myself = "copySearchTriple";
1386 
1387         *err = 0;
1388 
1389         if (old == 0 || new == 0) {
1390                 *err = EINVAL;
1391                 return;
1392         }
1393 
1394         if (old->base != NULL)
1395                 new->base = sdup(myself, T, old->base);
1396         else
1397                 new->base = NULL;
1398         if (old->attrs != NULL)
1399                 new->attrs = sdup(myself, T, old->attrs);
1400         else
1401                 new->attrs = NULL;
1402         if ((new->base == 0 && old->base != 0) ||
1403                         (new->attrs == 0 && old->attrs != 0)) {
1404                 sfree(new->base);
1405                 new->base = 0;
1406                 sfree(new->attrs);
1407                 new->attrs = 0;
1408                 *err = ENOMEM;
1409                 return;
1410         }
1411         new->scope = old->scope;
1412         /*
1413          * XXX Really should have a cloneMappingElement() function.
1414          * However, since whatever the 'element' field points to
1415          * is allocated at parse time, and never is freed or modified,
1416          * it's sufficient to copy the pointer value.
1417          */
1418         new->element = old->element;
1419 }
1420 
1421 __nis_search_triple_t *
1422 cloneSearchTriple(__nis_search_triple_t *old) {
1423         char                    *myself = "cloneSearchTriple";
1424         int                     err = 0;
1425         __nis_search_triple_t   *new = am(myself, sizeof (*new));
1426 
1427         if (new != 0) {
1428                 copySearchTriple(old, new, &err);
1429                 if (err != 0) {
1430                         freeSearchTriple(new, 1);
1431                         new = 0;
1432                 }
1433         }
1434 
1435         return (new);
1436 }
1437 
1438 void
1439 freeSearchTriple(__nis_search_triple_t *old, bool_t doFree) {
1440 
1441         if (old == 0)
1442                 return;
1443 
1444         sfree(old->base);
1445         sfree(old->attrs);
1446         /*
1447          * Since we only copied the element pointer when this structure
1448          * was created, we don't free old->element.
1449          */
1450         if (doFree)
1451                 free(old);
1452 }
1453 
1454 void
1455 copyTripleOrObj(__nis_mapping_item_type_t type,
1456                 __nis_triple_or_obj_t *old, __nis_triple_or_obj_t *new,
1457                 int *err) {
1458 
1459         *err = 0;
1460 
1461         if (old == 0 || new == 0) {
1462                 *err = EINVAL;
1463                 return;
1464         }
1465 
1466         if (type == mit_nisplus) {
1467                 copyObjSpec(&old->obj, &new->obj, err);
1468         } else if (type == mit_ldap) {
1469                 copySearchTriple(&old->triple, &new->triple, err);
1470         }
1471 }
1472 
1473 __nis_triple_or_obj_t *
1474 cloneTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old) {
1475         char                    *myself = "cloneTripleOrObj";
1476         int                     err = 0;
1477         __nis_triple_or_obj_t   *new = am(myself, sizeof (*new));
1478 
1479         if (new != 0) {
1480                 copyTripleOrObj(type, old, new, &err);
1481                 if (err != 0) {
1482                         freeTripleOrObj(type, new, 1);
1483                         new = 0;
1484                 }
1485         }
1486 
1487         return (new);
1488 }
1489 
1490 void
1491 freeTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old,
1492                 bool_t doFree) {
1493 
1494         if (old == 0)
1495                 return;
1496 
1497         if (type == mit_nisplus)
1498                 freeObjSpec(&old->obj, doFree);
1499         else if (type == mit_ldap)
1500                 freeSearchTriple(&old->triple, doFree);
1501 
1502         if (doFree)
1503                 free(old);
1504 }
1505 
1506 void
1507 copyItem(__nis_mapping_item_t *old, __nis_mapping_item_t *new, int *err) {
1508 
1509         *err = 0;
1510 
1511         if (old == 0 || new == 0) {
1512                 *err = EINVAL;
1513                 return;
1514         }
1515 
1516         new->type = old->type;
1517         new->repeat = old->repeat;
1518         if (old->name != 0) {
1519                 new->name = strdup(old->name);
1520                 if (new->name == 0) {
1521                         *err = ENOMEM;
1522                         return;
1523                 }
1524         } else {
1525                 new->name = 0;
1526         }
1527         if (old->type == mit_nisplus || old->type == mit_ldap)
1528                 copyTripleOrObj(old->type, &old->searchSpec, &new->searchSpec,
1529                                 err);
1530         else
1531                 memset(&new->searchSpec, 0, sizeof (new->searchSpec));
1532 }
1533 
1534 __nis_mapping_item_t *
1535 cloneItem(__nis_mapping_item_t *old) {
1536         __nis_mapping_item_t    *new;
1537         int                     err = 0;
1538         char                    *myself = "cloneItem";
1539 
1540         if (old == 0)
1541                 return (0);
1542 
1543         new = am(myself, sizeof (*new));
1544         if (new == 0)
1545                 return (0);
1546 
1547         copyItem(old, new, &err);
1548         if (err != 0) {
1549                 freeMappingItem(new, 1);
1550                 return (0);
1551         }
1552 
1553         return (new);
1554 }
1555 
1556 void
1557 freeMappingItem(__nis_mapping_item_t *item, int numItems) {
1558         int     i;
1559 
1560         if (item == 0)
1561                 return;
1562 
1563         for (i = 0; i < numItems; i++) {
1564                 sfree(item[i].name);
1565                 freeTripleOrObj(item[i].type, &item[i].searchSpec, FALSE);
1566         }
1567         sfree(item);
1568 }
1569 
1570 __nis_mapping_item_t *
1571 concatenateMappingItem(__nis_mapping_item_t *old, int numItems,
1572                 __nis_mapping_item_t *cat) {
1573         __nis_mapping_item_t    *new;
1574         int                     i, err = 0;
1575         char                    *myself = "concatenateMappingItem";
1576 
1577         if (old == 0 || numItems < 1)
1578                 return (cloneItem(cat));
1579 
1580         new = am(myself, (numItems + 1) * sizeof (*new));
1581         if (new == 0)
1582                 return (0);
1583 
1584         for (i = 0; i < numItems; i++) {
1585                 copyItem(&old[i], &new[i], &err);
1586                 if (err != 0) {
1587                         freeMappingItem(new, i);
1588                         return (0);
1589                 }
1590         }
1591         copyItem(cat, &new[numItems], &err);
1592         if (err != 0) {
1593                 freeMappingItem(new, numItems);
1594                 new = 0;
1595         }
1596 
1597         return (new);
1598 }
1599 
1600 __nis_value_t *
1601 concatenateValues(__nis_value_t *v1, __nis_value_t *v2) {
1602         int             i, n, a;
1603         __nis_value_t   *v;
1604         char            *myself = "concatenateValues";
1605 
1606         if (v1 == 0 || v1->numVals <= 0)
1607                 return (cloneValue(v2, 1));
1608         if (v2 == 0 || v2->numVals <= 0)
1609                 return (cloneValue(v1, 1));
1610 
1611         if (v1->type != v2->type)
1612                 return (0);
1613 
1614         n = v1->numVals + v2->numVals;
1615         v = am(myself, sizeof (*v));
1616         if (v == 0)
1617                 return (0);
1618         v->val = am(myself, n * sizeof (v->val[0]));
1619         if (v->val == 0) {
1620                 free(v);
1621                 return (0);
1622         }
1623         v->type = v1->type;
1624         v->numVals = 0;
1625 
1626         for (a = 0; a < 2; a++) {
1627                 __nis_single_value_t    *val = (a == 0) ? v1->val : v2->val;
1628                 int                     numv = (a == 0) ? v1->numVals :
1629                                                         v2->numVals;
1630                 for (i = 0; i < numv; i++) {
1631                         int     clen, alen = val[i].length;
1632 
1633                         clen = alen;
1634 
1635                         /*
1636                          * Make sure there's a NUL at the end of a string,
1637                          * but avoid adding to the allocated length if there's
1638                          * already a NUL at the end.
1639                          */
1640                         if (alen > 0 && v->type == vt_string &&
1641                                         ((char *)val[i].value)[alen-1] != '\0')
1642                                 alen += 1;
1643                         v->val[v->numVals].value = am(myself, alen);
1644                         if (v->val[v->numVals].value == 0) {
1645                                 freeValue(v, 1);
1646                                 return (0);
1647                         }
1648                         memcpy(v->val[v->numVals].value, val[i].value, clen);
1649                         v->val[v->numVals].length = val[i].length;
1650                         v->numVals++;
1651                 }
1652         }
1653 
1654         return (v);
1655 }
1656 
1657 __nis_value_t *
1658 splitMappingItem(__nis_mapping_item_t *item, char delim,
1659                 __nis_rule_value_t *rv) {
1660         __nis_value_t           *val = getMappingItem(item, mit_any,
1661                         rv, 0, NULL);
1662         __nis_single_value_t    *nval;
1663         int                     i, n, nv;
1664 
1665         if (val == 0)
1666                 return (0);
1667         else if (delim == 0 || val->val == 0 || val->numVals <= 0 ||
1668                         val->type != vt_string) {
1669                 freeValue(val, 1);
1670                 return (0);
1671         }
1672 
1673         nval = val->val;
1674         nv = val->numVals;
1675         val->repeat = FALSE;
1676         val->val = 0;
1677         val->numVals = 0;
1678 
1679         /* In N2L, space and tab delimiters are treated the same */
1680         if (yp2ldap && delim == '\t')
1681                 delim = ' ';
1682 
1683         /* If the item has multiple values, we split each one independently */
1684         for (i = 0; i < nv; i++) {
1685                 char                    *str;
1686                 int                     s, e;
1687                 char                    *newstr;
1688                 __nis_single_value_t    *newval;
1689 
1690                 if (yp2ldap && delim == ' ')
1691                         nval[i].value = trimWhiteSpaces(nval[i].value,
1692                                                         &nval[i].length, 1);
1693 
1694                 str = nval[i].value;
1695 
1696                 if (nval[i].value == 0)
1697                         continue;
1698 
1699                 for (s = 0; s < nval[i].length; s = e+1) {
1700                         /* Find the next delimiter, or end-of-string */
1701                         for (e = s; str[e] != '\0' && str[e] != delim; e++);
1702                         /*
1703                          * 'str[e]' is either a delimiter, or the concluding
1704                          * NUL. Make sure it's NUL.
1705                          */
1706                         str[e] = '\0';
1707                         /* Add to val->val */
1708                         newstr = strdup(&str[s]);
1709                         newval = realloc(val->val,
1710                                         (val->numVals+1) *
1711                                                 sizeof (val->val[0]));
1712                         if (newval != 0)
1713                                 val->val = newval;
1714                         if (newstr == 0 || newval == 0) {
1715                                 freeValue(val, 1);
1716                                 for (n = i; n < nv; n++) {
1717                                         sfree(nval[n].value);
1718                                 }
1719                                 free(nval);
1720                                 sfree(newstr);
1721                                 return (0);
1722                         }
1723                         val->val[val->numVals].value = newstr;
1724                         val->val[val->numVals].length = strlen(newstr) + 1;
1725                         val->numVals++;
1726                 }
1727                 free(nval[i].value);
1728                 nval[i].value = 0;
1729         }
1730         /* Already freed the nval[i].value's as we traversed nval */
1731         free(nval);
1732 
1733         return (val);
1734 }
1735 
1736 /*
1737  * Match the format spec 'f[curf]' to the input value string 'str'.
1738  *
1739  * If successful, returns the updated position in the value string 'str'.
1740  * Otherwise, NULL is returned.
1741  *
1742  * curf         Current index (i.e., the one we should look at) in 'f'
1743  * nf           Number of elements in 'f', including 'mmt_end'
1744  * str          The value string we're scanning
1745  * val          Pointer to where an item value (if any) should be returned
1746  *              Set to NULL if not an 'mmt_item'.
1747  * fmtstart     If non-zero on entry, skip characters in 'str' until we find
1748  *              the f[curf].type data, if doing so makes any sense. On exit,
1749  *              set to the start of the fmt element data (which will be 'str',
1750  *              unless we did skip characters)
1751  * sepset       List of separators
1752  */
1753 char *
1754 scanMappingFormat(__nis_mapping_format_t *f, int curf, int nf, char *str,
1755                 char **val, char **fmtstart, char *sepset) {
1756         char    *mstr, *next, *start = 0, *tmpstr;
1757         int     i, len;
1758         bool_t  match;
1759         char    *myself = "scanMappingFormat";
1760         /* N2L variables */
1761         int     af, skipspaces = 0;
1762         bool_t  ipaddr = FALSE;
1763         char    *spacestr = " ", *emptystr = "";
1764 
1765 
1766         if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1767                 return (0);
1768 
1769         /*
1770          * If separator list is NULL (which will be the case for
1771          * nis+2ldap), then simply use empty string
1772          */
1773         if (sepset == 0)
1774                 sepset = emptystr;
1775 
1776         if (curf >= nf) {
1777                 /* OK if the string also is exhausted */
1778                 if (strchr(sepset, *str) != 0)
1779                         return (str);
1780                 else
1781                         return (0);
1782         }
1783 
1784         switch (f[curf].type) {
1785         case mmt_berstring:
1786                 if (f[curf].match.berString[0] != 'a') {
1787                         /* Not a matchable element */
1788                         return (0);
1789                 }
1790 
1791                 /*
1792                  * If here, it means it's an IP address (N2L case)
1793                  * So continue processing as if it was mmt_item
1794                  */
1795                 ipaddr = TRUE;
1796 
1797         case mmt_item:
1798                 /*
1799                  * In order to find the end of the item value, we must look
1800                  * ahead and determine the start of the next formatting element.
1801                  * If successful, 'next' will be the start of the fmt element
1802                  * after the next one; we don't care about that, other than to
1803                  * check for error.
1804                  *
1805                  * Since an item match is somewhat like an any match, in that
1806                  * we don't know a priori if the first occurence of the next
1807                  * element really is the one we want, we have to scan ahead
1808                  * until we've reached the end.
1809                  */
1810                 tmpstr = str;
1811                 while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1812                                 &start, sepset)) != 0) {
1813                         char    *tmp = next;
1814                         int     cf;
1815 
1816                         for (cf = curf+2; cf < nf; cf++) {
1817                                 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1818                                         0, sepset);
1819                                 if (tmp == 0)
1820                                         break;
1821                         }
1822                         if (tmp == 0) {
1823                                 tmpstr = next;
1824                         } else if (strchr(sepset, *tmp) != 0) {
1825                                 break;
1826                         } else {
1827                                 return (0);
1828                         }
1829 
1830                 }
1831                 if (next == 0 || start == 0)
1832                         return (0);
1833 
1834                 if (val != 0) {
1835                         len = (int)((long)start - (long)str);
1836                         *val = am(myself, len + 1);
1837                         if (*val == 0)
1838                                 return (0);
1839                         memcpy(*val, str, len);
1840                         (*val)[len] = '\0';
1841 
1842                         if (ipaddr == TRUE) {
1843                                 /*
1844                                  * In N2L, we need to check if *val is truly an
1845                                  * IP address
1846                                  */
1847                                 af = checkIPaddress(*val, len, &tmpstr);
1848 
1849                                 if (af == -2) {
1850                                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1851                                                 "%s:Internal error while "
1852                                                 "processing IPaddress %s",
1853                                                 myself, *val);
1854                                         sfree(*val);
1855                                         return (0);
1856                                 } else if (af == -1) {
1857                                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1858                                                 "%s:%s is not an IP address",
1859                                                 myself, *val);
1860                                         sfree(*val);
1861                                         return (0);
1862                                 } else if (af == 0) {
1863                                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1864                                                 "%s:IP address %s is not "
1865                                                 "supported by rfc2307bis",
1866                                                 myself, *val);
1867                                         sfree(*val);
1868                                         return (0);
1869                                 } else if (sstrncmp(*val, tmpstr, len) != 0) {
1870                                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1871                                                 "%s:IPaddress %s converted "
1872                                                 "to %s", myself, *val, tmpstr);
1873                                 }
1874 
1875                                 sfree(*val);
1876                                 *val = tmpstr;
1877                         }
1878                 }
1879 
1880                 if (fmtstart != 0)
1881                         *fmtstart = str;
1882 
1883                 return (start);
1884 
1885         case mmt_string:
1886                 if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1887                         /*
1888                          * Count this as a successful match of an empty
1889                          * string.
1890                          */
1891                         if (fmtstart != 0)
1892                                 *fmtstart = str;
1893                         return (str);
1894                 }
1895 
1896                 /*
1897                  * In N2L, if the format string 'mstr' contains only
1898                  * whitespaces (spaces and tabs), then it should
1899                  * match one or more whitespaces from the input
1900                  * string 'str'.
1901                  */
1902                 if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1903                                 mstr = spacestr;
1904                                 skipspaces = 1;
1905                                 next = str + strcspn(str, " \t");
1906                                 /*
1907                                  * Even if there is no whitespace in 'str',
1908                                  * it's OK. This is to allow formats like
1909                                  * "%s %s %s" to match inputs like "foo bar".
1910                                  */
1911                                 if (*next == '\0')
1912                                         mstr = emptystr;
1913                 } else {
1914                         /* No match string in 'str' => failure */
1915                         if ((next = strstr(str, mstr)) == 0)
1916                                 return (0);
1917                 }
1918 
1919                 /* If 'fmtstart' == 0, we require 'next' == 'str' */
1920                 if (fmtstart == 0 && next != str)
1921                         return (0);
1922                 /* Success; save start of match string if requested */
1923                 if (fmtstart != 0)
1924                         *fmtstart = next;
1925                 /* Update position in the value string */
1926                 str = (char *)((long)next + (long)strlen(mstr));
1927 
1928                 /* Skip whitespaces for N2L */
1929                 if (skipspaces == 1)
1930                         for (; *str == ' ' || *str == '\t'; str++);
1931 
1932                 return (str);
1933 
1934         case mmt_single:
1935                 if (fmtstart != 0) {
1936                         match = FALSE;
1937                         /* Skip ahead until we match */
1938                         for (next = str; *next != '\0'; next++) {
1939                                 unsigned char   *lo = f[curf].match.single.lo;
1940                                 unsigned char   *hi = f[curf].match.single.hi;
1941 
1942                                 for (i = 0; i < f[curf].match.single.numRange;
1943                                                 i++) {
1944                                         if (*next >= lo[i] && *next <= hi[i]) {
1945                                                 match = TRUE;
1946                                                 break;
1947                                         }
1948                                 }
1949                                 if (match)
1950                                         break;
1951                         }
1952                         if (!match)
1953                                 return (0);
1954                         *fmtstart = next;
1955                         str = next;
1956                 } else {
1957                         match = FALSE;
1958                         for (i = 0; i < f[curf].match.single.numRange; i++) {
1959                                 if (*str >= f[curf].match.single.lo[i] &&
1960                                         *str <= f[curf].match.single.hi[i]) {
1961                                         match = TRUE;
1962                                         break;
1963                                 }
1964                         }
1965                         if (!match)
1966                                 return (0);
1967                 }
1968                 /* Step over the matched character */
1969                 str++;
1970                 return (str);
1971 
1972         case mmt_any:
1973                 /*
1974                  * Look ahead to find the beginning of the next element.
1975                  * Because a wildcard-match isn't necessarily uniquely
1976                  * determined until we've reached the end, we then continue
1977                  * to scan ahead.
1978                  */
1979                 while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1980                                                 &start, sepset)) != 0) {
1981                         char    *tmp = next;
1982                         int     cf;
1983 
1984                         for (cf = curf+2; cf < nf; cf++) {
1985                                 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1986                                         0, sepset);
1987                                 if (tmp == 0)
1988                                         break;
1989                         }
1990                         if (tmp == 0) {
1991                                 str = next;
1992                         } else if (*tmp == '\0') {
1993                                 break;
1994                         } else {
1995                                 return (0);
1996                         }
1997                 }
1998                 if (next == 0 || start == 0)
1999                         return (0);
2000 
2001                 if (fmtstart != 0)
2002                         *fmtstart = str;
2003 
2004                 return (start);
2005 
2006         case mmt_limit:
2007                 if (f[curf].match.limit == eos) {
2008                         if (fmtstart != 0) {
2009                                 /* Skip to the end */
2010                                 str = str + strcspn(str, sepset);
2011                                 *fmtstart = str;
2012                         } else if (strchr(sepset, *str) == 0) {
2013                                 return (0);
2014                         }
2015                 }
2016                 return (str);
2017 
2018         case mmt_begin:
2019                 if (fmtstart != 0)
2020                         *fmtstart = str;
2021                 return (str);
2022 
2023         case mmt_end:
2024                 if (fmtstart != 0) {
2025                         /* Skip to the end */
2026                         str = str + strcspn(str, sepset);
2027                         *fmtstart = str;
2028                         return (str);
2029                 }
2030                 /* No skipping, so we must be at the end of the value */
2031                 if (strchr(sepset, *str) == 0)
2032                         return (0);
2033                 return (str);
2034 
2035         default:
2036                 break;
2037         }
2038 
2039         return (0);
2040 }
2041 
2042 /*
2043  * Verify that the string 'str' matches the mapping format array 'f'.
2044  * Returns 1 in case of a match, 0 otherwise.
2045  */
2046 int
2047 verifyMappingMatch(__nis_mapping_format_t *f, char *str) {
2048         int                     n, nf;
2049         __nis_mapping_format_t  *ftmp;
2050 
2051         /* Count the number of format elements in the format */
2052         for (nf = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2053                 nf++;
2054         }
2055         /* Count the mmt_end as well */
2056         nf++;
2057 
2058         for (n = 0; n < nf; n++) {
2059                 str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2060                 if (str == 0)
2061                         break;
2062         }
2063 
2064         return ((str != 0) ? 1 : 0);
2065 }
2066 
2067 /*
2068  * Perform a match operation. For example, given the rule
2069  *      ("{%s}%s", auth_name, public_data)=nisPublicKey
2070  * and assuming that 'nisPublicKey' has the value "{dh640-0}abcdef12345",
2071  * assign "dh640-0" to 'auth_name' and "abcdef12345" to 'public_data'.
2072  *
2073  * Note that this function doesn't perform the actual assignment. Rather,
2074  * it returns an array of __nis_value_t's, with element zero of the value
2075  * array being the new value of the first matched item, element one the
2076  * value of the second matched item, etc. In the example above, we'd
2077  * return a value array with two elements.
2078  *
2079  * If there is more than one input value (inVal->numVals > 1), the
2080  * output array elements will also be multi-valued.
2081  *
2082  * f            The match format
2083  * inVal        Input value(s)
2084  * numVal       Number of elements in the output value array
2085  * sepset       List of separators
2086  * outstr       Points to the updated position upto which the
2087  *              input string has been matched
2088  */
2089 __nis_value_t **
2090 matchMappingItem(__nis_mapping_format_t *f, __nis_value_t *inVal,
2091                 int *numVals, char *sepset, char **outstr) {
2092         __nis_value_t           **v = 0;
2093         int                     i, n, ni, numItems, nf, nv = 0;
2094         char                    *str, *valstr;
2095         __nis_mapping_format_t  *ftmp;
2096         char                    *myself = "matchMappingItem";
2097 
2098         if (f == 0 ||
2099                 inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2100                 return (0);
2101 
2102         /* Count the number of format elements and items in the format */
2103         for (nf = numItems = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2104                 nf++;
2105 
2106                 /*
2107                  * Count mmt_item and mmt_berstring (used by N2L to
2108                  * represent address %a)
2109                  */
2110                 if (ftmp->type == mmt_item)
2111                                 numItems++;
2112                 else if (ftmp->type == mmt_berstring && ftmp->match.berString &&
2113                                 ftmp->match.berString[0] == 'a')
2114                                 numItems++;
2115         }
2116         /* Count the mmt_end as well */
2117         nf++;
2118 
2119         /*
2120          * If no items, there will be no values. This isn't exactly an error
2121          * from the limited point of view of this function, so we return a
2122          * __nis_value_t with zero values.
2123          */
2124         if (numItems <= 0) {
2125                 v = am(myself, sizeof (v[0]));
2126                 if (v == 0)
2127                         return (0);
2128                 v[0] = am(myself, sizeof (*v[0]));
2129                 if (v[0] == 0) {
2130                         sfree(v);
2131                         return (0);
2132                 }
2133                 v[0]->type = vt_string;
2134                 v[0]->numVals = 0;
2135                 v[0]->val = 0;
2136                 if (numVals != 0)
2137                         *numVals = 1;
2138                 return (v);
2139         }
2140 
2141         /* Allocate and initialize the return array */
2142         v = am(myself, numItems * sizeof (v[0]));
2143         if (v == 0)
2144                 return (0);
2145         for (n = 0; n < numItems; n++) {
2146                 v[n] = am(myself, sizeof (*v[n]));
2147                 if (v[n] == 0) {
2148                         int     j;
2149 
2150                         for (j = 0; j < n; j++)
2151                                 freeValue(v[j], 1);
2152                         sfree(v);
2153                         return (0);
2154                 }
2155                 v[n]->type = vt_string;
2156                 v[n]->numVals = 0;
2157                 v[n]->val = am(myself, inVal->numVals * sizeof (v[n]->val[0]));
2158                 if (v[n]->val == 0) {
2159                         int     j;
2160 
2161                         for (j = 0; j < n; j++)
2162                                 freeValue(v[j], 1);
2163                         sfree(v);
2164                         return (0);
2165                 }
2166                 for (i = 0; i < inVal->numVals; i++) {
2167                         v[n]->val[i].length = 0;
2168                         v[n]->val[i].value = 0;
2169                 }
2170         }
2171 
2172         /* For each input value, perform the match operation */
2173         for (i = 0; i < inVal->numVals; i++) {
2174                 str = inVal->val[i].value;
2175                 if (str == 0)
2176                         continue;
2177                 for (n = 0, ni = 0; n < nf; n++) {
2178                         valstr = 0;
2179                         str = scanMappingFormat(f, n, nf, str, &valstr,
2180                                 0, sepset);
2181                         if (str == 0)
2182                                 break;
2183                         if (valstr != 0 && ni < numItems &&
2184                                         v[ni]->numVals < inVal->numVals) {
2185                                 v[ni]->val[v[ni]->numVals].value = valstr;
2186                                 v[ni]->val[v[ni]->numVals].length =
2187                                                         strlen(valstr) + 1;
2188                                 v[ni]->numVals++;
2189                                 ni++;
2190                         } else if (valstr != 0) {
2191                                 sfree(valstr);
2192                         }
2193                 }
2194                 if (str == 0) {
2195                         for (n = 0; n < numItems; n++)
2196                                 freeValue(v[n], 1);
2197                         sfree(v);
2198                         return (0);
2199                 }
2200         }
2201 
2202         if (numVals != 0)
2203                 *numVals = numItems;
2204 
2205         /*
2206          * Update the return string upto the point it has been matched
2207          * This string will be used by the N2L code in its next call
2208          * to this function
2209          */
2210         if (outstr != 0)
2211                 *outstr = str;
2212 
2213         return (v);
2214 }
2215 
2216 /*
2217  * Perform an extract operation. For example, given the expression
2218  *      (name, "%s.*")
2219  * and assuming 'name' is an item with the value "some.thing", the
2220  * value returned by the extract is "some".
2221  */
2222 __nis_value_t *
2223 extractMappingItem(__nis_mapping_item_t *item, __nis_mapping_format_t *f,
2224                 __nis_rule_value_t *rv, int *stat) {
2225         __nis_value_t           *val = getMappingItem(item, mit_any,
2226                         rv, 0, stat);
2227         __nis_single_value_t    *nval;
2228         int                     i, n, nv, nf;
2229         __nis_mapping_format_t  *ftmp;
2230 
2231         if (val == 0)
2232                 return (0);
2233         else if (f == 0 || rv == 0 || val->val == 0 ||
2234                         val->numVals <= 0 || val->type != vt_string) {
2235                 freeValue(val, 1);
2236                 return (0);
2237         }
2238 
2239         /* Sanity check the format; it must have one and only one mmt_item */
2240         {
2241                 int     numitem;
2242 
2243                 for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2244                                 ftmp++) {
2245                         nf++;
2246                         if (ftmp->type == mmt_item)
2247                                 numitem++;
2248                 }
2249                 /* Count the mmt_end as well */
2250                 nf++;
2251                 if (numitem != 1) {
2252                         freeValue(val, 1);
2253                         return (0);
2254                 }
2255         }
2256 
2257         nval = val->val;
2258         nv = val->numVals;
2259         val->repeat = FALSE;
2260         val->val = 0;
2261         val->numVals = 0;
2262 
2263         /* If the item has multiple values, we extract each one independently */
2264         for (i = 0; i < nv; i++) {
2265                 char                    *str = nval[i].value;
2266                 char                    *newstr = 0;
2267                 __nis_single_value_t    *newval;
2268 
2269                 if (nval[i].value == 0)
2270                         continue;
2271 
2272                 /*
2273                  * We match the whole string, even if we find a value for
2274                  * the item before exhausting all format elements. By doing
2275                  * this, we ensure that the string really matches the complete
2276                  * format specification.
2277                  */
2278                 for (n = 0; n < nf; n++) {
2279                         str = scanMappingFormat(f, n, nf, str, &newstr, 0, 0);
2280                         if (str == 0)
2281                                 break;
2282                 }
2283 
2284                 /*
2285                  * *str should now be NUL, meaning we've reached the end of
2286                  * the string (value), and it completely matched the format.
2287                  * If 'str' is NULL, there was an error, and if 'newstr' is
2288                  * 0, we somehow failed to obtain a value.
2289                  */
2290                 if (str == 0 || *str != '\0' || newstr == 0 ||
2291                                 (newval = realloc(val->val,
2292                                         (val->numVals+1) *
2293                                         sizeof (val->val[0]))) == 0) {
2294                         freeValue(val, 1);
2295                         for (n = 0; n < nv; n++) {
2296                                 sfree(nval[n].value);
2297                         }
2298                         free(nval);
2299                         sfree(newstr);
2300                         return (0);
2301                 }
2302 
2303                 val->val = newval;
2304                 val->val[val->numVals].value = newstr;
2305                 val->val[val->numVals].length = strlen(newstr) + 1;
2306                 val->numVals++;
2307 
2308                 free(nval[i].value);
2309                 nval[i].value = 0;
2310         }
2311         free(nval);
2312 
2313         return (val);
2314 }
2315 
2316 /*
2317  * For each value in 'val', remove the last character, provided that
2318  * it matches 'elide'.
2319  */
2320 void
2321 stringElide(__nis_value_t *val, char elide) {
2322 
2323         if (val != 0 && val->type == vt_string) {
2324                 int     i;
2325 
2326                 for (i = 0; i < val->numVals; i++) {
2327                         int     end = val->val[i].length;
2328                         char    *str = val->val[i].value;
2329 
2330                         if (str == 0 || end <= 0)
2331                                 continue;
2332 
2333                         /*
2334                          * If the NUL was counted in the length, step back
2335                          * over it.
2336                          */
2337                         if (str[end-1] == '\0')
2338                                 end--;
2339                         if (end > 0 && str[end-1] == elide) {
2340                                 str[end-1] = '\0';
2341                                 val->val[i].length--;
2342                         }
2343                 }
2344         }
2345 }
2346 
2347 /*
2348  * Obtain the value for the mapping sub-element 'e', given the input
2349  * rule-value 'rv'.
2350  */
2351 __nis_value_t *
2352 getMappingSubElement(__nis_mapping_sub_element_t *e,
2353         __nis_rule_value_t *rv, int *np_ldap_stat) {
2354         __nis_value_t   *val;
2355 
2356         if (e == 0)
2357                 return (0);
2358 
2359         switch (e->type) {
2360         case me_item:
2361                 val = getMappingItem(&e->element.item, mit_any, rv, 0,
2362                         np_ldap_stat);
2363                 break;
2364         case me_print:
2365                 val = getMappingFormatArray(e->element.print.fmt, rv,
2366                                                 fa_item,
2367                                                 e->element.print.numItems,
2368                                                 e->element.print.item);
2369                 if (e->element.print.doElide)
2370                         stringElide(val, e->element.print.elide);
2371                 break;
2372         case me_split:
2373                 val = splitMappingItem(&e->element.split.item,
2374                                         e->element.split.delim,
2375                                         rv);
2376                 break;
2377         case me_extract:
2378                 val = extractMappingItem(&e->element.extract.item,
2379                                         e->element.extract.fmt,
2380                                         rv, np_ldap_stat);
2381                 break;
2382         case me_match:
2383         default:
2384                 val = 0;
2385                 break;
2386         }
2387 
2388         return (val);
2389 }
2390 
2391 /*
2392  * Obtain the value of the mapping element 'e', given the input rule-
2393  * value 'rv'. The 'native' mapping type is used when 'rv' is NULL,
2394  * and the result is a string representation of the mapping element;
2395  * in that case, items of the 'native' type are printed without their
2396  * type designation ("nis+" or "ldap").
2397  */
2398 __nis_value_t *
2399 getMappingElement(__nis_mapping_element_t *e, __nis_mapping_item_type_t native,
2400                 __nis_rule_value_t *rv, int *stat) {
2401         __nis_value_t   *val, **tv;
2402         int             i, success = 0, novalue = 0;
2403         int *np_ldap_stat;
2404         char            *myself = "getMappingElement";
2405 
2406         switch (e->type) {
2407         case me_item:
2408                 val = getMappingItem(&e->element.item, native, rv, 0, NULL);
2409                 break;
2410         case me_print:
2411                 tv = am(myself, e->element.print.numSubElements *
2412                         sizeof (tv[0]));
2413                 np_ldap_stat = am(myself,
2414                         e->element.print.numSubElements * sizeof (int));
2415                 if ((e->element.print.numSubElements > 0) &&
2416                                 (tv == 0 || np_ldap_stat == 0)) {
2417                         val = 0;
2418                         sfree(tv);
2419                         sfree(np_ldap_stat);
2420                         break;
2421                 }
2422                 for (i = 0; i < e->element.print.numSubElements; i++) {
2423                         np_ldap_stat[i] = 0;
2424                         tv[i] = getMappingSubElement(
2425                                 &e->element.print.subElement[i],
2426                                 rv, &np_ldap_stat[i]);
2427                 }
2428                 /*
2429                  * if we get NP_LDAP_NO_VALUE to any of the subelement
2430                  * and we get NP_LDAP_MAP_SUCCESS to all other subelement
2431                  * then we had enough nis+ column values which can
2432                  * produce value for this rule, but didn't. So return
2433                  * NP_LDAP_RULES_NO_VALUE to indicate to proceed to
2434                  * next database id.
2435                  */
2436                 for (i = 0; i < e->element.print.numSubElements; i++) {
2437                         if (np_ldap_stat[i] == NP_LDAP_MAP_SUCCESS)
2438                                 success++;
2439                         if (np_ldap_stat[i] == NP_LDAP_NO_VALUE)
2440                                 novalue++;
2441                 }
2442                 if (stat != NULL && novalue > 0 &&
2443                                 ((novalue+success) ==
2444                                         e->element.print.numSubElements))
2445                                             *stat = NP_LDAP_RULES_NO_VALUE;
2446                 val = getMappingFormatArray(e->element.print.fmt, rv,
2447                                                 fa_value,
2448                                                 e->element.print.numSubElements,
2449                                                 tv);
2450                 for (i = 0; i < e->element.print.numSubElements; i++) {
2451                         freeValue(tv[i], 1);
2452                 }
2453                 sfree(tv);
2454                 sfree(np_ldap_stat);
2455                 if (e->element.print.doElide)
2456                         stringElide(val, e->element.print.elide);
2457                 break;
2458         case me_split:
2459                 val = splitMappingItem(&e->element.split.item,
2460                                         e->element.split.delim,
2461                                         rv);
2462                 break;
2463         case me_match:
2464                 /*
2465                  * A match doesn't produce an assignable value per se,
2466                  * so we shouldn't get one here.
2467                  */
2468                 val = 0;
2469                 break;
2470         case me_extract:
2471                 val = extractMappingItem(&e->element.extract.item,
2472                                         e->element.extract.fmt,
2473                                         rv, NULL);
2474                 break;
2475         default:
2476                 val = 0;
2477                 break;
2478         }
2479 
2480         return (val);
2481 }