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