1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <strings.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <errno.h> 33 #include <stdio.h> 34 #include <rpcsvc/nis.h> 35 #include <rpc/xdr.h> 36 37 #include "ldap_util.h" 38 #include "ldap_attr.h" 39 #include "ldap_ruleval.h" 40 #include "ldap_op.h" 41 #include "ldap_map.h" 42 #include "ldap_nisplus.h" 43 #include "ldap_glob.h" 44 #include "ldap_xdr.h" 45 #include "ldap_val.h" 46 47 /* From yptol/dit_access_utils.h */ 48 #define N2LKEY "rf_key" 49 #define N2LIPKEY "rf_ipkey" 50 51 __nis_hash_table_mt ldapMappingList = NIS_HASH_TABLE_MT_INIT; 52 extern int yp2ldap; 53 54 55 int 56 setColumnNames(__nis_table_mapping_t *t) { 57 int i, j, nic, noc, stat; 58 char **col; 59 zotypes type; 60 char *myself = "setColumnNames"; 61 62 if (t == 0) 63 return (0); 64 65 type = t->objType; 66 col = t->column; 67 nic = (col != 0) ? t->numColumns : -1; 68 69 t->objType = NIS_BOGUS_OBJ; 70 t->obj = 0; 71 72 stat = initializeColumnNames(t->objName, &t->column, &t->numColumns, 73 &t->objType, &t->obj); 74 if (stat == LDAP_OBJECT_CLASS_VIOLATION) { 75 /* Not a table object; that's OK */ 76 sfree(col); 77 return (0); 78 } else if (justTesting && stat != LDAP_SUCCESS) { 79 /* 80 * Restore the parser initialization. This will only work 81 * correctly if the config file is consistent in the ordering 82 * of column names, and either no NIS+ lookups are needed, 83 * or the ordering is the same as in NIS+. 84 */ 85 t->column = col; 86 t->numColumns = nic; 87 /* Make a guess at the object type, based on the name */ 88 if (strstr(t->objName, ".org_dir") != 0) 89 t->objType = NIS_TABLE_OBJ; 90 else if (strncmp(t->objName, "admin.groups_dir", 91 sizeof ("admin.groups_dir")) != 0) 92 t->objType = NIS_GROUP_OBJ; 93 else 94 t->objType = NIS_DIRECTORY_OBJ; 95 return (0); 96 } 97 98 /* 99 * If it's a table object, but there are no translation rules, 100 * this mapping is for the table object itself. In that case, 101 * we throw away the column names (if any). 102 */ 103 if (t->objType == NIS_TABLE_OBJ && t->numRulesFromLDAP == 0 && 104 t->numRulesToLDAP == 0) { 105 for (i = 0; i < t->numColumns; i++) 106 sfree(t->column[i]); 107 sfree(t->column); 108 t->column = 0; 109 t->numColumns = 0; 110 noc = 0; 111 } 112 113 /* 114 * Verify that all column names found by the parser 115 * are present in the actual column list. 116 */ 117 if (verbose) { 118 for (i = 0, noc = 0; i < nic; i++) { 119 int found = 0; 120 121 if (col[i] == 0) 122 continue; 123 /* Skip the 'zo_*' special column names */ 124 if (isObjAttrString(col[i])) 125 continue; 126 for (j = 0; j < t->numColumns; j++) { 127 if (strcmp(col[i], t->column[j]) == 0) { 128 noc++; 129 found = 1; 130 break; 131 } 132 } 133 if (!found) { 134 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 135 "%s: No column \"%s\" in \"%s\"", 136 myself, NIL(col[i]), NIL(t->objName)); 137 } 138 } 139 } 140 141 /* Remove any setup by the parser */ 142 for (i = 0; i < nic; i++) { 143 sfree(col[i]); 144 } 145 sfree(col); 146 147 return (0); 148 } 149 150 void 151 freeSingleObjAttr(__nis_obj_attr_t *attr) { 152 if (attr == 0) 153 return; 154 155 sfree(attr->zo_owner); 156 sfree(attr->zo_group); 157 sfree(attr->zo_domain); 158 sfree(attr); 159 } 160 161 void 162 freeObjAttr(__nis_obj_attr_t **attr, int numAttr) { 163 int i; 164 165 if (attr == 0) 166 return; 167 168 for (i = 0; i < numAttr; i++) { 169 freeSingleObjAttr(attr[i]); 170 } 171 172 sfree(attr); 173 } 174 175 __nis_obj_attr_t * 176 cloneObjAttr(__nis_obj_attr_t *old) { 177 __nis_obj_attr_t *new; 178 char *myself = "cloneObjAttr"; 179 180 if (old == 0) 181 return (0); 182 183 new = am(myself, sizeof (*new)); 184 if (new == 0) 185 return (0); 186 187 new->zo_owner = sdup(myself, T, old->zo_owner); 188 if (new->zo_owner == 0 && old->zo_owner != 0) 189 goto cleanup; 190 191 new->zo_group = sdup(myself, T, old->zo_group); 192 if (new->zo_group == 0 && old->zo_group != 0) 193 goto cleanup; 194 195 new->zo_domain = sdup(myself, T, old->zo_domain); 196 if (new->zo_domain == 0 && old->zo_domain != 0) 197 goto cleanup; 198 199 new->zo_access = old->zo_access; 200 new->zo_ttl = old->zo_ttl; 201 202 return (new); 203 204 cleanup: 205 freeSingleObjAttr(new); 206 207 return (0); 208 } 209 210 211 /* 212 * Obtain NIS+ entries (in the form of db_query's) from the supplied table 213 * mapping and db_query. 214 * 215 * If 'qin' is NULL, enumeration is desired. 216 * 217 * On exit, '*numQueries' contains the number of (db_query *)'s in the 218 * return array, '*ldapStat' the LDAP operation status, and '*objAttr' 219 * a pointer to an array (of '*numQueries elements) of object attributes 220 * (zo_owner, etc.). If no object attributes were retrieved, '*objAttr' 221 * is NULL; any and all of the (*objAttr)[i]'s may be NULL. 222 */ 223 db_query ** 224 mapFromLDAP(__nis_table_mapping_t *t, db_query *qin, int *numQueries, 225 char *dbId, int *ldapStat, __nis_obj_attr_t ***objAttr) { 226 __nis_table_mapping_t **tp; 227 db_query **q; 228 __nis_rule_value_t *rv; 229 __nis_ldap_search_t *ls; 230 int n, numVals, numMatches = 0; 231 int stat; 232 __nis_obj_attr_t **attr; 233 char *myself = "mapFromLDAP"; 234 235 if (ldapStat == 0) 236 ldapStat = &stat; 237 238 if (t == 0 || numQueries == 0) { 239 *ldapStat = LDAP_PARAM_ERROR; 240 return (0); 241 } 242 243 /* Select the correct table mapping(s) */ 244 tp = selectTableMapping(t, qin, 0, 0, dbId, &numMatches); 245 if (tp == 0 || numMatches <= 0) { 246 /* 247 * Not really an error; just no matching mapping 248 * for the query. 249 */ 250 *ldapStat = LDAP_SUCCESS; 251 return (0); 252 } 253 254 q = 0; 255 attr = 0; 256 257 /* For each mapping */ 258 for (numVals = 0, n = 0; n < numMatches; n++) { 259 db_query **qt; 260 int i, nqt = 0, filterOnQin, res = 0; 261 262 t = tp[n]; 263 264 if (qin != 0) { 265 rv = buildNisPlusRuleValue(t, qin, 0); 266 if (rv != 0) { 267 /* 268 * Depending on the value of res, we shall 269 * proceed to next table mapping. 270 */ 271 ls = createLdapRequest(t, rv, 0, 1, &res, NULL); 272 } 273 else 274 ls = 0; 275 } else { 276 /* Build enumeration request */ 277 rv = 0; 278 ls = createLdapRequest(t, 0, 0, 1, NULL, NULL); 279 } 280 281 freeRuleValue(rv, 1); 282 283 if (ls == 0) { 284 /* 285 * if the res is NP_LDAP_RULES_NO_VALUE, that means we 286 * have enough NIS+ columns for the rules to produce 287 * values, but none of them did, so continue to the 288 * next table mapping. Otherwise do cleanup and return 289 * error. 290 */ 291 if (res == NP_LDAP_RULES_NO_VALUE) 292 continue; 293 for (i = 0; i < numVals; i++) 294 freeQuery(q[i]); 295 sfree(q); 296 free(tp); 297 *ldapStat = LDAP_OPERATIONS_ERROR; 298 return (0); 299 } 300 301 /* Query LDAP */ 302 nqt = (ls->isDN || qin != 0) ? 0 : -1; 303 rv = ldapSearch(ls, &nqt, 0, ldapStat); 304 305 /* 306 * If qin != 0, then we need to make sure that the 307 * LDAP search is filtered so that only entries that 308 * are compatible with 'qin' are retained. This will 309 * happen automatically if we do a DN search (in which 310 * case, no need to filter on 'qin'). 311 */ 312 if (ls->isDN || qin == 0) 313 filterOnQin = 0; 314 else 315 filterOnQin = 1; 316 317 freeLdapSearch(ls); 318 319 /* Convert rule-values to db_query's */ 320 if (rv != 0 && nqt > 0) { 321 int nrv = nqt; 322 __nis_obj_attr_t **at = 0; 323 324 qt = ruleValue2Query(t, rv, 325 (filterOnQin) ? qin : 0, &at, &nqt); 326 freeRuleValue(rv, nrv); 327 328 if (qt != 0 && q == 0) { 329 q = qt; 330 attr = at; 331 numVals = nqt; 332 } else if (qt != 0) { 333 db_query **tmp; 334 __nis_obj_attr_t **atmp; 335 336 /* Extend the 'q' array */ 337 tmp = realloc(q, 338 (numVals+nqt) * sizeof (q[0])); 339 /* ... and the 'attr' array */ 340 atmp = realloc(attr, 341 (numVals+nqt) * sizeof (attr[0])); 342 if (tmp == 0 || atmp == 0) { 343 logmsg(MSG_NOMEM, LOG_ERR, 344 "%s: realloc(%d) => NULL", 345 myself, 346 (numVals+nqt) * sizeof (q[0])); 347 for (i = 0; i < numVals; i++) 348 freeQuery(q[i]); 349 for (i = 0; i < nqt; i++) 350 freeQuery(qt[i]); 351 sfree(tmp); 352 sfree(atmp); 353 sfree(q); 354 sfree(qt); 355 sfree(tp); 356 freeObjAttr(at, nqt); 357 freeObjAttr(attr, numVals); 358 *ldapStat = LDAP_NO_MEMORY; 359 return (0); 360 } 361 q = tmp; 362 attr = atmp; 363 /* Add the results for this 't' */ 364 (void) memcpy(&q[numVals], qt, 365 nqt * sizeof (qt[0])); 366 (void) memcpy(&attr[numVals], at, 367 nqt * sizeof (at[0])); 368 numVals += nqt; 369 370 sfree(qt); 371 sfree(at); 372 } 373 } 374 } 375 376 *numQueries = numVals; 377 if (objAttr != 0) 378 *objAttr = attr; 379 else 380 freeObjAttr(attr, numVals); 381 sfree(tp); 382 383 return (q); 384 } 385 386 /* 387 * Add the object attributes (zo_owner, etc.) to the rule-value 'rv'. 388 * Returns a pointer to the (possibly newly allocated) rule-value, 389 * or NULL in case of failure. If not returning 'rvIn', the latter 390 * will have been freed. 391 */ 392 __nis_rule_value_t * 393 addObjAttr2RuleValue(nis_object *obj, __nis_rule_value_t *rvIn) { 394 __nis_rule_value_t *rv; 395 char abuf[2 * sizeof (obj->zo_access) + 1]; 396 char tbuf[2 * sizeof (obj->zo_ttl) + 1]; 397 398 if (obj == 0) 399 return (0); 400 401 if (rvIn != 0) { 402 rv = rvIn; 403 } else { 404 rv = initRuleValue(1, 0); 405 if (rv == 0) 406 return (0); 407 } 408 409 if (obj->zo_owner != 0) { 410 if (addSCol2RuleValue("zo_owner", obj->zo_owner, rv) != 0) { 411 freeRuleValue(rv, 1); 412 return (0); 413 } 414 } 415 416 if (obj->zo_group != 0) { 417 if (addSCol2RuleValue("zo_group", obj->zo_group, rv) != 0) { 418 freeRuleValue(rv, 1); 419 return (0); 420 } 421 } 422 423 if (obj->zo_domain != 0) { 424 if (addSCol2RuleValue("zo_domain", obj->zo_domain, rv) != 0) { 425 freeRuleValue(rv, 1); 426 return (0); 427 } 428 } 429 430 (void) memset(abuf, 0, sizeof (abuf)); 431 (void) memset(tbuf, 0, sizeof (tbuf)); 432 433 sprintf(abuf, "%x", obj->zo_access); 434 sprintf(tbuf, "%x", obj->zo_ttl); 435 436 if (addSCol2RuleValue("zo_access", abuf, rv) != 0) { 437 freeRuleValue(rv, 1); 438 return (0); 439 } 440 if (addSCol2RuleValue("zo_ttl", tbuf, rv) != 0) { 441 freeRuleValue(rv, 1); 442 return (0); 443 } 444 445 return (rv); 446 } 447 448 /* 449 * Returns a pointer to (NOT a copy of) the value for the specified 450 * column 'col' in the rule-value 'rv'. 451 */ 452 __nis_value_t * 453 findColValue(char *col, __nis_rule_value_t *rv) { 454 int i; 455 456 if (col == 0 || rv == 0 || rv->numColumns <= 0) 457 return (0); 458 459 for (i = 0; i < rv->numColumns; i++) { 460 if (strcmp(col, rv->colName[i]) == 0) 461 return (&rv->colVal[i]); 462 } 463 464 return (0); 465 } 466 467 /* 468 * Return the NIS+ object attributes (if any) in the rule-value 'rv'. 469 */ 470 __nis_obj_attr_t * 471 ruleValue2ObjAttr(__nis_rule_value_t *rv) { 472 __nis_obj_attr_t *attr; 473 __nis_value_t *val; 474 char *myself = "ruleValue2ObjAttr"; 475 476 if (rv == 0 || rv->numColumns <= 0) 477 return (0); 478 479 attr = am(myself, sizeof (*attr)); 480 481 if ((val = findColValue("zo_owner", rv)) != 0 && 482 val->type == vt_string && val->numVals == 1 && 483 val->val[0].value != 0) { 484 attr->zo_owner = sdup(myself, T, val->val[0].value); 485 if (attr->zo_owner == 0) { 486 freeSingleObjAttr(attr); 487 return (0); 488 } 489 } 490 491 if ((val = findColValue("zo_group", rv)) != 0 && 492 val->type == vt_string && val->numVals == 1 && 493 val->val[0].value != 0) { 494 attr->zo_group = sdup(myself, T, val->val[0].value); 495 if (attr->zo_group == 0) { 496 freeSingleObjAttr(attr); 497 return (0); 498 } 499 } 500 501 if ((val = findColValue("zo_domain", rv)) != 0 && 502 val->type == vt_string && val->numVals == 1 && 503 val->val[0].value != 0) { 504 attr->zo_domain = sdup(myself, T, val->val[0].value); 505 if (attr->zo_domain == 0) { 506 freeSingleObjAttr(attr); 507 return (0); 508 } 509 } 510 511 if ((val = findColValue("zo_access", rv)) != 0 && 512 val->type == vt_string && val->numVals == 1 && 513 val->val[0].value != 0) { 514 if (sscanf(val->val[0].value, "%x", &attr->zo_access) != 1) { 515 freeSingleObjAttr(attr); 516 return (0); 517 } 518 } 519 520 if ((val = findColValue("zo_ttl", rv)) != 0 && 521 val->type == vt_string && val->numVals == 1 && 522 val->val[0].value != 0) { 523 if (sscanf(val->val[0].value, "%x", &attr->zo_ttl) != 1) { 524 freeSingleObjAttr(attr); 525 return (0); 526 } 527 } 528 529 return (attr); 530 } 531 532 /* 533 * If the supplied string is one of the object attributes, return one. 534 * Otherwise, return zero. 535 */ 536 int 537 isObjAttrString(char *str) { 538 if (str == 0) 539 return (0); 540 541 if (strcmp("zo_owner", str) == 0 || 542 strcmp("zo_group", str) == 0 || 543 strcmp("zo_domain", str) == 0 || 544 strcmp("zo_access", str) == 0 || 545 strcmp("zo_ttl", str) == 0) 546 return (1); 547 else 548 return (0); 549 } 550 551 552 /* 553 * If the supplied value is one of the object attribute strings, return 554 * a pointer to the string. Otherwise, return NULL. 555 */ 556 char * 557 isObjAttr(__nis_single_value_t *val) { 558 if (val == 0 || val->length <= 0 || val->value == 0) 559 return (0); 560 561 if (isObjAttrString(val->value)) 562 return (val->value); 563 else 564 return (0); 565 } 566 567 int 568 setObjAttrField(char *attrName, __nis_single_value_t *val, 569 __nis_obj_attr_t **objAttr) { 570 __nis_obj_attr_t *attr; 571 char *myself = "setObjAttrField"; 572 573 if (attrName == 0 || val == 0 || objAttr == 0 || 574 val->value == 0 || val->length <= 0) 575 return (-1); 576 577 if (*objAttr != 0) { 578 attr = *objAttr; 579 } else { 580 attr = am(myself, sizeof (*attr)); 581 if (attr == 0) 582 return (-2); 583 *objAttr = attr; 584 } 585 586 if (strcmp("zo_owner", attrName) == 0) { 587 if (attr->zo_owner == 0) { 588 attr->zo_owner = sdup(myself, T, val->value); 589 if (attr->zo_owner == 0) 590 return (-11); 591 } 592 } else if (strcmp("zo_group", attrName) == 0) { 593 if (attr->zo_group == 0) { 594 attr->zo_group = sdup(myself, T, val->value); 595 if (attr->zo_group == 0) 596 return (-12); 597 } 598 } else if (strcmp("zo_domain", attrName) == 0) { 599 if (attr->zo_domain == 0) { 600 attr->zo_domain = sdup(myself, T, val->value); 601 if (attr->zo_domain == 0) 602 return (-13); 603 } 604 } else if (strcmp("zo_access", attrName) == 0) { 605 if (attr->zo_access == 0) { 606 if (sscanf(val->value, "%x", &attr->zo_access) != 1) 607 return (-14); 608 } 609 } else if (strcmp("zo_ttl", attrName) == 0) { 610 if (attr->zo_ttl == 0) { 611 if (sscanf(val->value, "%x", &attr->zo_ttl) != 1) 612 return (-15); 613 } 614 } 615 616 return (0); 617 } 618 619 /* 620 * Return a DN and rule-value for the supplied mapping, db_query's, and 621 * input rule-value. This function only works on a single mapping. See 622 * mapToLDAP() below for a description of the action depending on the 623 * values of 'old' and 'new'. 624 * 625 * If both 'old' and 'new' are supplied, and the modify would result 626 * in a change to the DN, '*oldDN' will contain the old DN. Otherwise 627 * (and normally), '*oldDN' will be NULL. 628 */ 629 char * 630 map1qToLDAP(__nis_table_mapping_t *t, db_query *old, db_query *new, 631 __nis_rule_value_t *rvIn, __nis_rule_value_t **rvOutP, 632 char **oldDnP) { 633 634 __nis_rule_value_t *rv, *rvt; 635 __nis_ldap_search_t *ls; 636 char *dn = 0, *oldDn = 0; 637 __nis_table_mapping_t del; 638 char *myself = "map1qToLDAP"; 639 640 if (t == 0 || (old == 0 && new == 0) || rvOutP == 0) 641 return (0); 642 643 /* 644 * If entry should be deleted, we look at the delete 645 * policy in the table mapping. Should it specify a 646 * rule set, we use that rule set to build a rule- 647 * value, and the delete actually becomes a modify 648 * operation. 649 */ 650 if (old != 0 && new == 0) { 651 if (t->objectDN->delDisp == dd_perDbId) { 652 /* 653 * The functions that build a rule-value from a 654 * rule set expect a __nis_table_mapping_t, but the 655 * rule set in the __nis_object_dn_t isn't of that 656 * form. So, build a pseudo-__nis_table_mapping_t that 657 * borrows heavily from 't'. 658 */ 659 del = *t; 660 661 del.numRulesToLDAP = del.objectDN->numDbIds; 662 del.ruleToLDAP = del.objectDN->dbId; 663 664 /* 665 * Do a modify with the pseudo-table 666 * mapping, and the 'old' db_query 667 * supplying input to the delete rule 668 * set. 669 */ 670 t = &del; 671 new = old; 672 } else if (t->objectDN->delDisp == dd_always) { 673 674 /* Nothing to do here; all handled below */ 675 676 } else if (t->objectDN->delDisp == dd_never) { 677 678 return (0); 679 680 } else { 681 682 logmsg(MSG_INVALIDDELDISP, LOG_WARNING, 683 "%s: Invalid delete disposition %d for \"%s\"", 684 myself, t->objectDN->delDisp, 685 NIL(t->dbId)); 686 return (0); 687 688 } 689 } 690 691 /* Make a copy of the input rule-value */ 692 if (rvIn != 0) { 693 rv = initRuleValue(1, rvIn); 694 if (rv == 0) 695 return (0); 696 } else { 697 rv = 0; 698 } 699 700 /* First get a rule-value from the supplied NIS+ entry. */ 701 rvt = rv; 702 rv = buildNisPlusRuleValue(t, ((old != 0) ? old : new), rvt); 703 freeRuleValue(rvt, 1); 704 if (rv == 0) { 705 logmsg(MSG_NORULEVALUE, LOG_WARNING, 706 "%s: No in-query rule-value derived for \"%s\"", 707 myself, NIL(t->dbId)); 708 return (0); 709 } 710 711 /* 712 * Create a request (really only care about the DN) from the 713 * supplied NIS+ entry data. 714 */ 715 ls = createLdapRequest(t, rv, &dn, 0, NULL, NULL); 716 if (ls == 0 || dn == 0) { 717 logmsg(MSG_NOTIMECHECK, LOG_ERR, 718 "%s: Unable to create LDAP request for %s: %s", 719 myself, NIL(t->dbId), 720 (dn != 0) ? dn : rvId(rv, mit_nisplus)); 721 sfree(dn); 722 freeLdapSearch(ls); 723 freeRuleValue(rv, 1); 724 return (0); 725 } 726 727 freeLdapSearch(ls); 728 729 if (new != 0) { 730 /* 731 * Create a rule-value from the new NIS+ entry. 732 * Don't want to mix in the rule-value derived 733 * from 'old', so delete it. However, we still 734 * want the owner, group, etc., from 'rvIn'. 735 */ 736 if (old != 0) { 737 freeRuleValue(rv, 1); 738 if (rvIn != 0) { 739 rv = initRuleValue(1, rvIn); 740 if (rv == 0) { 741 sfree(dn); 742 return (0); 743 } 744 } else { 745 rv = 0; 746 } 747 } 748 rvt = rv; 749 rv = buildNisPlusRuleValue(t, new, rvt); 750 freeRuleValue(rvt, 1); 751 if (rv == 0) { 752 logmsg(MSG_NORULEVALUE, LOG_WARNING, 753 "%s: No new rule-value derived for \"%s: %s\"", 754 myself, NIL(t->dbId), dn); 755 sfree(dn); 756 return (0); 757 } 758 /* 759 * Check if the proposed modification would result in a 760 * a change to the DN. 761 */ 762 if (old != 0) { 763 oldDn = dn; 764 dn = 0; 765 ls = createLdapRequest(t, rv, &dn, 0, NULL, NULL); 766 if (ls == 0 || dn == 0) { 767 logmsg(MSG_NOTIMECHECK, LOG_ERR, 768 "%s: Unable to create new DN for \"%s: %s\"", 769 myself, NIL(t->dbId), oldDn); 770 sfree(oldDn); 771 freeLdapSearch(ls); 772 freeRuleValue(rv, 1); 773 return (0); 774 } 775 freeLdapSearch(ls); 776 if (strcasecmp(oldDn, dn) == 0) { 777 sfree(oldDn); 778 oldDn = 0; 779 } 780 } 781 } 782 783 784 *rvOutP = rv; 785 if (oldDnP != 0) 786 *oldDnP = oldDn; 787 788 return (dn); 789 } 790 791 /* 792 * Since the DN hash list is an automatic variable, there's no need for 793 * locking, and we remove the locking overhead by using the libnsl 794 * hash functions. 795 */ 796 #undef NIS_HASH_ITEM 797 #undef NIS_HASH_TABLE 798 #undef nis_insert_item 799 #undef nis_find_item 800 #undef nis_pop_item 801 #undef nis_remove_item 802 803 typedef struct { 804 NIS_HASH_ITEM item; 805 int index; 806 char *oldDn; 807 } __dn_item_t; 808 809 /* 810 * Update LDAP per the supplied table mapping and db_query's. 811 * 812 * 'nq' is the number of elements in the 'old', 'new', and 'rvIn' 813 * arrays. mapToLDAP() generally performs one update for each 814 * element; however, if one or more of the individual queries 815 * produce the same DN, they're merged into a single update. 816 * 817 * There are four cases, depending on the values of 'old[iq]' and 818 * 'new[iq]': 819 * 820 * (1) old[iq] == 0 && new[iq] == 0 821 * No action; skip to next query 822 * 823 * (2) old[iq] == 0 && new[iq] != 0 824 * Attempt to use the 'new' db_query to get a DN, and try to create 825 * the corresponding LDAP entry. 826 * 827 * (3) old[iq] != 0 && new[iq] == 0 828 * Use the 'old' db_query to get a DN, and try to delete the LDAP 829 * entry per the table mapping. 830 * 831 * (4) old[iq] != 0 && new[iq] != 0 832 * Use the 'old' db_query to get a DN, and update (possibly create) 833 * the corresponding LDAP entry per the 'new' db_query. 834 * 835 * If 'rvIn' is non-NULL, it is expected to contain the object attributes 836 * (zo_owner, etc.) to be written to LDAP. 'rvIn' is an array with 'nq' 837 * elements. 838 * 839 * If 'firstOnly' is set, only the first old[iq]/new[iq] pair is used 840 * to perform the actual update. Any additional queries specified will 841 * have their values folded in, but are not used to derive update targets. 842 * This mode is inteded to support the case where multiple NIS+ entries 843 * map to one and the same LDAP entry. Note that 'rvIn' must still be 844 * an array of 'nq' elements, though if 'firstOnly' is set, it should be 845 * OK to leave all but 'rvIn[0]' empty. 846 * 847 * 'dbId' is used to further narow down the selection of mapping candidates 848 * to those matching the 'dbId' value. 849 */ 850 int 851 mapToLDAP(__nis_table_mapping_t *tm, int nq, db_query **old, db_query **new, 852 __nis_rule_value_t *rvIn, int firstOnly, char *dbId) { 853 __nis_table_mapping_t **tp, **tpa; 854 int i, n, rnq, iq, r, ret = LDAP_SUCCESS; 855 int maxMatches, numMatches = 0; 856 __nis_ldap_search_t *ls; 857 char **dn = 0, **odn = 0; 858 __nis_rule_value_t **rv; 859 NIS_HASH_TABLE dntab; 860 __dn_item_t *dni; 861 char *myself = "mapToLDAP"; 862 863 864 if (tm == 0 || (old == 0 && new == 0) || nq <= 0) 865 return (LDAP_PARAM_ERROR); 866 867 /* Determine maximum number of table mapping matches */ 868 if (nq == 1) { 869 tp = selectTableMapping(tm, 870 (old != 0 && old[0] != 0) ? old[0] : new[0], 1, 0, 871 dbId, &maxMatches); 872 numMatches = maxMatches; 873 } else { 874 tp = selectTableMapping(tm, 0, 1, 0, dbId, &maxMatches); 875 } 876 877 /* 878 * If no matching mapping, we're not mapping to LDAP in this 879 * particular case. 880 */ 881 if (tp == 0 || maxMatches == 0) { 882 sfree(tp); 883 return (LDAP_SUCCESS); 884 } 885 886 /* 887 * Allocate the 'rv', 'dn', and 'tpa' arrays. Worst case is that 888 * we need nq * maxMatches elements in each array. However, if 889 * 'firstOnly' is set, we only need one element per matching 890 * mapping in each. 891 */ 892 dn = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (dn[0])); 893 odn = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (odn[0])); 894 rv = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (rv[0])); 895 tpa = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (tpa[0])); 896 if (dn == 0 || odn == 0 || rv == 0 || tpa == 0) { 897 sfree(tp); 898 sfree(dn); 899 sfree(odn); 900 sfree(rv); 901 sfree(tpa); 902 return (LDAP_NO_MEMORY); 903 } 904 905 /* Unless nq == 1, we don't need the 'tp' value */ 906 if (nq != 1) 907 sfree(tp); 908 909 logmsg(MSG_NOTIMECHECK, 910 #ifdef NISDB_LDAP_DEBUG 911 LOG_WARNING, 912 #else 913 LOG_INFO, 914 #endif /* NISDB_LDAP_DEBUG */ 915 "%s: %s: %d * %d potential updates", 916 myself, NIL(tm->objName), nq, maxMatches); 917 918 (void) memset(&dntab, 0, sizeof (dntab)); 919 920 /* 921 * Create DNs, column and attribute values, and merge duplicate DNs. 922 */ 923 for (iq = 0, rnq = 0; iq < nq; iq++) { 924 int idx; 925 926 if ((old == 0 || old[iq] == 0) && 927 (new == 0 || new[iq] == 0)) 928 continue; 929 930 /* 931 * Select matching table mappings; if nq == 1, we've already 932 * got the 'tp' array from above. We expect this to be the 933 * most common case, so it's worth special treatment. 934 */ 935 if (nq != 1) 936 tp = selectTableMapping(tm, 937 (old != 0 && old[iq] != 0) ? old[iq] : new[iq], 1, 0, 938 dbId, &numMatches); 939 if (tp == 0) 940 continue; 941 else if (numMatches <= 0) { 942 sfree(tp); 943 continue; 944 } 945 946 idx = iq * maxMatches; 947 948 if (idx == 0 || !firstOnly) 949 (void) memcpy(&tpa[idx], tp, 950 numMatches * sizeof (tpa[idx])); 951 952 for (n = 0; n < numMatches; n++) { 953 char *dnt, *odnt; 954 __nis_rule_value_t *rvt = 0; 955 956 if (tp[n] == 0) 957 continue; 958 959 dnt = map1qToLDAP(tp[n], 960 (old != 0) ? old[iq] : 0, 961 (new != 0) ? new[iq] : 0, 962 (rvIn != 0) ? &rvIn[iq] : 0, 963 &rvt, &odnt); 964 965 if (dnt == 0) 966 continue; 967 if (rvt == 0) { 968 #ifdef NISDB_LDAP_DEBUG 969 abort(); 970 #else 971 sfree(dnt); 972 sfree(odnt); 973 continue; 974 #endif /* NISDB_LDAP_DEBUG */ 975 } 976 977 /* 978 * Create a request to get a rule-value with 979 * NIS+ data translated to LDAP equivalents. 980 */ 981 ls = createLdapRequest(tp[n], rvt, 0, 0, NULL, NULL); 982 if (ls == 0) { 983 if (ret == LDAP_SUCCESS) 984 ret = LDAP_OPERATIONS_ERROR; 985 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 986 "%s: Unable to map to LDAP attrs for %s:dn=%s", 987 myself, NIL(tp[n]->dbId), dnt); 988 sfree(dnt); 989 freeRuleValue(rvt, 1); 990 continue; 991 } 992 freeLdapSearch(ls); 993 994 /* 995 * If the DN is the same as one we already know 996 * about, merge the rule-values. 997 */ 998 999 dni = (__dn_item_t *)nis_find_item(dnt, &dntab); 1000 if (dni != 0) { 1001 i = dni->index; 1002 1003 if (i >= (firstOnly ? ((idx < maxMatches) ? 1004 idx : maxMatches) : idx)) { 1005 goto update_cleanup; 1006 } 1007 1008 if (odnt != 0 && (dni->oldDn == 0 || 1009 strcasecmp(odnt, dni->oldDn) != 1010 0)) { 1011 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1012 "%s: DN mismatch while merging updates: %s: %s != %s", 1013 myself, NIL(tpa[i]->dbId), 1014 NIL(odnt), NIL(dni->oldDn)); 1015 goto update_cleanup; 1016 } 1017 1018 if (mergeRuleValue(rv[i], rvt)) { 1019 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1020 "%s: Error merging updates for %s:dn=%s", 1021 myself, NIL(tpa[i]->dbId), 1022 dn[i]); 1023 if ((dni = (__dn_item_t *) 1024 nis_remove_item(dnt, &dntab)) != 1025 0) { 1026 i = dni->index; 1027 sfree(dn[i]); 1028 dn[i] = 0; 1029 tpa[i] = 0; 1030 freeRuleValue(rv[i], 1); 1031 rv[i] = 0; 1032 sfree(dni); 1033 } 1034 goto update_cleanup; 1035 } 1036 update_cleanup: 1037 sfree(dnt); 1038 dnt = 0; 1039 sfree(odnt); 1040 odnt = 0; 1041 freeRuleValue(rvt, 1); 1042 rvt = 0; 1043 } else if ((iq == 0 || !firstOnly) && dnt != 0) { 1044 dni = am(myself, sizeof (*dni)); 1045 if (dni != 0) { 1046 dni->item.name = dnt; 1047 dni->index = idx + n; 1048 dni->oldDn = odnt; 1049 } else { 1050 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1051 "%s: Skipping update for dn=\"%s\"", 1052 myself, dnt); 1053 sfree(dnt); 1054 dnt = 0; 1055 } 1056 if (dni != 0 && 1057 nis_insert_item((NIS_HASH_ITEM *)dni, 1058 &dntab) != 1) { 1059 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1060 "%s: Unable to memorize dn=\"%s\"", 1061 myself, dnt); 1062 sfree(dnt); 1063 dnt = 0; 1064 sfree(odnt); 1065 odnt = 0; 1066 } 1067 if (dnt != 0) { 1068 dn[idx+n] = dnt; 1069 odn[idx+n] = odnt; 1070 rv[idx+n] = rvt; 1071 rnq++; 1072 } else { 1073 freeRuleValue(rvt, 1); 1074 rvt = 0; 1075 } 1076 } else if (dnt != 0) { 1077 sfree(dnt); 1078 sfree(odnt); 1079 freeRuleValue(rvt, 1); 1080 } 1081 } 1082 sfree(tp); 1083 } 1084 1085 /* Done with the dntab */ 1086 while ((dni = (__dn_item_t *)nis_pop_item(&dntab)) != 0) { 1087 sfree(dni); 1088 } 1089 1090 logmsg(MSG_NOTIMECHECK, 1091 #ifdef NISDB_LDAP_DEBUG 1092 LOG_WARNING, 1093 #else 1094 LOG_INFO, 1095 #endif /* NISDB_LDAP_DEBUG */ 1096 "%s: %s: %d update%s requested", 1097 myself, NIL(tm->objName), rnq, rnq != 1 ? "s" : ""); 1098 1099 /* Perform the updates */ 1100 for (i = rnq = 0; i < (firstOnly ? maxMatches : nq*maxMatches); i++) { 1101 int delPerDbId; 1102 1103 if (dn[i] == 0) 1104 continue; 1105 1106 #ifdef NISDB_LDAP_DEBUG 1107 logmsg(MSG_NOTIMECHECK, LOG_INFO, 1108 "%s: %s %s:dn=%s", 1109 myself, 1110 (new != 0 && new[i/maxMatches] != 0) ? 1111 "modify" : "delete", 1112 NIL(tpa[i]->dbId), dn[i]); 1113 #endif /* NISDB_LDAP_DEBUG */ 1114 1115 delPerDbId = (tpa[i]->objectDN->delDisp == dd_perDbId); 1116 if ((new != 0 && new[i/maxMatches] != 0) || delPerDbId) { 1117 /* 1118 * Try to modify/create the specified DN. First, 1119 * however, if the update changes the DN, make 1120 * that change. 1121 */ 1122 if (odn[i] == 0 || (r = ldapChangeDN(odn[i], dn[i])) == 1123 LDAP_SUCCESS) { 1124 int addFirst; 1125 1126 addFirst = (new != 0 && 1127 new[i/maxMatches] != 0 && 1128 !delPerDbId); 1129 r = ldapModify(dn[i], rv[i], 1130 tpa[i]->objectDN->write.attrs, 1131 addFirst); 1132 } 1133 } else { 1134 /* Try to delete the specified DN */ 1135 r = ldapModify(dn[i], 0, 1136 tpa[i]->objectDN->write.attrs, 0); 1137 } 1138 1139 if (r == LDAP_SUCCESS) { 1140 rnq++; 1141 } else { 1142 if (ret == LDAP_SUCCESS) 1143 ret = r; 1144 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1145 "%s: LDAP %s request error %d for %s:dn=%s", 1146 myself, 1147 (new != 0 && new[i/maxMatches] != 0) ? 1148 "modify" : "delete", 1149 r, NIL(tpa[i]->dbId), dn[i]); 1150 } 1151 1152 sfree(dn[i]); 1153 dn[i] = 0; 1154 freeRuleValue(rv[i], 1); 1155 rv[i] = 0; 1156 } 1157 1158 sfree(dn); 1159 sfree(odn); 1160 sfree(rv); 1161 sfree(tpa); 1162 1163 logmsg(MSG_NOTIMECHECK, 1164 #ifdef NISDB_LDAP_DEBUG 1165 LOG_WARNING, 1166 #else 1167 LOG_INFO, 1168 #endif /* NISDB_LDAP_DEBUG */ 1169 "%s: %s: %d update%s performed", 1170 myself, NIL(tm->objName), rnq, rnq != 1 ? "s" : ""); 1171 1172 return (ret); 1173 } 1174 1175 /* 1176 * In nis+2ldap, check if the query 'q' matches the selector index 'x->index'. 1177 * 1178 * In nis2ldap, if 'name' is provided then check if its value in 'val' 1179 * matches the selector index. If 'name' is NULL, then check if rule-value 'rv' 1180 * matches the index. 1181 * To match the selector index, all fieldspecs in the indexlist should match 1182 * (AND). In nis2ldap, an exception is, if there are multiple fieldspecs with 1183 * the same fieldname then only one of them needs to match (OR). 1184 * Example: 1185 * Indexlist = [host="H*", host="I*", user="U*", domain="D*"] 1186 * Then, 1187 * host = "H1", user="U1", domain="D1" ==> pass 1188 * host = "I1", user="U1", domain="D1" ==> pass 1189 * host = "X1", user="U1", domain="D1" ==> fail 1190 * host = "H1", user="X1", domain="D1" ==> fail 1191 * host = "H1", user="U1" ==> fail 1192 * 1193 * Return 1 in case of a match, 0 otherwise. 1194 */ 1195 int 1196 verifyIndexMatch(__nis_table_mapping_t *x, db_query *q, 1197 __nis_rule_value_t *rv, char *name, char *val) { 1198 int i, j, k, match = 1; 1199 char *myself = "verifyIndexMatch"; 1200 1201 /* 1202 * The pass and fail arrays are used by N2L to keep track of 1203 * index matches. This saves us from having matches in a 1204 * nested loop to decide OR or AND. 1205 */ 1206 int ppos, fpos; 1207 char **pass, **fail; 1208 1209 if (x == 0) 1210 return (0); 1211 1212 /* Trivial match */ 1213 if (x->index.numIndexes <= 0 || (!yp2ldap && q == 0)) 1214 return (1); 1215 1216 if (yp2ldap) { 1217 if (!(pass = am(myself, x->index.numIndexes * sizeof (char *)))) 1218 return (0); 1219 if (!(fail = am(myself, 1220 x->index.numIndexes * sizeof (char *)))) { 1221 sfree(pass); 1222 return (0); 1223 } 1224 ppos = fpos = 0; 1225 } 1226 1227 /* Check each index */ 1228 for (i = 0; i < x->index.numIndexes; i++) { 1229 int len = 0; 1230 char *value = 0; 1231 1232 /* Skip NULL index names */ 1233 if (x->index.name[i] == 0) 1234 continue; 1235 1236 /* Check N2L values */ 1237 if (yp2ldap) { 1238 if (name) { 1239 if (strcasecmp(x->index.name[i], name) == 0) 1240 value = val; 1241 else 1242 continue; 1243 } else if (rv) { 1244 if (strcasecmp(x->index.name[i], N2LKEY) == 0 || 1245 strcasecmp(x->index.name[i], N2LIPKEY) 1246 == 0) 1247 continue; 1248 value = findVal(x->index.name[i], rv, 1249 mit_nisplus); 1250 } 1251 1252 if (value && verifyMappingMatch(x->index.value[i], 1253 value)) 1254 pass[ppos++] = x->index.name[i]; 1255 else 1256 fail[fpos++] = x->index.name[i]; 1257 continue; 1258 } 1259 1260 /* If here, means nis+2ldap */ 1261 1262 /* Is the index name a known column ? */ 1263 for (j = 0; j < x->numColumns; j++) { 1264 if (strcmp(x->index.name[i], x->column[j]) == 0) { 1265 /* 1266 * Do we have a value for the column ? 1267 */ 1268 for (k = 0; k < q->components.components_len; 1269 k++) { 1270 if (q->components.components_val[k]. 1271 which_index == j) { 1272 value = q->components. 1273 components_val[k]. 1274 index_value-> 1275 itemvalue. 1276 itemvalue_val; 1277 len = q->components. 1278 components_val[k]. 1279 index_value-> 1280 itemvalue. 1281 itemvalue_len; 1282 break; 1283 } 1284 } 1285 if (value != 0) 1286 break; 1287 } 1288 } 1289 1290 /* 1291 * If we found a value, check if it matches the 1292 * format. If no value found or no match, this 1293 * mapping is _not_ an alternative. Otherwise, 1294 * we continue checking any other indexes. 1295 */ 1296 if (value == 0 || 1297 !verifyMappingMatch(x->index.value[i], 1298 value)) { 1299 match = 0; 1300 break; 1301 } 1302 } 1303 1304 if (yp2ldap) { 1305 for (--fpos; fpos >= 0; fpos--) { 1306 for (i = 0; i < ppos; i++) { 1307 if (strcmp(pass[i], fail[fpos]) == 0) 1308 break; 1309 } 1310 if (i == ppos) { 1311 match = 0; 1312 break; 1313 } 1314 } 1315 sfree(pass); 1316 sfree(fail); 1317 } 1318 1319 return (match); 1320 } 1321 1322 /* 1323 * Return all table mappings that match the column values in 'q'. 1324 * If there's no match, return those alternative mappings that don't 1325 * have an index; if no such mapping exists, return NULL. 1326 * 1327 * If 'wantWrite' is set, we want mappings for writing (i.e., data 1328 * to LDAP); otherwise, we want mappings for reading. 1329 * 1330 * If 'wantObj' is set, we want object mappings only (i.e., _not_ 1331 * those used to map entries in tables). 1332 * 1333 * If 'dbId' is non-NULL, we select mappings with a matching dbId field. 1334 */ 1335 __nis_table_mapping_t ** 1336 selectTableMapping(__nis_table_mapping_t *t, db_query *q, 1337 int wantWrite, int wantObj, char *dbId, 1338 int *numMatches) { 1339 __nis_table_mapping_t *r, *x, **tp; 1340 int i, j, k, nm, numap; 1341 char *myself = "selectTableMapping"; 1342 1343 if (numMatches == 0) 1344 numMatches = &nm; 1345 1346 /* 1347 * Count the number of possible mappings, so that we can 1348 * allocate the 'tp' array up front. 1349 */ 1350 for (numap = 0, x = t; x != 0; numap++, x = x->next); 1351 1352 if (numap == 0) { 1353 *numMatches = 0; 1354 return (0); 1355 } 1356 1357 tp = am(myself, numap * sizeof (tp[0])); 1358 if (tp == 0) { 1359 *numMatches = -1; 1360 return (0); 1361 } 1362 1363 /* 1364 * Special cases: 1365 * 1366 * q == 0 trivially matches any 't' of the correct object type 1367 * 1368 * wantObj != 0 means we ignore 'q' 1369 */ 1370 if (q == 0 || wantObj) { 1371 for (i = 0, x = t, nm = 0; i < numap; i++, x = x->next) { 1372 if (x->objectDN == 0) 1373 continue; 1374 if (wantWrite) { 1375 if (x->objectDN->write.scope == 1376 LDAP_SCOPE_UNKNOWN) 1377 continue; 1378 } else { 1379 if (x->objectDN->read.scope == 1380 LDAP_SCOPE_UNKNOWN) 1381 continue; 1382 } 1383 if (wantObj) { 1384 if (x->numColumns > 0) 1385 continue; 1386 } else { 1387 if (x->numColumns <= 0) 1388 continue; 1389 } 1390 if (dbId != 0 && x->dbId != 0 && 1391 strcmp(dbId, x->dbId) != 0) 1392 continue; 1393 tp[nm] = x; 1394 nm++; 1395 } 1396 *numMatches = nm; 1397 if (nm == 0) { 1398 sfree(tp); 1399 tp = 0; 1400 } 1401 return (tp); 1402 } 1403 1404 /* Scan all mappings, and collect candidates */ 1405 for (nm = 0, r = 0, x = t; x != 0; x = x->next) { 1406 if (x->objectDN == 0) 1407 continue; 1408 if (wantWrite) { 1409 if (x->objectDN->write.scope == LDAP_SCOPE_UNKNOWN) 1410 continue; 1411 } else { 1412 if (x->objectDN->read.scope == LDAP_SCOPE_UNKNOWN) 1413 continue; 1414 } 1415 /* Only want table/entry mappings */ 1416 if (x->numColumns <= 0) 1417 continue; 1418 if (dbId != 0 && x->dbId != 0 && 1419 strcmp(dbId, x->dbId) != 0) 1420 continue; 1421 /* 1422 * It's a match if: there are no indexes, or we actually 1423 * match the query with the indexes. 1424 */ 1425 if (x->index.numIndexes <= 0 || 1426 verifyIndexMatch(x, q, 0, 0, 0)) { 1427 tp[nm] = x; 1428 nm++; 1429 } 1430 } 1431 1432 if (nm == 0) { 1433 free(tp); 1434 tp = 0; 1435 } 1436 1437 *numMatches = nm; 1438 1439 return (tp); 1440 } 1441 1442 /* 1443 * Return 1 if there's an indexed mapping, 0 otherwise. 1444 */ 1445 int 1446 haveIndexedMapping(__nis_table_mapping_t *t) { 1447 __nis_table_mapping_t *x; 1448 1449 for (x = t; x != 0; x = x->next) { 1450 if (x->index.numIndexes > 0) 1451 return (1); 1452 } 1453 1454 return (0); 1455 } 1456 1457 /* 1458 * Given an input string 'attrs' of the form "attr1=val1,attr2=val2,...", 1459 * or a filter, return the value associated with the attribute 'attrName'. 1460 * If no instance of 'attrName' is found, return 'default'. In all cases, 1461 * the return value is a copy, and must be freed by the caller. 1462 * 1463 * Of course, return NULL in case of failure. 1464 */ 1465 static char * 1466 attrVal(char *msg, char *attrName, char *def, char *attrs) { 1467 char *val, *filter, **fc = 0; 1468 int i, nfc; 1469 char *myself = "attrVal"; 1470 1471 if (attrName == 0 || attrs == 0) 1472 return (0); 1473 1474 if (msg == 0) 1475 msg = myself; 1476 1477 val = def; 1478 1479 filter = makeFilter(attrs); 1480 if (filter != 0 && (fc = makeFilterComp(filter, &nfc)) != 0 && 1481 nfc > 0) { 1482 for (i = 0; i < nfc; i++) { 1483 char *name, *value; 1484 1485 name = fc[i]; 1486 /* Skip if not of attr=value form */ 1487 if ((value = strchr(name, '=')) == 0) 1488 continue; 1489 1490 *value = '\0'; 1491 value++; 1492 1493 if (strcasecmp(attrName, name) == 0) { 1494 val = value; 1495 break; 1496 } 1497 } 1498 } 1499 1500 if (val != 0) 1501 val = sdup(msg, T, val); 1502 1503 sfree(filter); 1504 freeFilterComp(fc, nfc); 1505 1506 return (val); 1507 } 1508 1509 extern bool_t xdr_nis_object(register XDR *xdrs, nis_object *objp); 1510 1511 /* 1512 * Copy an XDR:ed version of the NIS+ object 'o' (or the one indicated 1513 * by 't->objName' if 'o' is NULL) to the place indicated by 1514 * 't->objectDN->write'. Return an appropriate LDAP status code. 1515 */ 1516 int 1517 objToLDAP(__nis_table_mapping_t *t, nis_object *o, entry_obj **ea, int numEa) { 1518 __nis_table_mapping_t **tp; 1519 XDR xdr; 1520 nis_result *res = 0; 1521 char *objName; 1522 int stat, osize, n, numMatches = 0; 1523 void *buf; 1524 __nis_rule_value_t *rv; 1525 __nis_value_t *val; 1526 __nis_single_value_t *sv; 1527 char **attrName, *dn; 1528 char *myself = "objToLDAP"; 1529 1530 if (t == 0) 1531 return (LDAP_PARAM_ERROR); 1532 1533 logmsg(MSG_NOTIMECHECK, 1534 #ifdef NISDB_LDAP_DEBUG 1535 LOG_WARNING, 1536 #else 1537 LOG_INFO, 1538 #endif /* NISDB_LDAP_DEBUG */ 1539 "%s: %s", myself, NIL(t->objName)); 1540 1541 tp = selectTableMapping(t, 0, 1, 1, 0, &numMatches); 1542 if (tp == 0 || numMatches <= 0) { 1543 sfree(tp); 1544 logmsg(MSG_NOTIMECHECK, 1545 #ifdef NISDB_LDAP_DEBUG 1546 LOG_WARNING, 1547 #else 1548 LOG_INFO, 1549 #endif /* NISDB_LDAP_DEBUG */ 1550 "%s: %s (no mapping)", myself, NIL(t->objName)); 1551 return (LDAP_SUCCESS); 1552 } 1553 1554 for (n = 0; n < numMatches; n++) { 1555 1556 t = tp[n]; 1557 1558 if (o == 0) { 1559 stat = getNisPlusObj(t->objName, myself, &res); 1560 if (stat != LDAP_SUCCESS) { 1561 sfree(tp); 1562 return (stat); 1563 } 1564 1565 /* 1566 * getNisPlusObj() only returns success when res != 0, 1567 * and res->objects.objects_len > 0, so no need to 1568 * check for those conditons. 1569 */ 1570 1571 o = res->objects.objects_val; 1572 if (o == 0) { 1573 sfree(tp); 1574 nis_freeresult(res); 1575 return (LDAP_OPERATIONS_ERROR); 1576 } 1577 if (o->zo_data.zo_type == NIS_DIRECTORY_OBJ) { 1578 /* XXX??? get dir list, set 'ea' and 'numEa' */ 1579 } 1580 } 1581 1582 buf = (char *)xdrNisObject(o, ea, numEa, &osize); 1583 if (res != 0) { 1584 nis_freeresult(res); 1585 res = 0; 1586 } 1587 if (buf == 0) { 1588 sfree(tp); 1589 return (LDAP_OPERATIONS_ERROR); 1590 } 1591 1592 /* 1593 * Prepare to build a rule-value containing the XDR:ed 1594 * object 1595 */ 1596 rv = am(myself, sizeof (*rv)); 1597 sv = am(myself, sizeof (*sv)); 1598 val = am(myself, sizeof (*val)); 1599 attrName = am(myself, sizeof (attrName[0])); 1600 if (attrName != 0) 1601 attrName[0] = attrVal(myself, "nisplusObject", 1602 "nisplusObject", 1603 t->objectDN->write.attrs); 1604 if (rv == 0 || sv == 0 || val == 0 || attrName == 0 || 1605 attrName[0] == 0) { 1606 sfree(tp); 1607 sfree(buf); 1608 sfree(rv); 1609 sfree(sv); 1610 sfree(val); 1611 sfree(attrName); 1612 return (LDAP_NO_MEMORY); 1613 } 1614 1615 sv->length = osize; 1616 sv->value = buf; 1617 1618 /* 'vt_ber' just means "not a NUL-terminated string" */ 1619 val->type = vt_ber; 1620 val->repeat = 0; 1621 val->numVals = 1; 1622 val->val = sv; 1623 1624 rv->numAttrs = 1; 1625 rv->attrName = attrName; 1626 rv->attrVal = val; 1627 1628 /* 1629 * The 'write.base' is the actual DN of the entry (and the 1630 * scope had better be 'base', but we don't check that). 1631 */ 1632 dn = t->objectDN->write.base; 1633 1634 stat = ldapModify(dn, rv, t->objectDN->write.attrs, 1); 1635 1636 freeRuleValue(rv, 1); 1637 1638 logmsg(MSG_NOTIMECHECK, 1639 #ifdef NISDB_LDAP_DEBUG 1640 LOG_WARNING, 1641 #else 1642 LOG_INFO, 1643 #endif /* NISDB_LDAP_DEBUG */ 1644 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat)); 1645 1646 if (stat != LDAP_SUCCESS) 1647 break; 1648 1649 } 1650 1651 sfree(tp); 1652 1653 return (stat); 1654 } 1655 1656 /* 1657 * Retrieve a copy of the 't->objName' object from LDAP, where it's 1658 * stored in XDR:ed form in the place indicated by 't->objectDN->read'. 1659 * Un-XDR the object, and return a pointer to it in '*obj'; it's the 1660 * responsibility of the caller to free the object when it's no 1661 * longer needed. 1662 * 1663 * Returns an appropriate LDAP status. 1664 */ 1665 int 1666 objFromLDAP(__nis_table_mapping_t *t, nis_object **obj, 1667 entry_obj ***eaP, int *numEaP) { 1668 __nis_table_mapping_t **tp; 1669 XDR xdr; 1670 nis_object *o; 1671 __nis_rule_value_t *rv; 1672 __nis_ldap_search_t *ls; 1673 char *attrs[2], *filter, **fc = 0; 1674 void *buf; 1675 int i, j, nfc, nrv, blen, stat = LDAP_SUCCESS; 1676 int n, numMatches; 1677 char *myself = "objFromLDAP"; 1678 1679 if (t == 0) 1680 return (LDAP_PARAM_ERROR); 1681 1682 /* 1683 * If there's nowhere to store the result, we might as 1684 * well pretend all went well, and return right away. 1685 */ 1686 if (obj == 0) 1687 return (LDAP_SUCCESS); 1688 1689 /* Prepare for the worst */ 1690 *obj = 0; 1691 1692 logmsg(MSG_NOTIMECHECK, 1693 #ifdef NISDB_LDAP_DEBUG 1694 LOG_WARNING, 1695 #else 1696 LOG_INFO, 1697 #endif /* NISDB_LDAP_DEBUG */ 1698 "%s: %s", myself, NIL(t->objName)); 1699 1700 tp = selectTableMapping(t, 0, 0, 1, 0, &numMatches); 1701 if (tp == 0 || numMatches <= 0) { 1702 sfree(tp); 1703 logmsg(MSG_NOTIMECHECK, 1704 #ifdef NISDB_LDAP_DEBUG 1705 LOG_WARNING, 1706 #else 1707 LOG_INFO, 1708 #endif /* NISDB_LDAP_DEBUG */ 1709 "%s: %s (no mapping)", myself, NIL(t->objName)); 1710 return (LDAP_SUCCESS); 1711 } 1712 1713 for (n = 0; n < numMatches; n++) { 1714 1715 t = tp[n]; 1716 1717 filter = makeFilter(t->objectDN->read.attrs); 1718 if (filter == 0 || (fc = makeFilterComp(filter, &nfc)) == 0 || 1719 nfc <= 0) { 1720 sfree(tp); 1721 sfree(filter); 1722 freeFilterComp(fc, nfc); 1723 return ((t->objectDN->read.attrs != 0) ? 1724 LDAP_NO_MEMORY : LDAP_PARAM_ERROR); 1725 } 1726 /* Don't need the filter, just the components */ 1727 sfree(filter); 1728 1729 /* 1730 * Look for a "nisplusObject" attribute, and (if found) copy 1731 * the value to attrs[0]. Also remove the "nisplusObject" 1732 * attribute and value from the filter components. 1733 */ 1734 attrs[0] = sdup(myself, T, "nisplusObject"); 1735 if (attrs[0] == 0) { 1736 sfree(tp); 1737 freeFilterComp(fc, nfc); 1738 return (LDAP_NO_MEMORY); 1739 } 1740 attrs[1] = 0; 1741 for (i = 0; i < nfc; i++) { 1742 char *name, *value; 1743 int compare; 1744 1745 name = fc[i]; 1746 /* Skip if not of attr=value form */ 1747 if ((value = strchr(name, '=')) == 0) 1748 continue; 1749 1750 /* Temporarily overWrite the '=' with a '\0' */ 1751 *value = '\0'; 1752 1753 /* Compare with our target attribute name */ 1754 compare = strcasecmp("nisplusObject", name); 1755 1756 /* Put back the '=' */ 1757 *value = '='; 1758 1759 /* Is it the name we're looking for ? */ 1760 if (compare == 0) { 1761 sfree(attrs[0]); 1762 attrs[0] = sdup(myself, T, value+1); 1763 if (attrs[0] == 0) { 1764 sfree(tp); 1765 freeFilterComp(fc, nfc); 1766 return (LDAP_NO_MEMORY); 1767 } 1768 sfree(fc[i]); 1769 if (i < nfc-1) 1770 (void) memmove(&fc[i], &fc[i+1], 1771 (nfc-1-i) * sizeof (fc[i])); 1772 nfc--; 1773 break; 1774 } 1775 } 1776 1777 ls = buildLdapSearch(t->objectDN->read.base, 1778 t->objectDN->read.scope, 1779 nfc, fc, 0, attrs, 0, 1); 1780 sfree(attrs[0]); 1781 freeFilterComp(fc, nfc); 1782 if (ls == 0) { 1783 sfree(tp); 1784 return (LDAP_OPERATIONS_ERROR); 1785 } 1786 1787 nrv = 0; 1788 rv = ldapSearch(ls, &nrv, 0, &stat); 1789 if (rv == 0) { 1790 sfree(tp); 1791 freeLdapSearch(ls); 1792 return (stat); 1793 } 1794 1795 for (i = 0, buf = 0; i < nrv && buf == 0; i++) { 1796 for (j = 0; j < rv[i].numAttrs; j++) { 1797 if (strcasecmp(ls->attrs[0], 1798 rv[i].attrName[j]) == 0) { 1799 if (rv[i].attrVal[j].numVals <= 0) 1800 continue; 1801 buf = rv[i].attrVal[j].val[0].value; 1802 blen = rv[i].attrVal[j].val[0].length; 1803 break; 1804 } 1805 } 1806 } 1807 1808 if (buf != 0) { 1809 o = unXdrNisObject(buf, blen, eaP, numEaP); 1810 if (o == 0) { 1811 sfree(tp); 1812 freeLdapSearch(ls); 1813 freeRuleValue(rv, nrv); 1814 return (LDAP_OPERATIONS_ERROR); 1815 } 1816 stat = LDAP_SUCCESS; 1817 *obj = o; 1818 } else { 1819 stat = LDAP_NO_SUCH_OBJECT; 1820 } 1821 1822 freeLdapSearch(ls); 1823 freeRuleValue(rv, nrv); 1824 1825 logmsg(MSG_NOTIMECHECK, 1826 #ifdef NISDB_LDAP_DEBUG 1827 LOG_WARNING, 1828 #else 1829 LOG_INFO, 1830 #endif /* NISDB_LDAP_DEBUG */ 1831 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat)); 1832 1833 if (stat != LDAP_SUCCESS) 1834 break; 1835 1836 } 1837 1838 sfree(tp); 1839 1840 return (stat); 1841 } 1842 1843 int 1844 deleteLDAPobj(__nis_table_mapping_t *t) { 1845 __nis_table_mapping_t **tp; 1846 int n, stat, numMatches = 0; 1847 char *myself = "deleteLDAPobj"; 1848 1849 if (t == 0) 1850 return (LDAP_PARAM_ERROR); 1851 1852 logmsg(MSG_NOTIMECHECK, 1853 #ifdef NISDB_LDAP_DEBUG 1854 LOG_WARNING, 1855 #else 1856 LOG_INFO, 1857 #endif /* NISDB_LDAP_DEBUG */ 1858 "%s: %s", myself, NIL(t->objName)); 1859 1860 tp = selectTableMapping(t, 0, 1, 1, 0, &numMatches); 1861 if (tp == 0 || numMatches <= 0) { 1862 sfree(tp); 1863 logmsg(MSG_NOTIMECHECK, 1864 #ifdef NISDB_LDAP_DEBUG 1865 LOG_WARNING, 1866 #else 1867 LOG_INFO, 1868 #endif /* NISDB_LDAP_DEBUG */ 1869 "%s: %s (no mapping)", myself, NIL(t->objName)); 1870 return (LDAP_SUCCESS); 1871 } 1872 1873 for (n = 0; n < numMatches; n++) { 1874 1875 t = tp[n]; 1876 1877 if (t->objectDN->delDisp == dd_always) { 1878 /* Delete entire entry */ 1879 stat = ldapModify(t->objectDN->write.base, 0, 1880 t->objectDN->write.attrs, 1); 1881 } else if (t->objectDN->delDisp == dd_perDbId) { 1882 /* 1883 * Delete the attribute holding the object. 1884 * First, determine what that attribute is called. 1885 */ 1886 char *attrName = 1887 attrVal(myself, 1888 "nisplusObject", 1889 "nisplusObject", 1890 t->objectDN->write.attrs); 1891 __nis_rule_value_t rv; 1892 __nis_value_t val; 1893 1894 if (attrName == 0) { 1895 sfree(tp); 1896 return (LDAP_NO_MEMORY); 1897 } 1898 1899 /* 1900 * Build a __nis_value_t with 'numVals' < 0 to 1901 * indicate deletion. 1902 */ 1903 val.type = vt_ber; 1904 val.numVals = -1; 1905 val.val = 0; 1906 1907 /* 1908 * Build a rule-value with the name we determined 1909 * above, and the deletion value. 1910 */ 1911 (void) memset(&rv, 0, sizeof (rv)); 1912 rv.numAttrs = 1; 1913 rv.attrName = &attrName; 1914 rv.attrVal = &val; 1915 1916 stat = ldapModify(t->objectDN->write.base, &rv, 1917 t->objectDN->write.attrs, 0); 1918 1919 sfree(attrName); 1920 } else if (t->objectDN->delDisp == dd_never) { 1921 /* Nothing to do, so we're trivially successful */ 1922 stat = LDAP_SUCCESS; 1923 } else { 1924 stat = LDAP_PARAM_ERROR; 1925 } 1926 1927 logmsg(MSG_NOTIMECHECK, 1928 #ifdef NISDB_LDAP_DEBUG 1929 LOG_WARNING, 1930 #else 1931 LOG_INFO, 1932 #endif /* NISDB_LDAP_DEBUG */ 1933 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat)); 1934 1935 /* If there were no such object, we've trivially succeeded */ 1936 if (stat == LDAP_NO_SUCH_OBJECT) 1937 stat = LDAP_SUCCESS; 1938 1939 if (stat != LDAP_SUCCESS) 1940 break; 1941 1942 } 1943 1944 sfree(tp); 1945 1946 return (stat); 1947 } 1948