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 31 #include "nisdb_mt.h" 32 33 #include "ldap_util.h" 34 #include "ldap_val.h" 35 #include "ldap_attr.h" 36 #include "ldap_ldap.h" 37 #include "ldap_ruleval.h" 38 39 40 /* 41 * Free an array of 'count' rule-value elements. 42 */ 43 void 44 freeRuleValue(__nis_rule_value_t *rv, int count) { 45 int n, i, j; 46 47 if (rv == 0) 48 return; 49 50 for (n = 0; n < count; n++) { 51 52 if (rv[n].colName != 0) { 53 for (i = 0; i < rv[n].numColumns; i++) { 54 sfree(rv[n].colName[i]); 55 } 56 free(rv[n].colName); 57 } 58 if (rv[n].colVal != 0) { 59 for (i = 0; i < rv[n].numColumns; i++) { 60 for (j = 0; j < rv[n].colVal[i].numVals; j++) { 61 sfree(rv[n].colVal[i].val[j].value); 62 } 63 if (rv[n].colVal[i].numVals > 0) 64 sfree(rv[n].colVal[i].val); 65 } 66 free(rv[n].colVal); 67 } 68 69 if (rv[n].attrName != 0) { 70 for (i = 0; i < rv[n].numAttrs; i++) { 71 sfree(rv[n].attrName[i]); 72 } 73 free(rv[n].attrName); 74 } 75 if (rv[n].attrVal != 0) { 76 for (i = 0; i < rv[n].numAttrs; i++) { 77 for (j = 0; j < rv[n].attrVal[i].numVals; 78 j++) { 79 sfree(rv[n].attrVal[i].val[j].value); 80 } 81 if (rv[n].attrVal[i].numVals > 0) 82 sfree(rv[n].attrVal[i].val); 83 } 84 free(rv[n].attrVal); 85 } 86 87 } 88 sfree(rv); 89 } 90 91 /* 92 * Return an array of 'count' __nis_rule_value_t elements, initialized 93 * to be copies of 'rvIn' if supplied; empty otherwise. 94 */ 95 __nis_rule_value_t * 96 initRuleValue(int count, __nis_rule_value_t *rvIn) { 97 return (growRuleValue(0, count, 0, rvIn)); 98 } 99 100 static const __nis_rule_value_t rvZero = {0}; 101 102 /* 103 * Grow 'old' from 'oldCount' to 'newCount' elements, initialize the 104 * new portion to 'rvIn' (empty if not supplied), and return a pointer 105 * to the result. Following a call to this function, the caller must 106 * refer only to the returned array, not to 'old'. 107 */ 108 __nis_rule_value_t * 109 growRuleValue(int oldCount, int newCount, __nis_rule_value_t *old, 110 __nis_rule_value_t *rvIn) { 111 __nis_rule_value_t *rv; 112 int i, j; 113 char *myself = "growRuleValue"; 114 115 if (newCount <= 0 || newCount <= oldCount) 116 return (old); 117 118 if (oldCount <= 0) { 119 oldCount = 0; 120 old = 0; 121 } 122 123 if (rvIn == 0) 124 rvIn = (__nis_rule_value_t *)&rvZero; 125 126 rv = realloc(old, newCount * sizeof (rv[0])); 127 if (rv == 0) { 128 logmsg(MSG_NOMEM, LOG_ERR, 129 "%s: realloc(%d ((%d+%d)*%d)) => 0", 130 myself, (oldCount+newCount) * sizeof (rv[0]), 131 oldCount, newCount, sizeof (rv[0])); 132 freeRuleValue(old, oldCount); 133 return (0); 134 } 135 136 (void) memset(&rv[oldCount], 0, (newCount-oldCount)*sizeof (rv[0])); 137 138 for (i = oldCount; i < newCount; i++) { 139 rv[i].numColumns = rvIn->numColumns; 140 if (rv[i].numColumns > 0) { 141 rv[i].colName = cloneName(rvIn->colName, 142 rv[i].numColumns); 143 rv[i].colVal = cloneValue(rvIn->colVal, 144 rv[i].numColumns); 145 } 146 if (rv[i].numColumns > 0 && 147 (rv[i].colName == 0 || rv[i].colVal == 0)) { 148 freeRuleValue(rv, i); 149 return (0); 150 } 151 rv[i].numAttrs = rvIn->numAttrs; 152 rv[i].attrName = cloneName(rvIn->attrName, rv[i].numAttrs); 153 rv[i].attrVal = cloneValue(rvIn->attrVal, rv[i].numAttrs); 154 if (rv[i].numAttrs > 0 && 155 (rv[i].attrName == 0 || rv[i].attrVal == 0)) { 156 freeRuleValue(rv, i); 157 return (0); 158 } 159 } 160 161 return (rv); 162 } 163 164 /* 165 * Merge the source rule-value 's' into the target rule-value 't'. 166 * If successful, unless 's' is a sub-set of 't', 't' will be changed 167 * on exit, and will contain the values from 's' as well. 168 */ 169 int 170 mergeRuleValue(__nis_rule_value_t *t, __nis_rule_value_t *s) { 171 int i, j; 172 173 if (s == 0) 174 return (0); 175 else if (t == 0) 176 return (-1); 177 178 for (i = 0; i < s->numColumns; i++) { 179 for (j = 0; j < s->colVal[i].numVals; j++) { 180 if (addCol2RuleValue(s->colVal[i].type, s->colName[i], 181 s->colVal[i].val[j].value, 182 s->colVal[i].val[j].length, 183 t)) 184 return (-1); 185 } 186 } 187 188 for (i = 0; i < s->numAttrs; i++) { 189 for (j = 0; j < s->attrVal[i].numVals; j++) { 190 if (addAttr2RuleValue(s->attrVal[i].type, 191 s->attrName[i], 192 s->attrVal[i].val[j].value, 193 s->attrVal[i].val[j].length, 194 t)) 195 return (-1); 196 } 197 } 198 199 return (0); 200 } 201 202 static int 203 addVal2RuleValue(char *msg, int caseSens, int snipNul, __nis_value_type_t type, 204 char *name, void *value, int valueLen, 205 int *numP, char ***inNameP, __nis_value_t **inValP) { 206 int i, j, copyLen = valueLen; 207 __nis_single_value_t *v; 208 char **inName = *inNameP; 209 __nis_value_t *inVal = *inValP; 210 int num = *numP; 211 int (*comp)(const char *s1, const char *s2); 212 char *myself = "addVal2RuleValue"; 213 214 /* Internal function, so assume arguments OK */ 215 216 if (msg == 0) 217 msg = myself; 218 219 /* Should we match the 'inName' value case sensitive or not ? */ 220 if (caseSens) 221 comp = strcmp; 222 else 223 comp = strcasecmp; 224 225 /* 226 * String-valued NIS+ entries count the concluding NUL in the 227 * length, while LDAP entries don't. In order to support this, 228 * we implement the following for vt_string value types: 229 * 230 * If the last byte of the value isn't a NUL, add one to the 231 * allocated length, so that there always is a NUL after the 232 * value, making it safe to pass to strcmp() etc. 233 * 234 * If 'snipNul' is set (presumably meaning we're inserting a 235 * value derived from a NIS+ entry), and the last byte of the 236 * value already is a NUL, decrement the length to be copied by 237 * one. This (a) doesn't count the NUL in the value length, but 238 * (b) still leaves a NUL following the value. 239 * 240 * In N2L, for all cases we set 'copyLen' to the number of non-0 241 * characters in 'value'. 242 */ 243 if (type == vt_string && valueLen > 0) { 244 char *charval = value; 245 246 if (charval[valueLen-1] != '\0') 247 valueLen += 1; 248 else if (yp2ldap || snipNul) 249 copyLen -= 1; 250 } else if (valueLen == 0) { 251 /* 252 * If the 'value' pointer is non-NULL, we create a zero- 253 * length value with one byte allocated. This takes care 254 * of empty strings. 255 */ 256 valueLen += 1; 257 } 258 259 /* If we already have values for this attribute, add another one */ 260 for (i = 0; i < num; i++) { 261 if ((*comp)(inName[i], name) == 0) { 262 263 /* 264 * Our caller often doesn't know the type of the 265 * value; this happens because the type (vt_string 266 * or vt_ber) is determined by the format in the 267 * rule sets, and we may be invoked as a preparation 268 * for evaluating the rules. Hence, we only use the 269 * supplied 'type' if we need to create a value. 270 * Otherwise, we accept mixed types. 271 * 272 * Strings are OK in any case, since we always make 273 * sure to have a zero byte at the end of any value, 274 * whatever the type. 275 */ 276 277 if (inVal[i].numVals < 0) { 278 /* 279 * Used to indicate deletion of attribute, 280 * so we honor that and don't add a value. 281 */ 282 return (0); 283 } 284 285 /* 286 * If 'value' is NULL, we should delete, so 287 * remove any existing values, and set the 288 * 'numVals' field to -1. 289 */ 290 if (value == 0) { 291 for (j = 0; j < inVal[i].numVals; j++) { 292 sfree(inVal[i].val[j].value); 293 } 294 sfree(inVal[i].val); 295 inVal[i].val = 0; 296 inVal[i].numVals = -1; 297 return (0); 298 } 299 300 /* Is the value a duplicate ? */ 301 for (j = 0; j < inVal[i].numVals; j++) { 302 if (copyLen == inVal[i].val[j].length && 303 memcmp(value, inVal[i].val[j].value, 304 copyLen) == 0) { 305 break; 306 } 307 } 308 if (j < inVal[i].numVals) 309 return (0); 310 311 /* Not a duplicate, so add the name/value pair */ 312 v = realloc(inVal[i].val, 313 (inVal[i].numVals+1) * 314 sizeof (inVal[i].val[0])); 315 if (v == 0) 316 return (-1); 317 inVal[i].val = v; 318 v[inVal[i].numVals].length = copyLen; 319 v[inVal[i].numVals].value = am(msg, valueLen); 320 if (v[inVal[i].numVals].value == 0 && 321 value != 0) { 322 sfree(v); 323 return (-1); 324 } 325 memcpy(v[inVal[i].numVals].value, value, copyLen); 326 inVal[i].numVals++; 327 328 return (0); 329 } 330 } 331 332 /* No previous value for this attribute */ 333 334 /* 335 * value == 0 means deletion, in which case we create a 336 * __nis_value_t with the numVals field set to -1. 337 */ 338 if (value != 0) { 339 if ((v = am(msg, sizeof (*v))) == 0) 340 return (-1); 341 v->length = copyLen; 342 v->value = am(msg, valueLen); 343 if (v->value == 0 && value != 0) { 344 sfree(v); 345 return (-1); 346 } 347 memcpy(v->value, value, copyLen); 348 } 349 350 inVal = realloc(inVal, (num+1)*sizeof (inVal[0])); 351 if (inVal == 0) { 352 if (value != 0) { 353 sfree(v->value); 354 sfree(v); 355 } 356 return (-1); 357 } 358 *inValP = inVal; 359 360 inName = realloc(inName, 361 (num+1)*sizeof (inName[0])); 362 if (inName == 0 || (inName[num] = 363 sdup(msg, T, name)) == 0) { 364 sfree(v->value); 365 sfree(v); 366 return (-1); 367 } 368 *inNameP = inName; 369 370 inVal[num].type = type; 371 inVal[num].repeat = 0; 372 if (value != 0) { 373 inVal[num].numVals = 1; 374 inVal[num].val = v; 375 } else { 376 inVal[num].numVals = -1; 377 inVal[num].val = 0; 378 } 379 380 *numP += 1; 381 382 return (0); 383 } 384 385 int 386 addAttr2RuleValue(__nis_value_type_t type, char *name, void *value, 387 int valueLen, __nis_rule_value_t *rv) { 388 char *myself = "addAttr2RuleValue"; 389 390 if (name == 0 || rv == 0) 391 return (-1); 392 393 return (addVal2RuleValue(myself, 0, 0, type, name, value, valueLen, 394 &rv->numAttrs, &rv->attrName, &rv->attrVal)); 395 } 396 397 int 398 addSAttr2RuleValue(char *name, char *value, __nis_rule_value_t *rv) { 399 return (addAttr2RuleValue(vt_string, name, value, slen(value), rv)); 400 } 401 402 int 403 addCol2RuleValue(__nis_value_type_t type, char *name, void *value, 404 int valueLen, __nis_rule_value_t *rv) { 405 char *myself = "addCol2RuleValue"; 406 407 if (name == 0 || rv == 0) 408 return (-1); 409 410 return (addVal2RuleValue(myself, 1, 1, type, name, value, valueLen, 411 &rv->numColumns, &rv->colName, &rv->colVal)); 412 } 413 414 int 415 addSCol2RuleValue(char *name, char *value, __nis_rule_value_t *rv) { 416 return (addCol2RuleValue(vt_string, name, value, slen(value), rv)); 417 } 418 419 /* 420 * Given a table mapping, a NIS+ DB query, and (optionally) an existing 421 * and compatible __nis_rule_value_t, return a new __nis_rule_value_t 422 * with the values from the query added. 423 */ 424 __nis_rule_value_t * 425 buildNisPlusRuleValue(__nis_table_mapping_t *t, db_query *q, 426 __nis_rule_value_t *rv) { 427 int i; 428 __nis_single_value_t *sv; 429 char *myself = "buildNisPlusRuleValue"; 430 431 if (t == 0 || q == 0) 432 return (0); 433 434 rv = initRuleValue(1, rv); 435 if (rv == 0) 436 return (0); 437 438 for (i = 0; i < q->components.components_len; i++) { 439 int ic; 440 int iv, v, dup; 441 int len; 442 443 /* Ignore out-of-range column index */ 444 if (q->components.components_val[i].which_index >= 445 t->numColumns) 446 continue; 447 448 /* 449 * Add the query value. A NULL value indicates deletion, 450 * but addCol2RuleValue() takes care of that for us. 451 */ 452 if (addCol2RuleValue(vt_string, 453 t->column[q->components.components_val[i]. 454 which_index], 455 q->components.components_val[i].index_value-> 456 itemvalue.itemvalue_val, 457 q->components.components_val[i].index_value-> 458 itemvalue.itemvalue_len, rv) != 0) { 459 freeRuleValue(rv, 1); 460 rv = 0; 461 break; 462 } 463 } 464 465 return (rv); 466 } 467 468 469 /* 470 * Given a LHS rule 'rl', return an array containing the item names, 471 * and the number of elements in the array in '*numItems'. 472 * 473 * If there are 'me_match' __nis_mapping_element_t's, we use the 474 * supplied '*rval' (if any) to derive values for the items in 475 * the 'me_match', and add the values thus derived to '*rval' (in 476 * which case the '*rval' pointer will change; the old '*rval' 477 * is deleted). 478 */ 479 __nis_mapping_item_t * 480 buildLvalue(__nis_mapping_rlhs_t *rl, __nis_value_t **rval, int *numItems) { 481 __nis_value_t *val, *r; 482 __nis_mapping_item_t *item = 0; 483 int i, n, ni = 0, nv = 0; 484 int repeat = 0; 485 486 if (rl == 0) 487 return (0); 488 489 if (rval != 0) { 490 r = *rval; 491 repeat = r->repeat; 492 } else 493 r = 0; 494 495 /* If there is more than one element, we concatenate the items */ 496 for (i = 0; i < rl->numElements; i++) { 497 __nis_mapping_element_t *e = &rl->element[i]; 498 __nis_mapping_item_t *olditem, *tmpitem = 0; 499 __nis_value_t **tmp; 500 501 switch (e->type) { 502 case me_item: 503 tmpitem = cloneItem(&e->element.item); 504 break; 505 case me_match: 506 /* 507 * Obtain values for the items in the 'me_match' 508 * element. 509 */ 510 tmp = matchMappingItem(e->element.match.fmt, r, &nv, 511 0, 0); 512 if (tmp != 0) { 513 freeValue(r, 1); 514 val = 0; 515 for (n = 0; n < nv; n++) { 516 r = concatenateValues(val, tmp[n]); 517 freeValue(val, 1); 518 freeValue(tmp[n], 1); 519 val = r; 520 if (val == 0) { 521 for (n++; n < nv; n++) { 522 freeValue(tmp[n], 1); 523 } 524 break; 525 } 526 } 527 free(tmp); 528 if (rval != 0) { 529 if (repeat && val != 0) 530 val->repeat = repeat; 531 *rval = val; 532 } 533 for (n = 0; n < e->element.match.numItems; 534 n++) { 535 olditem = item; 536 item = concatenateMappingItem(item, ni, 537 &e->element.match.item[n]); 538 freeMappingItem(olditem, ni); 539 if (item == 0) { 540 ni = 0; 541 break; 542 } 543 ni++; 544 } 545 } 546 break; 547 case me_print: 548 case me_split: 549 case me_extract: 550 default: 551 /* These shouldn't show up on the LHS; ignore */ 552 break; 553 } 554 555 if (tmpitem != 0) { 556 olditem = item; 557 item = concatenateMappingItem(item, ni, tmpitem); 558 freeMappingItem(olditem, ni); 559 freeMappingItem(tmpitem, 1); 560 ni++; 561 if (item == 0) { 562 ni = 0; 563 break; 564 } 565 } 566 } 567 568 if (numItems != 0) 569 *numItems = ni; 570 571 return (item); 572 } 573 574 __nis_value_t * 575 buildRvalue(__nis_mapping_rlhs_t *rl, __nis_mapping_item_type_t native, 576 __nis_rule_value_t *rv, int *stat) { 577 __nis_value_t *val, *vold = 0, *vnew; 578 int i; 579 char *myself = "buildRvalue"; 580 581 if (rl == 0 || rl->numElements <= 0) { 582 /* 583 * No RHS indicates deletion, as does a __nis_value_t 584 * with numVals == -1, so we return such a creature. 585 */ 586 val = am(myself, sizeof (*val)); 587 if (val != 0) { 588 val->type = vt_string; 589 val->numVals = -1; 590 } 591 return (val); 592 } 593 594 /* If there is more than one element, we concatenate the values */ 595 for (i = 0; i < rl->numElements; i++) { 596 vnew = getMappingElement(&rl->element[i], native, rv, stat); 597 val = concatenateValues(vold, vnew); 598 freeValue(vnew, 1); 599 freeValue(vold, 1); 600 vold = val; 601 } 602 return (val); 603 } 604 605 /* 606 * Derive values for the LDAP attributes specified by the rule 'r', 607 * and add them to the rule-value 'rv'. 608 * 609 * If 'doAssign' is set, out-of-context assignments are performed, 610 * otherwise not. 611 */ 612 __nis_rule_value_t * 613 addLdapRuleValue(__nis_table_mapping_t *t, 614 __nis_mapping_rule_t *r, 615 __nis_mapping_item_type_t lnative, 616 __nis_mapping_item_type_t rnative, 617 __nis_rule_value_t *rv, 618 int doAssign, int *stat) { 619 int i, j; 620 char **new; 621 __nis_value_t *rval, *lval; 622 __nis_buffer_t b = {0, 0}; 623 __nis_mapping_item_t *litem; 624 int numItems; 625 char **dn = 0; 626 int numDN = 0; 627 char *myself = "addLdapRuleValue"; 628 629 630 /* Do we have the required values ? */ 631 if (rv == 0) 632 return (0); 633 634 /* 635 * Establish appropriate search base. For rnative == mit_nisplus, 636 * we're deriving LDAP attribute values from NIS+ columns; in other 637 * words, we're writing to LDAP, and should use the write.base value. 638 */ 639 __nisdb_get_tsd()->searchBase = (rnative == mit_nisplus) ? 640 t->objectDN->write.base : t->objectDN->read.base; 641 642 /* Set escapeFlag if LHS is "dn" to escape special chars */ 643 if (yp2ldap && r->lhs.numElements == 1 && 644 r->lhs.element->type == me_item && 645 r->lhs.element->element.item.type == mit_ldap && 646 strcasecmp(r->lhs.element->element.item.name, "dn") == 0) { 647 __nisdb_get_tsd()->escapeFlag = '1'; 648 } 649 650 /* Build the RHS value */ 651 rval = buildRvalue(&r->rhs, rnative, rv, stat); 652 653 /* Reset escapeFlag */ 654 __nisdb_get_tsd()->escapeFlag = '\0'; 655 656 if (rval == 0) 657 return (rv); 658 659 /* 660 * Special case: If we got no value for the RHS (presumably because 661 * we're missing one or more item values), we don't produce an lval. 662 * Note that this isn't the same thing as an empty value, which we 663 * faithfully try to transmit to LDAP. 664 */ 665 if (rval->numVals == 1 && rval->val[0].value == 0) { 666 freeValue(rval, 1); 667 return (rv); 668 } 669 670 /* Obtain the LHS item names */ 671 litem = buildLvalue(&r->lhs, &rval, &numItems); 672 if (litem == 0) { 673 freeValue(rval, 1); 674 return (rv); 675 } 676 677 /* Get string representations of the LHS item names */ 678 lval = 0; 679 for (i = 0; i < numItems; i++) { 680 __nis_value_t *tmpval, *old; 681 682 tmpval = getMappingItem(&litem[i], lnative, 0, 0, NULL); 683 684 /* 685 * If the LHS item is out-of-context, we do the 686 * assignment right here. 687 */ 688 if (doAssign && litem[i].type == mit_ldap && 689 litem[i].searchSpec.triple.scope != 690 LDAP_SCOPE_UNKNOWN && 691 slen(litem[i].searchSpec.triple.base) > 0 && 692 (slen(litem[i].searchSpec.triple.attrs) > 0 || 693 litem[i].searchSpec.triple.element != 0)) { 694 int stat; 695 696 if (dn == 0) 697 dn = findDNs(myself, rv, 1, 698 t->objectDN->write.base, 699 &numDN); 700 701 stat = storeLDAP(&litem[i], i, numItems, rval, 702 t->objectDN, dn, numDN); 703 if (stat != LDAP_SUCCESS) { 704 char *iname = "<unknown>"; 705 706 if (tmpval != 0 && 707 tmpval->numVals == 1) 708 iname = tmpval->val[0].value; 709 logmsg(MSG_NOTIMECHECK, LOG_ERR, 710 "%s: LDAP store \"%s\": %s", 711 myself, iname, 712 ldap_err2string(stat)); 713 } 714 715 freeValue(tmpval, 1); 716 continue; 717 } 718 719 old = lval; 720 lval = concatenateValues(old, tmpval); 721 freeValue(tmpval, 1); 722 freeValue(old, 1); 723 } 724 725 /* Don't need the LHS items themselves anymore */ 726 freeMappingItem(litem, numItems); 727 728 /* 729 * If we don't have an 'lval' (probably because all litem[i]:s 730 * were out-of-context assignments), we're done. 731 */ 732 if (lval == 0 || lval->numVals <= 0) { 733 freeValue(lval, 1); 734 freeValue(rval, 1); 735 return (rv); 736 } 737 738 for (i = 0, j = 0; i < lval->numVals; i++) { 739 /* Special case: rval->numVals < 0 means deletion */ 740 if (rval->numVals < 0) { 741 (void) addAttr2RuleValue(rval->type, 742 lval->val[i].value, 0, 0, rv); 743 continue; 744 } 745 /* If we're out of values, repeat the last one */ 746 if (j >= rval->numVals) 747 j = (rval->numVals > 0) ? rval->numVals-1 : 0; 748 for (0; j < rval->numVals; j++) { 749 /* 750 * If this is the 'dn', and the value ends in a 751 * comma, append the appropriate search base. 752 */ 753 if (strcasecmp("dn", lval->val[i].value) == 0 && 754 lastChar(&rval->val[j]) == ',' && 755 t->objectDN->write.scope != 756 LDAP_SCOPE_UNKNOWN) { 757 void *nval; 758 int nlen = -1; 759 760 nval = appendString2SingleVal( 761 t->objectDN->write.base, &rval->val[j], 762 &nlen); 763 if (nval != 0 && nlen >= 0) { 764 sfree(rval->val[j].value); 765 rval->val[j].value = nval; 766 rval->val[j].length = nlen; 767 } 768 } 769 (void) addAttr2RuleValue(rval->type, 770 lval->val[i].value, rval->val[j].value, 771 rval->val[j].length, rv); 772 /* 773 * If the lval is multi-valued, go on to the 774 * other values; otherwise, quit (but increment 775 * the 'rval' value index). 776 */ 777 if (!lval->repeat) { 778 j++; 779 break; 780 } 781 } 782 } 783 784 /* Clean up */ 785 freeValue(lval, 1); 786 freeValue(rval, 1); 787 788 return (rv); 789 } 790 791 /* 792 * Remove the indicated attribute, and any values for it, from the 793 * rule-value. 794 */ 795 void 796 delAttrFromRuleValue(__nis_rule_value_t *rv, char *attrName) { 797 int i; 798 799 if (rv == 0 || attrName == 0) 800 return; 801 802 for (i = 0; i < rv->numAttrs; i++) { 803 if (strcasecmp(attrName, rv->attrName[i]) == 0) { 804 int j; 805 806 for (j = 0; j < rv->attrVal[i].numVals; j++) 807 sfree(rv->attrVal[i].val[j].value); 808 if (rv->attrVal[i].numVals > 0) 809 sfree(rv->attrVal[i].val); 810 811 sfree(rv->attrName[i]); 812 813 /* Move up the rest of the attribute names/values */ 814 for (j = i+1; j < rv->numAttrs; j++) { 815 rv->attrName[j-1] = rv->attrName[j]; 816 rv->attrVal[j-1] = rv->attrVal[j]; 817 } 818 819 rv->numAttrs -= 1; 820 821 break; 822 } 823 } 824 } 825 826 /* 827 * Remove the indicated column, and any values for it, from the 828 * rule-value. 829 */ 830 void 831 delColFromRuleValue(__nis_rule_value_t *rv, char *colName) { 832 int i; 833 834 if (rv == 0 || colName == 0) 835 return; 836 837 for (i = 0; i < rv->numColumns; i++) { 838 if (strcmp(colName, rv->colName[i]) == 0) { 839 int j; 840 841 for (j = 0; j < rv->colVal[i].numVals; j++) 842 sfree(rv->colVal[i].val[j].value); 843 if (rv->colVal[i].numVals > 0) 844 sfree(rv->colVal[i].val); 845 846 sfree(rv->colName[i]); 847 848 /* Move up the rest of the column names/values */ 849 for (j = i+1; j < rv->numColumns; j++) { 850 rv->colName[j-1] = rv->colName[j]; 851 rv->colVal[j-1] = rv->colVal[j]; 852 } 853 854 rv->numColumns -= 1; 855 856 break; 857 } 858 } 859 } 860 861 /* 862 * Add the write-mode object classes specified by 'objClassAttrs' to the 863 * rule-value 'rv'. 864 * If there's an error, 'rv' is deleted, and NULL returned. 865 */ 866 __nis_rule_value_t * 867 addObjectClasses(__nis_rule_value_t *rv, char *objClassAttrs) { 868 char *filter = 0, **fc = 0; 869 int i, nfc = 0; 870 871 /* 872 * Expect to only use this for existing rule-values, so rv == 0 is 873 * an error. 874 */ 875 if (rv == 0) 876 return (0); 877 878 /* 879 * If 'objClassAttrs' is NULL, we trivially have nothing to do. 880 * Assume the caller knows what it's doing, and return success. 881 */ 882 if (objClassAttrs == 0) 883 return (rv); 884 885 /* 886 * Make an AND-filter of the object classes, and split into 887 * components. (Yes, this is a bit round-about, but leverages 888 * existing functions.) 889 */ 890 filter = makeFilter(objClassAttrs); 891 if (filter == 0) { 892 freeRuleValue(rv, 1); 893 return (0); 894 } 895 896 fc = makeFilterComp(filter, &nfc); 897 if (fc == 0 || nfc <= 0) { 898 free(filter); 899 freeRuleValue(rv, 1); 900 return (0); 901 } 902 903 /* Add the objectClass attributes to the rule-value */ 904 for (i = 0; i < nfc; i++) { 905 char *name, *value; 906 907 name = fc[i]; 908 /* Skip if not of the "name=value" form */ 909 if ((value = strchr(name, '=')) == 0) 910 continue; 911 912 *value = '\0'; 913 value++; 914 915 /* Skip if the attribute name isn't "objectClass" */ 916 if (strcasecmp("objectClass", name) != 0) 917 continue; 918 919 if (addSAttr2RuleValue(name, value, rv) != 0) { 920 free(filter); 921 freeFilterComp(fc, nfc); 922 freeRuleValue(rv, 1); 923 return (0); 924 } 925 } 926 927 free(filter); 928 freeFilterComp(fc, nfc); 929 930 return (rv); 931 } 932 933 934 static char * 935 valString(__nis_value_t *val) { 936 int i; 937 938 if (val == 0 || val->type != vt_string) 939 return (0); 940 941 for (i = 0; i < val->numVals; i++) { 942 /* Look for a non-NULL, non-zero length value */ 943 if (val->val[i].value != 0 && val->val[i].length > 0) { 944 char *v = val->val[i].value; 945 946 /* 947 * Check that there's a NUL at the end. True, 948 * if there isn't, we may be looking beyond 949 * allocated memory. However, we would have done 950 * so in any case when the supposed string was 951 * traversed (printed, etc.), very possibly by 952 * a lot more than one byte. So, it's better to 953 * take a small risk here than a large one later. 954 */ 955 if (v[val->val[i].length-1] == '\0' || 956 v[val->val[i].length] == '\0') 957 return (v); 958 } 959 } 960 961 return (0); 962 } 963 964 char * 965 findVal(char *name, __nis_rule_value_t *rv, __nis_mapping_item_type_t type) { 966 int i; 967 968 if (type == mit_nisplus) { 969 for (i = 0; i < rv->numColumns; i++) { 970 if (rv->colName[i] == 0) 971 continue; 972 if (strcmp(name, rv->colName[i]) == 0) { 973 return (valString(&rv->colVal[i])); 974 } 975 } 976 } else if (type == mit_ldap) { 977 for (i = 0; i < rv->numAttrs; i++) { 978 if (rv->attrName[i] == 0) 979 continue; 980 if (strcasecmp(name, rv->attrName[i]) == 0) { 981 return (valString(&rv->attrVal[i])); 982 } 983 } 984 } 985 986 return (0); 987 } 988 989 static char *norv = "<NIL>"; 990 static char *unknown = "<unknown>"; 991 992 /* 993 * Attempt to derive a string identifying the rule-value 'rv'. The 994 * returned string is a pointer, either into 'rv', or to static 995 * storage, and must not be freed. 996 */ 997 char * 998 rvId(__nis_rule_value_t *rv, __nis_mapping_item_type_t type) { 999 char *v; 1000 1001 if (rv == 0) 1002 return (norv); 1003 1004 if (rv->numColumns > 0 && type == mit_nisplus) { 1005 /* 1006 * Look for a column called "cname" or "name". 1007 * If that fails, try "key" or "alias". 1008 */ 1009 if ((v = findVal("cname", rv, type)) != 0) 1010 return (v); 1011 else if ((v = findVal("name", rv, type)) != 0) 1012 return (v); 1013 else if ((v = findVal("key", rv, type)) != 0) 1014 return (v); 1015 else if ((v = findVal("alias", rv, type)) != 0) 1016 return (v); 1017 } else if (rv->numAttrs > 0 && type == mit_ldap) { 1018 /* 1019 * Look for "dn", or "cn". 1020 */ 1021 if ((v = findVal("dn", rv, type)) != 0) 1022 return (v); 1023 else if ((v = findVal("cn", rv, type)) != 0) 1024 return (v); 1025 } 1026 1027 return (unknown); 1028 } 1029 1030 /* 1031 * Merge the rule-values with the same DN into one. Each rule-value 1032 * in the returned array will have unique 'dn'. On entry, *numVals 1033 * contains the number of rule-values in 'rv'. On exit, it contains 1034 * the number of rule-values in the returned array or -1 on error. 1035 */ 1036 __nis_rule_value_t * 1037 mergeRuleValueWithSameDN(__nis_rule_value_t *rv, int *numVals) { 1038 __nis_rule_value_t *rvq = 0; 1039 char *dn, *odn; 1040 int count = 0; 1041 int i, j; 1042 1043 if (numVals == 0) 1044 return (0); 1045 1046 for (i = 0; i < *numVals; i++) { 1047 if ((dn = findVal("dn", &rv[i], mit_ldap)) != 0) { 1048 for (j = 0; j < count; j++) { 1049 if ((odn = findVal("dn", &rvq[j], 1050 mit_ldap)) != 0) { 1051 /* case sensitive compare */ 1052 if (strcmp(dn, odn) != 0) 1053 continue; 1054 if (mergeRuleValue(&rvq[j], 1055 &rv[i]) == -1) { 1056 freeRuleValue(rvq, count); 1057 *numVals = -1; 1058 return (0); 1059 } 1060 break; 1061 } else { 1062 freeRuleValue(rvq, count); 1063 *numVals = -1; 1064 return (0); 1065 } 1066 } 1067 /* if no match, then add it to the rulevalue array */ 1068 if (j == count) { 1069 rvq = growRuleValue(count, count + 1, rvq, 1070 &rv[i]); 1071 if (rvq == 0) { 1072 *numVals = -1; 1073 return (0); 1074 } 1075 count++; 1076 } 1077 } 1078 } 1079 1080 *numVals = count; 1081 return (rvq); 1082 } 1083