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