1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <lber.h> 30 #include <ldap.h> 31 #include <strings.h> 32 #include <errno.h> 33 34 #include "nisdb_mt.h" 35 36 #include "ldap_util.h" 37 #include "ldap_op.h" 38 #include "ldap_ruleval.h" 39 #include "ldap_attr.h" 40 #include "ldap_val.h" 41 #include "ldap_nisplus.h" 42 #include "ldap_ldap.h" 43 44 extern int yp2ldap; 45 46 47 __nis_mapping_format_t * 48 cloneMappingFormat(__nis_mapping_format_t *m) { 49 __nis_mapping_format_t *new; 50 int i, nf, err; 51 char *myself = "cloneMappingFormat"; 52 53 if (m == 0) 54 return (0); 55 56 for (nf = 0; m[nf].type != mmt_end; nf++); 57 nf++; 58 59 new = am(myself, nf * sizeof (new[0])); 60 if (new == 0) 61 return (0); 62 63 /* Copy the whole array */ 64 memcpy(new, m, nf * sizeof (new[0])); 65 66 /* Make copies of allocated stuff */ 67 for (i = 0, err = 0; i < nf; i++) { 68 switch (m[i].type) { 69 case mmt_string: 70 new[i].match.string = sdup(myself, T, 71 m[i].match.string); 72 if (new[i].match.string == 0 && m[i].match.string != 0) 73 err++; 74 break; 75 case mmt_single: 76 new[i].match.single.lo = 77 am(myself, m[i].match.single.numRange * 78 sizeof (new[i].match.single.lo[0])); 79 new[i].match.single.hi = 80 am(myself, m[i].match.single.numRange * 81 sizeof (new[i].match.single.hi[0])); 82 if (new[i].match.single.lo != 0) 83 memcpy(new[i].match.single.lo, 84 m[i].match.single.lo, 85 m[i].match.single.numRange); 86 else if (m[i].match.single.lo != 0) 87 err++; 88 if (new[i].match.single.hi != 0) 89 memcpy(new[i].match.single.hi, 90 m[i].match.single.hi, 91 m[i].match.single.numRange); 92 else if (m[i].match.single.hi != 0) 93 err++; 94 break; 95 case mmt_berstring: 96 new[i].match.berString = sdup(myself, T, 97 m[i].match.berString); 98 if (new[i].match.berString == 0 && 99 m[i].match.berString != 0) 100 err++; 101 break; 102 case mmt_item: 103 case mmt_limit: 104 case mmt_any: 105 case mmt_begin: 106 case mmt_end: 107 default: 108 break; 109 } 110 } 111 112 /* If there were memory allocation errors, free the copy */ 113 if (err > 0) { 114 freeMappingFormat(new); 115 new = 0; 116 } 117 118 return (new); 119 } 120 121 void 122 freeMappingFormat(__nis_mapping_format_t *m) { 123 int i; 124 125 if (m == 0) 126 return; 127 128 for (i = 0; m[i].type != mmt_end; i++) { 129 switch (m[i].type) { 130 case mmt_string: 131 sfree(m[i].match.string); 132 break; 133 case mmt_single: 134 sfree(m[i].match.single.lo); 135 sfree(m[i].match.single.hi); 136 break; 137 case mmt_berstring: 138 sfree(m[i].match.berString); 139 break; 140 case mmt_item: 141 case mmt_limit: 142 case mmt_any: 143 case mmt_begin: 144 case mmt_end: 145 default: 146 break; 147 } 148 } 149 150 free(m); 151 } 152 153 154 void 155 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) { 156 int i; 157 char *myself = "copyIndex"; 158 159 if (old == 0 || new == 0) { 160 *err = EINVAL; 161 return; 162 } 163 164 for (i = 0; i < old->numIndexes; i++) { 165 new->name[i] = sdup(myself, T, old->name[i]); 166 if (new->name[i] == 0 && old->name[i] != 0) { 167 *err = ENOMEM; 168 return; 169 } 170 new->value[i] = cloneMappingFormat(old->value[i]); 171 if (new->value[i] == 0 && old->value[i] != 0) { 172 *err = ENOMEM; 173 return; 174 } 175 } 176 177 new->numIndexes = old->numIndexes; 178 } 179 180 __nis_index_t * 181 cloneIndex(__nis_index_t *old) { 182 char *myself = "cloneIndex"; 183 int err = 0; 184 __nis_index_t *new = am(myself, sizeof (*new)); 185 186 if (old == 0) 187 return (0); 188 189 if (new != 0) { 190 copyIndex(old, new, &err); 191 if (err != 0) { 192 freeIndex(new, 1); 193 new = 0; 194 } 195 } 196 197 return (new); 198 } 199 200 void 201 freeIndex(__nis_index_t *old, bool_t doFree) { 202 int i; 203 204 if (old == 0) 205 return; 206 207 for (i = 0; i < old->numIndexes; i++) { 208 sfree(old->name[i]); 209 freeMappingFormat(old->value[i]); 210 } 211 212 if (doFree) 213 free(old); 214 } 215 216 char ** 217 cloneName(char **name, int numNames) { 218 char **new; 219 int i; 220 char *myself = "cloneName"; 221 222 if (name == 0 || numNames <= 0) 223 return (0); 224 225 new = am(myself, numNames * sizeof (new[0])); 226 if (new == 0) 227 return (0); 228 229 for (i = 0; i < numNames; i++) { 230 if (name[i] != 0) { 231 new[i] = sdup(myself, T, name[i]); 232 if (new[i] == 0) { 233 for (i--; i >= 0; i--) { 234 sfree(new[i]); 235 } 236 sfree(new); 237 return (0); 238 } 239 } else { 240 new[i] = 0; 241 } 242 } 243 244 return (new); 245 } 246 247 void 248 freeValue(__nis_value_t *val, int count) { 249 int c, i; 250 251 if (val == 0) 252 return; 253 254 for (c = 0; c < count; c++) { 255 if (val[c].val != 0) { 256 for (i = 0; i < val[c].numVals; i++) { 257 sfree(val[c].val[i].value); 258 } 259 free(val[c].val); 260 } 261 } 262 263 free(val); 264 } 265 266 __nis_value_t * 267 cloneValue(__nis_value_t *val, int count) { 268 __nis_value_t *n; 269 int c, i; 270 char *myself = "cloneValue"; 271 272 if (count <= 0 || val == 0) 273 return (0); 274 275 n = am(myself, count * sizeof (*n)); 276 if (n == 0) 277 return (0); 278 279 for (c = 0; c < count; c++) { 280 n[c].type = val[c].type; 281 n[c].repeat = val[c].repeat; 282 n[c].numVals = val[c].numVals; 283 if (n[c].numVals > 0) { 284 n[c].val = am(myself, n[c].numVals * 285 sizeof (n[c].val[0])); 286 if (n[c].val == 0) { 287 freeValue(n, c); 288 return (0); 289 } 290 } else { 291 n[c].val = 0; 292 } 293 for (i = 0; i < n[c].numVals; i++) { 294 int amlen = val[c].val[i].length; 295 296 /* 297 * The functions that create string values try to 298 * make sure that there's a NUL at the end. However, 299 * both NIS+ and LDAP have a tendency to store strings 300 * without a NUL, so the value length may not include 301 * the NUL (even though it's there). In order to 302 * preserve that NUL, we add a byte to the length if 303 * the type is vt_string, and there isn't already a 304 * NUL at the end. The memory allocation function 305 * (am()) will take care of actually putting the NUL 306 * in place, since it allocates zero-initialized 307 * memory. 308 */ 309 n[c].val[i].length = val[c].val[i].length; 310 if (n[c].type == vt_string && amlen > 0 && 311 ((char *)val[c].val[i].value)[amlen-1] != 312 '\0') { 313 amlen++; 314 } 315 n[c].val[i].value = am(myself, amlen); 316 if (amlen > 0 && n[c].val[i].value == 0) { 317 freeValue(n, c); 318 return (0); 319 } 320 memcpy(n[c].val[i].value, val[c].val[i].value, 321 n[c].val[i].length); 322 } 323 } 324 325 return (n); 326 } 327 328 /* Define LBER_USE_DER per ber_decode(3LDAP) */ 329 #ifndef LBER_USE_DER 330 #define LBER_USE_DER 0x01 331 #endif /* LBER_USE_DER */ 332 333 /* 334 * Return a copy of 'valIn' where each value has been replaced by the 335 * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged. 336 */ 337 __nis_value_t * 338 berEncode(__nis_value_t *valIn, char *berstring) { 339 char *myself = "berEncode"; 340 __nis_value_t *val; 341 int i; 342 343 if (valIn == 0 || berstring == 0) 344 return (0); 345 346 val = cloneValue(valIn, 1); 347 if (val == 0) 348 return (0); 349 350 for (i = 0; i < val->numVals; i++) { 351 BerElement *ber = ber_alloc(); 352 struct berval *bv = 0; 353 int ret; 354 355 if (ber == 0) { 356 logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL", 357 myself); 358 freeValue(val, 1); 359 return (0); 360 } 361 362 if ((strcmp("b", berstring) == 0 || 363 strcmp("i", berstring) == 0)) { 364 if (val->val[i].length >= sizeof (int)) { 365 ret = ber_printf(ber, berstring, 366 *((int *)(val->val[i].value))); 367 } else { 368 ret = -1; 369 } 370 } else if (strcmp("B", berstring) == 0) { 371 ret = ber_printf(ber, berstring, 372 val->val[i].value, 373 val->val[i].length * 8); 374 } else if (strcmp("n", berstring) == 0) { 375 ret = ber_printf(ber, berstring); 376 } else if (strcmp("o", berstring) == 0) { 377 ret = ber_printf(ber, berstring, 378 val->val[i].value, val->val[i].length); 379 } else if (strcmp("s", berstring) == 0) { 380 char *str = am(myself, val->val[i].length + 1); 381 382 if (str != 0) { 383 ret = ber_printf(ber, berstring, str); 384 free(str); 385 } else { 386 ret = -1; 387 } 388 } else { 389 ret = -1; 390 } 391 392 if (ret == -1) { 393 reportError(NPL_BERENCODE, "%s: BER encoding error", 394 myself); 395 ber_free(ber, 1); 396 freeValue(val, 1); 397 return (0); 398 } 399 400 if (ber_flatten(ber, &bv) != 0 || bv == 0) { 401 reportError(NPL_BERENCODE, "%s: ber_flatten() error", 402 myself); 403 ber_free(ber, 1); 404 freeValue(val, 1); 405 return (0); 406 } 407 408 sfree(val->val[i].value); 409 val->val[i].length = bv->bv_len; 410 val->val[i].value = bv->bv_val; 411 412 ber_free(ber, 1); 413 } 414 415 val->type = vt_ber; 416 417 return (val); 418 } 419 420 __nis_value_t * 421 berDecode(__nis_value_t *valIn, char *berstring) { 422 __nis_value_t *val; 423 int i; 424 char *myself = "berDecode"; 425 426 if (valIn == 0 || berstring == 0) 427 return (0); 428 429 val = cloneValue(valIn, 1); 430 if (val == 0) 431 return (0); 432 433 for (i = 0; i < val->numVals; i++) { 434 void *v = 0; 435 int ret, len = 0; 436 struct berval bv; 437 BerElement *ber; 438 439 if (val->val[i].value == 0 || val->val[i].length <= 0) 440 continue; 441 442 bv.bv_val = val->val[i].value; 443 bv.bv_len = val->val[i].length; 444 ber = ber_init(&bv); 445 if (ber == 0) { 446 reportError(NPL_BERDECODE, "%s: ber_init() error", 447 myself); 448 freeValue(val, 1); 449 return (0); 450 } 451 452 if ((strcmp("b", berstring) == 0 || 453 strcmp("i", berstring) == 0)) { 454 len = sizeof (int); 455 v = am(myself, len); 456 if (v != 0) { 457 ret = ber_scanf(ber, berstring, v); 458 } else { 459 ret = -1; 460 } 461 } else if (strcmp("B", berstring) == 0) { 462 long llen; 463 464 ret = ber_scanf(ber, berstring, &v, &llen); 465 if (ret != -1) { 466 len = llen/8; 467 } 468 } else if (strcmp("n", berstring) == 0) { 469 ret = 0; 470 } else if (strcmp("o", berstring) == 0) { 471 struct berval *bv = am(myself, sizeof (*bv)); 472 473 if (bv != 0) { 474 ret = ber_scanf(ber, "O", &bv); 475 if (ret != -1 && bv != 0) { 476 v = bv->bv_val; 477 len = bv->bv_len; 478 } else { 479 ret = -1; 480 } 481 /* Only free 'bv' itself */ 482 free(bv); 483 } else { 484 ret = -1; 485 } 486 } else if (strcmp("s", berstring) == 0) { 487 ret = ber_scanf(ber, "a", &v); 488 if (ret != -1) { 489 len = slen(v); 490 } 491 } else { 492 ret = -1; 493 } 494 495 if (ret == -1) { 496 reportError(NPL_BERDECODE, "%s: BER decoding error", 497 myself); 498 freeValue(val, 1); 499 return (0); 500 } 501 502 /* Free the old value, and replace it with the decoded one */ 503 sfree(val->val[i].value); 504 val->val[i].value = v; 505 val->val[i].length = len; 506 } 507 508 return (val); 509 } 510 511 /* 512 * Return the value of the specified item. 513 */ 514 __nis_value_t * 515 getMappingItemVal(__nis_mapping_item_t *item, __nis_mapping_item_type_t native, 516 __nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) { 517 __nis_value_t *val = 0, *nameVal, *exVal = 0; 518 int numName, caseInsens, cmp; 519 int i, j, k; 520 char **name; 521 enum {rvOnly, rvThenLookup, lookupOnly} check; 522 unsigned char fromldap = '\0'; 523 524 if (item == 0) 525 return (0); 526 527 /* 528 * First, we decide if we should look for the value in 'rv', 529 * directly from NIS+/LDAP, or both. 530 */ 531 switch (item->type) { 532 case mit_nisplus: 533 /* Do we have a valid index/object spec ? */ 534 if (item->searchSpec.obj.index.numIndexes <= 0 && 535 item->searchSpec.obj.name == 0) { 536 /* 537 * No valid index/object. If we have a rule-value, 538 * use it. Otherwise, return error. 539 */ 540 if (rv != 0) { 541 name = rv->colName; 542 nameVal = rv->colVal; 543 numName = rv->numColumns; 544 caseInsens = 0; 545 check = rvOnly; 546 } else { 547 return (0); 548 } 549 } else { 550 /* 551 * Valid index, so skip the rule-value and do 552 * a direct NIS+ lookup. 553 */ 554 check = lookupOnly; 555 } 556 break; 557 case mit_ldap: 558 if (rv != 0) { 559 name = rv->attrName; 560 nameVal = rv->attrVal; 561 numName = rv->numAttrs; 562 caseInsens = 1; 563 fromldap = '1'; 564 } 565 /* Do we have a valid triple ? */ 566 if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) { 567 /* 568 * No valid triple. If we have a rule-value, use it. 569 * Otherwise, return error. 570 */ 571 if (rv != 0) { 572 check = rvOnly; 573 } else { 574 return (0); 575 } 576 } else if (item->searchSpec.triple.base == 0 && 577 item->searchSpec.triple.scope == 578 LDAP_SCOPE_ONELEVEL && 579 item->searchSpec.triple.attrs == 0 && 580 item->searchSpec.triple.element == 0) { 581 /* 582 * We have a valid triple, but it points to the 583 * current LDAP container. Thus, first look in 584 * the rule-value; if that fails, perform a direct 585 * LDAP lookup. 586 */ 587 if (rv != 0) { 588 check = rvThenLookup; 589 } else { 590 check = lookupOnly; 591 } 592 } else { 593 /* 594 * Valid triple, and it's not the current container 595 * (at least not in the trivial sense). Hence, do 596 * a direct LDAP lookup. 597 */ 598 check = lookupOnly; 599 } 600 break; 601 default: 602 return (0); 603 } 604 605 /* Check the rule-value */ 606 if (check == rvOnly || check == rvThenLookup) { 607 for (i = 0; i < numName; i++) { 608 if (caseInsens) 609 cmp = strcasecmp(item->name, name[i]); 610 else 611 cmp = strcmp(item->name, name[i]); 612 if (cmp == 0) { 613 if (nameVal[i].numVals <= 0) 614 break; 615 if (berstring == 0) { 616 val = cloneValue(&nameVal[i], 1); 617 } else if (yp2ldap && berstring[0] == 'a') { 618 val = cloneValue(&nameVal[i], 1); 619 } else { 620 val = berDecode(&nameVal[i], 621 berstring); 622 } 623 if (val != 0) { 624 val->repeat = item->repeat; 625 /* 626 * If value for nis+ column is 627 * passed with value, val is 628 * manipulated in cloneValue(). 629 * To decide whether there are 630 * enough nis+ column values 631 * for rule to produce a value, 632 * we need nis+ column values 633 * as well as nis_mapping_element 634 * from the rule. If we are here, 635 * it indicates that the 'val has 636 * an valid value for the column 637 * item-> name. So set 638 * NP_LDAP_MAP_SUCCESS 639 * to np_ldap-stat. 640 */ 641 642 if (np_ldap_stat != NULL) 643 *np_ldap_stat = 644 NP_LDAP_MAP_SUCCESS; 645 } 646 break; 647 } 648 } 649 } 650 651 /* Do a direct lookup ? */ 652 if (val == 0 && (check == rvThenLookup || check == lookupOnly)) { 653 if (item->type == mit_nisplus) { 654 val = lookupNisPlus(&item->searchSpec.obj, item->name, 655 rv); 656 } else if (item->type == mit_ldap) { 657 int err = 0; 658 __nis_search_triple_t triple; 659 char *baseDN; 660 661 /* 662 * If item->searchSpec.triple.base is NULL, or ends 663 * in a comma, append the current search base from 664 * the TSD (put there by an upper layer). 665 * 666 * Special case for N2L mode: 667 * if item->searchSpec.triple.base ends in a comma, 668 * the current domain Context is used. 669 */ 670 if (yp2ldap && item->searchSpec.triple.base && 671 strlen(item->searchSpec.triple.base) > 0) { 672 baseDN = __nisdb_get_tsd()->domainContext; 673 } else { 674 baseDN = __nisdb_get_tsd()->searchBase; 675 } 676 triple.base = appendBase(item->searchSpec.triple.base, 677 baseDN, &err, 0); 678 if (err == 0) { 679 triple.scope = item->searchSpec.triple.scope; 680 triple.attrs = item->searchSpec.triple.attrs; 681 triple.element = 682 item->searchSpec.triple.element; 683 val = lookupLDAP(&triple, item->name, rv, 0, 684 np_ldap_stat); 685 fromldap = '1'; 686 } else { 687 val = 0; 688 } 689 sfree(triple.base); 690 } 691 } 692 693 694 /* Special processing for NIS to LDAP mode */ 695 if (yp2ldap && val != 0) { 696 697 /* 698 * Escape special chars from dn before sending to DIT, 699 * provided val is not ldap-based 700 */ 701 if (fromldap == '\0' && __nisdb_get_tsd()->escapeFlag == '1') { 702 if (escapeSpecialChars(val) < 0) { 703 freeValue(val, 1); 704 return (0); 705 } 706 } else if (__nisdb_get_tsd()->escapeFlag == '2') { 707 /* Remove escape chars from data received from DIT */ 708 (void) removeEscapeChars(val); 709 } 710 711 /* 712 * Remove from 'val', any values obtained using 713 * the 'removespec' syntax 714 */ 715 716 /* Obtain exVal */ 717 if (item->exItem) 718 exVal = getMappingItemVal(item->exItem, native, rv, 719 berstring, NULL); 720 721 /* delete */ 722 if (exVal != 0) { 723 for (i = 0; i < val->numVals; ) { 724 for (j = 0; j < exVal->numVals; j++) { 725 if (sstrncmp(val->val[i].value, 726 exVal->val[j].value, 727 MAX(val->val[i].length, 728 exVal->val[j].length)) 729 == 0) 730 break; 731 } 732 if (j < exVal->numVals) { 733 sfree(val->val[i].value); 734 val->val[i].value = 0; 735 val->val[i].length = 0; 736 for (k = i; k < val->numVals - 1; k++) { 737 val->val[k] = val->val[k + 1]; 738 val->val[k + 1].value = 0; 739 val->val[k + 1].length = 0; 740 } 741 val->numVals--; 742 } else 743 i++; 744 } 745 746 freeValue(exVal, 1); 747 748 /* 749 * If val->numVals <= 0, then we have no val to 750 * return. So free up stuff. 751 */ 752 if (val->numVals <= 0) { 753 free(val->val); 754 val->val = 0; 755 free(val); 756 return (0); 757 } 758 } 759 } 760 761 return (val); 762 } 763 764 __nis_value_t * 765 getMappingFormat(__nis_mapping_format_t *f, __nis_rule_value_t *rv, 766 __nis_format_arg_t at, void *a, int *numArg) { 767 char *myself = "getMappingFormat"; 768 __nis_value_t *val = 0; 769 __nis_buffer_t b = {0, 0}; 770 int i; 771 772 if (f == 0) 773 return (0); 774 775 if (rv == 0) { 776 val = am(myself, sizeof (*val)); 777 if (val == 0) 778 return (0); 779 780 switch (f->type) { 781 case mmt_item: 782 bp2buf(myself, &b, "%%s"); 783 break; 784 case mmt_string: 785 bp2buf(myself, &b, "%s", NIL(f->match.string)); 786 break; 787 case mmt_single: 788 bp2buf(myself, &b, "["); 789 for (i = 0; i < f->match.single.numRange; i++) { 790 if (f->match.single.lo[i] == 791 f->match.single.hi[i]) 792 bp2buf(myself, &b, "%c", 793 f->match.single.lo[i]); 794 else 795 bp2buf(myself, &b, "%c-%c", 796 f->match.single.lo[i], 797 f->match.single.hi[i]); 798 } 799 bp2buf(myself, &b, "]"); 800 break; 801 case mmt_limit: 802 break; 803 case mmt_any: 804 bp2buf(myself, &b, "*"); 805 break; 806 case mmt_berstring: 807 bp2buf(myself, &b, "%s", NIL(f->match.berString)); 808 break; 809 case mmt_begin: 810 case mmt_end: 811 bp2buf(myself, &b, "\""); 812 break; 813 default: 814 bp2buf(myself, &b, "<unknown>"); 815 } 816 val->type = vt_string; 817 val->numVals = 1; 818 val->val = am(myself, sizeof (val->val[0])); 819 if (val->val == 0) { 820 sfree(val); 821 return (0); 822 } 823 val->val[0].value = b.buf; 824 val->val[0].length = b.len; 825 } else { 826 switch (f->type) { 827 case mmt_item: 828 case mmt_berstring: 829 if (a != 0) { 830 if (at == fa_item) { 831 val = getMappingItemVal( 832 (__nis_mapping_item_t *)a, 833 mit_any, rv, 834 (f->type == mmt_berstring) ? f->match.berString : 0, NULL); 835 if (numArg != 0) 836 (*numArg)++; 837 } else { 838 val = cloneValue( 839 (__nis_value_t *)a, 1); 840 if (numArg != 0) 841 (*numArg)++; 842 } 843 } 844 break; 845 case mmt_string: 846 val = am(myself, sizeof (*val)); 847 if (val == 0) 848 return (0); 849 val->type = vt_string; 850 val->numVals = 1; 851 val->val = am(myself, sizeof (val->val[0])); 852 if (val->val == 0) { 853 sfree(val); 854 return (0); 855 } 856 val->val[0].value = sdup(myself, T, f->match.string); 857 val->val[0].length = strlen(val->val[0].value); 858 break; 859 case mmt_single: 860 case mmt_limit: 861 case mmt_any: 862 case mmt_begin: 863 case mmt_end: 864 /* Not an error, so return an empty value */ 865 val = am(myself, sizeof (*val)); 866 if (val == 0) 867 return (0); 868 val->type = vt_string; 869 val->numVals = 0; 870 val->val = 0; 871 break; 872 default: 873 /* Do nothing */ 874 val = 0; 875 break; 876 } 877 } 878 return (val); 879 } 880 881 /* 882 * Used when evaluating an expression. Typically, the value of the 883 * expression so far will be kept in 'v1', and 'v2' is the value 884 * of the current component of the expression. In the general case, 885 * both will be multi-valued, and the result is an "explosion" 886 * resulting in N*M new values (if 'v1' had N values, and 'v2' 887 * M ditto). 888 * 889 * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"}, 890 * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl", 891 * "efgh", "efij", "efkl"}. 892 * 893 * There are special cases when v1->repeat and/or v2->repeat are set. 894 * Repeat mostly makes sense with single values; for example, if 895 * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result 896 * is {"x=1", "x=2", "x=3"}. 897 * 898 * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's 899 * not clear if there's a useful application for this, but the code's 900 * there for the sake of orthogonality. 901 */ 902 __nis_value_t * 903 explodeValues(__nis_value_t *v1, __nis_value_t *v2) { 904 int i1, i2, n, nv; 905 __nis_value_t *v; 906 __nis_buffer_t b = {0, 0}; 907 char *myself = "explodeValues"; 908 909 if (v1 == 0 || v1->numVals <= 0) 910 return (cloneValue(v2, 1)); 911 if (v2 == 0 || v2->numVals <= 0) 912 return (cloneValue(v1, 1)); 913 914 /* 915 * XXX What should we do if (v1->type != v2->type) ? 916 * Policy: Just explode anyway, even though the result is 917 * unlikely to be very useful. 918 */ 919 920 v = am(myself, sizeof (*v)); 921 if (v == 0) 922 return (0); 923 924 if (!v1->repeat && !v2->repeat) 925 nv = v1->numVals * v2->numVals; 926 else if (v1->repeat && !v2->repeat) 927 nv = v2->numVals; 928 else if (!v1->repeat && v2->repeat) 929 nv = v1->numVals; 930 else /* v1->repeat && v2->repeat */ 931 nv = 1; 932 933 v->val = am(myself, nv * sizeof (v->val[0])); 934 if (v->val == 0) { 935 free(v); 936 return (0); 937 } 938 939 /* 940 * Four different cases, depending on the 'repeat' flags. 941 */ 942 if (!v1->repeat && !v2->repeat) { 943 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) { 944 for (i2 = 0; i2 < v2->numVals; i2++) { 945 if (v1->type == vt_string) 946 sbc2buf(myself, v1->val[i1].value, 947 v1->val[i1].length, 948 &b); 949 else 950 bc2buf(myself, v1->val[i1].value, 951 v1->val[i1].length, 952 &b); 953 if (v2->type == vt_string) 954 sbc2buf(myself, v2->val[i2].value, 955 v2->val[i2].length, 956 &b); 957 else 958 bc2buf(myself, v2->val[i2].value, 959 v2->val[i2].length, 960 &b); 961 v->val[n].value = b.buf; 962 v->val[n].length = b.len; 963 n++; 964 b.buf = 0; 965 b.len = 0; 966 } 967 } 968 } else if (v1->repeat && !v2->repeat) { 969 for (i2 = 0; i2 < v2->numVals; i2++) { 970 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) { 971 if (v1->type == vt_string) 972 sbc2buf(myself, v1->val[i1].value, 973 v1->val[i1].length, 974 &b); 975 else 976 bc2buf(myself, v1->val[i1].value, 977 v1->val[i1].length, 978 &b); 979 if (v2->type == vt_string) 980 sbc2buf(myself, v2->val[i2].value, 981 v2->val[i2].length, 982 &b); 983 else 984 bc2buf(myself, v2->val[i2].value, 985 v2->val[i2].length, 986 &b); 987 } 988 v->val[n].value = b.buf; 989 v->val[n].length = b.len; 990 n++; 991 b.buf = 0; 992 b.len = 0; 993 } 994 } else if (!v1->repeat && v2->repeat) { 995 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) { 996 for (i2 = 0; i2 < v2->numVals; i2++) { 997 if (v1->type == vt_string) 998 sbc2buf(myself, v1->val[i1].value, 999 v1->val[i1].length, 1000 &b); 1001 else 1002 bc2buf(myself, v1->val[i1].value, 1003 v1->val[i1].length, 1004 &b); 1005 if (v2->type == vt_string) 1006 sbc2buf(myself, v2->val[i2].value, 1007 v2->val[i2].length, 1008 &b); 1009 else 1010 bc2buf(myself, v2->val[i2].value, 1011 v2->val[i2].length, 1012 &b); 1013 } 1014 v->val[n].value = b.buf; 1015 v->val[n].length = b.len; 1016 n++; 1017 b.buf = 0; 1018 b.len = 0; 1019 } 1020 } else { /* v1->repeat && v2->repeat */ 1021 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) { 1022 for (i2 = 0; i2 < v2->numVals; i2++) { 1023 if (v1->type == vt_string) 1024 sbc2buf(myself, v1->val[i1].value, 1025 v1->val[i1].length, 1026 &b); 1027 else 1028 bc2buf(myself, v1->val[i1].value, 1029 v1->val[i1].length, 1030 &b); 1031 if (v2->type == vt_string) 1032 sbc2buf(myself, v2->val[i2].value, 1033 v2->val[i2].length, 1034 &b); 1035 else 1036 bc2buf(myself, v2->val[i2].value, 1037 v2->val[i2].length, 1038 &b); 1039 } 1040 } 1041 v->val[n].value = b.buf; 1042 v->val[n].length = b.len; 1043 n++; 1044 b.buf = 0; 1045 b.len = 0; 1046 } 1047 1048 #ifdef NISDB_LDAP_DEBUG 1049 /* Sanity check */ 1050 if (n != nv) 1051 abort(); 1052 #endif /* NISD__LDAP_DEBUG */ 1053 1054 v->type = (v1->type == vt_string) ? 1055 ((v2->type == vt_string) ? 1056 vt_string : vt_ber) : vt_ber; 1057 v->repeat = 0; 1058 v->numVals = n; 1059 1060 return (v); 1061 } 1062 1063 __nis_value_t * 1064 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv, 1065 __nis_format_arg_t at, int numArgs, void *arg) { 1066 int i, ia = 0; 1067 __nis_value_t *val, *v = 0; 1068 bool_t moreFormat = (a != 0); 1069 bool_t moreArgs = (numArgs > 0); 1070 1071 while (moreFormat && (arg == 0 || ia < numArgs)) { 1072 for (i = 0; moreFormat; i++) { 1073 moreFormat = (a[i].type != mmt_end); 1074 if (at == fa_item) { 1075 __nis_mapping_item_t *item = arg; 1076 val = getMappingFormat(&a[i], rv, at, 1077 ((item != 0) ? &item[ia] : 0), &ia); 1078 } else { 1079 __nis_value_t **ival = arg; 1080 val = getMappingFormat(&a[i], rv, at, 1081 ((ival != 0) ? ival[ia] : 0), &ia); 1082 } 1083 if (val != 0) { 1084 __nis_value_t *new = explodeValues(v, val); 1085 1086 freeValue(v, 1); 1087 freeValue(val, 1); 1088 if (new == 0) 1089 return (0); 1090 1091 v = new; 1092 } else { 1093 freeValue(v, 1); 1094 return (0); 1095 } 1096 /* 1097 * If we run out of arguments, but still have format 1098 * remaining, repeat the last argument. Keep track of 1099 * the fact that we've really consumed all arguments. 1100 */ 1101 if (moreFormat &&