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 }