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 (c) 2001 by Sun Microsystems, Inc. 24 * All Rights Reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 31 #include <malloc.h> 32 #include <strings.h> 33 #include <string.h> 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <time.h> 37 #include "db_headers.h" 38 #include "db.h" 39 #include "db_mindex.h" 40 #include "db_pickle.h" 41 #include "nisdb_mt.h" 42 #include "nisdb_ldap.h" 43 #include "ldap_nisdbquery.h" 44 #include "ldap_map.h" 45 #include "ldap_ruleval.h" 46 #include "ldap_scheme.h" 47 #include "ldap_parse.h" 48 #include "nis_hashitem.h" 49 #include "nis_servlist.h" 50 #include "ldap_nisplus.h" 51 #include "nis_db.h" 52 #include "ldap_glob.h" 53 54 /* Pass through configuration information to the table */ 55 bool_t 56 db_mindex::configure(char *tablePath) { 57 if (tablePath == NULL) 58 return (FALSE); 59 60 if (objPath.ptr != 0) 61 free(objPath.ptr); 62 objPath.ptr = strdup(tablePath); 63 64 if (table != NULL) { 65 return (table->configure(tablePath)); 66 } else { 67 /* Defer table config until we have a table instance */ 68 return (objPath.ptr != NULL); 69 } 70 } 71 72 /* 73 * The noWriteThrough flag is used to prevent modifies/updates to LDAP 74 * while we're incorporating log data into the in-memory tables. 75 */ 76 void 77 db_mindex::setNoWriteThrough(void) { 78 ASSERTWHELD(this->mindex); 79 noWriteThrough.flag++; 80 } 81 82 void 83 db_mindex::clearNoWriteThrough(void) { 84 ASSERTWHELD(this->mindex); 85 if (noWriteThrough.flag > 0) 86 noWriteThrough.flag--; 87 #ifdef NISDB_LDAP_DEBUG 88 else 89 abort(); 90 #endif /* NISDB_LDAP_DEBUG */ 91 } 92 93 /* 94 * The noLDAPquery flag is used to prevent recursive LDAP queries when 95 * satisfy_query() is re-entered as we add an entry from queryLDAP(). 96 */ 97 void 98 db_mindex::setNoLDAPquery(void) { 99 ASSERTWHELD(this->mindex); 100 noLDAPquery.flag++; 101 } 102 103 void 104 db_mindex::clearNoLDAPquery(void) { 105 ASSERTWHELD(this->mindex); 106 if (noLDAPquery.flag > 0) 107 noLDAPquery.flag--; 108 #ifdef NISDB_LDAP_DEBUG 109 else 110 abort(); 111 #endif /* NISDB_LDAP_DEBUG */ 112 } 113 114 /* 115 * The initialLoad flag tells us if an add or remove is done as part of 116 * the initial load of data, in which case we should use the initial TTLs. 117 */ 118 void 119 db_mindex::setInitialLoad(void) { 120 ASSERTWHELD(this->mindex); 121 initialLoad.flag++; 122 } 123 124 void 125 db_mindex::clearInitialLoad(void) { 126 ASSERTWHELD(this->mindex); 127 if (initialLoad.flag > 0) 128 initialLoad.flag--; 129 #ifdef NISDB_LDAP_DEBUG 130 else 131 abort(); 132 #endif /* NISDB_LDAP_DEBUG */ 133 } 134 135 void 136 db_mindex::setDbPtr(void *ptr) { 137 dbptr.ptr = ptr; 138 } 139 140 void * 141 db_mindex::getDbPtr(void) { 142 return (dbptr.ptr); 143 } 144 145 db_table * 146 db_mindex::getTable(void) { 147 return (table); 148 } 149 150 extern void db_free_result(db_result *); 151 152 zotypes 153 updateMappingObj(__nis_table_mapping_t *t, char **objNameP, 154 bool_t *isMasterP) { 155 zotypes type = NIS_BOGUS_OBJ; 156 char *objName = 0; 157 char *myself = "updateMappingObj"; 158 159 if (t != 0) 160 objName = t->objName; 161 else if (objNameP != 0) 162 objName = *objNameP; 163 else 164 return (NIS_BOGUS_OBJ); 165 166 if (objName != 0) { 167 db_status stat; 168 int lstat = LDAP_SUCCESS; 169 nis_object *o = dbFindObject(objName, &stat); 170 171 /* If not found in the local DB, try LDAP */ 172 if (o == 0) { 173 if (stat != DB_NOTFOUND) { 174 logmsg(MSG_NOTIMECHECK, LOG_INFO, 175 "%s: DB err %d for \"%s\"", 176 myself, stat, NIL(objName)); 177 } 178 o = ldapFindObj(t, objName, &lstat); 179 /* If found, refresh/create the local copy */ 180 if (o != 0) { 181 db_status rstat; 182 rstat = dbRefreshObj(objName, o); 183 if (rstat != DB_SUCCESS) 184 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 185 "%s: DB error %d refreshing \"%s\"", 186 myself, rstat, NIL(objName)); 187 } 188 } 189 190 if (o != 0) { 191 type = o->zo_data.zo_type; 192 if (objNameP != 0) { 193 *objNameP = sdup(myself, T, objName); 194 if (*objNameP == 0) { 195 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 196 "%s: Unable to copy object name (\"%s\")", 197 myself, NIL(objName)); 198 } 199 } 200 if (t != 0) { 201 if (!setMappingObjTypeEtc(t, o)) 202 nis_destroy_object(o); 203 204 if (isMasterP != 0) 205 *isMasterP = t->isMaster; 206 } else { 207 if (isMasterP != 0) 208 *isMasterP = isMaster(o); 209 nis_destroy_object(o); 210 } 211 } else if (lstat != LDAP_SUCCESS) { 212 logmsg(MSG_NOTIMECHECK, LOG_INFO, 213 "%s: LDAP err %d for \"%s\"", 214 myself, lstat, NIL(objName)); 215 } 216 } 217 218 return (type); 219 } 220 221 static __nis_table_mapping_t * 222 mappingFromObj(nis_object *obj, int *statP) { 223 __nis_table_mapping_t *t; 224 __nis_buffer_t b = {0, 0}; 225 char *objPath; 226 char *myself = "mappingFromObj"; 227 228 if (obj == 0 || obj->zo_data.zo_type == NIS_ENTRY_OBJ) 229 return (0); 230 231 /* 232 * Convert full object name to the db table path used as 233 * key for the mapping hash list. 234 */ 235 bp2buf(myself, &b, "%s.%s", 236 NIL(obj->zo_name), NIL(obj->zo_domain)); 237 objPath = internalTableName(b.buf); 238 sfree(b.buf); 239 if (slen(objPath) <= 0) { 240 if (statP != 0) 241 *statP = LDAP_OPERATIONS_ERROR; 242 sfree(objPath); 243 return (0); 244 } 245 246 t = (__nis_table_mapping_t *)__nis_find_item_mt(objPath, 247 &ldapMappingList, 0, 0); 248 249 sfree(objPath); 250 251 return (t); 252 } 253 254 static __nis_table_mapping_t * 255 selectMapping(db_table *table, nis_object *obj, db_query *qin, 256 bool_t wantWrite, bool_t *asObjP, int *statP) { 257 __nis_table_mapping_t *t; 258 __nis_buffer_t b = {0, 0}; 259 bool_t doLDAP, asObj; 260 int stat = LDAP_SUCCESS; 261 char *objPath = 0, buf[MAXPATHLEN+NIS_MAXNAMELEN+1]; 262 char *myself = "db_mindex::selectMapping"; 263 264 /* 265 * If 'table' is NULL, we try to find a mapping for 'obj'. 266 * We expect this to happen when our caller wants to write 267 * the object from a directory entry to LDAP. 268 */ 269 if (table == 0) { 270 if (asObjP != 0) 271 *asObjP = TRUE; 272 if (statP != 0) 273 *statP = LDAP_SUCCESS; 274 275 t = mappingFromObj(obj, statP); 276 277 if (t == 0) 278 return (0); 279 280 /* 281 * Should the object type in the mapping be NIS_BOGUS_OBJ, 282 * we need to determine what kind of object this is. 283 */ 284 if (t->objType == NIS_BOGUS_OBJ) { 285 t->objType = updateMappingObj(t, 0, 0); 286 if (t->objType == NIS_BOGUS_OBJ) { 287 if (statP != 0) 288 *statP = LDAP_OPERATIONS_ERROR; 289 return (0); 290 } 291 } 292 293 /* 294 * If caller wants a mapping suitable for writing, 295 * check that we're the master for this object. 296 */ 297 if (wantWrite && !t->isMaster) 298 return (0); 299 300 return (t); 301 } 302 303 /* 304 * If the object type for the mapping is NIS_BOGUS_OBJ, then 305 * we haven't yet been able to determine what kind of object this 306 * is. Try to fix that now. 307 */ 308 if (table->mapping.objType == NIS_BOGUS_OBJ) { 309 table->mapping.objType = updateMappingObj(table->mapping.tm, 310 &table->mapping.objName, 311 &table->mapping.isMaster); 312 table->mapping.expireType = table->mapping.objType; 313 } 314 315 /* 316 * Depending on the object type (table->mapping.objType): 317 * 318 * table Use table->mapping.tm to query LDAP 319 * for entries per 'qin'. 320 * 321 * directory Use 'qin' and table->mapping.objName 322 * to retrieve a mapping entry, and then 323 * query LDAP for the corresponding object. 324 * 'qin' == NULL means reading/writing the 325 * entire directory object, plus the names 326 * of the directory entries. 327 * 328 * bogus Not mapping this object. However, we may 329 * still be mapping the object 'obj'. 330 * 331 * other Shouldn't happen; illegal. 332 */ 333 switch (table->mapping.objType) { 334 case NIS_TABLE_OBJ: 335 t = table->mapping.tm; 336 if (wantWrite) 337 doLDAP = table->mapping.isMaster && 338 table->mapping.toLDAP; 339 else 340 doLDAP = table->mapping.fromLDAP; 341 asObj = FALSE; 342 break; 343 case NIS_DIRECTORY_OBJ: { 344 char *sub = 0; 345 int nqc, len = 0; 346 db_qcomp *qc; 347 348 t = 0; 349 doLDAP = FALSE; 350 asObj = TRUE; 351 352 /* 353 * We expect the query to have one component, containing 354 * the directory entry name. If there's no query, we want 355 * an enumeration of the entries in the directory. They're 356 * stored with the XDR:ed directory object in LDAP, so 357 * asObj should be TRUE. 358 */ 359 if (qin == 0) { 360 t = table->mapping.tm; 361 if (wantWrite) 362 doLDAP = table->mapping.isMaster && 363 table->mapping.toLDAP; 364 else 365 doLDAP = table->mapping.fromLDAP; 366 asObj = TRUE; 367 break; 368 } 369 370 nqc = qin->size(); 371 if (nqc != 1 || (qc = qin->queryloc()) == 0 || 372 qc[0].index_value == 0) { 373 stat = LDAP_PARAM_ERROR; 374 break; 375 } 376 qc[0].index_value->get_value(&sub, &len); 377 if (sub == 0 || len <= 0) { 378 stat = LDAP_PARAM_ERROR; 379 break; 380 } 381 382 /* Append directory name to dir entry name */ 383 sbc2buf(myself, sub, len, &b); 384 bp2buf(myself, &b, ".%s", table->mapping.objName); 385 386 /* Convert to the DB internal name */ 387 objPath = internal_table_name(b.buf, buf); 388 sfree(b.buf); 389 if (slen(objPath) <= 0) { 390 stat = LDAP_OPERATIONS_ERROR; 391 break; 392 } 393 394 /* Look for the corresponding table mapping */ 395 t = (__nis_table_mapping_t *)__nis_find_item_mt( 396 objPath, &ldapMappingList, 0, 0); 397 398 if (t == 0) 399 break; 400 401 /* Update object mapping information */ 402 if (t->objType == NIS_BOGUS_OBJ) 403 (void) updateMappingObj(t, 0, 0); 404 405 /* 406 * Should check the objectDN's in 't', but leave that to 407 * underlying functions. 408 */ 409 if (wantWrite) 410 doLDAP = t->isMaster; 411 else 412 doLDAP = TRUE; 413 414 break; 415 } 416 case NIS_BOGUS_OBJ: 417 t = mappingFromObj(obj, statP); 418 doLDAP = TRUE; 419 asObj = TRUE; 420 break; 421 default: 422 t = 0; 423 doLDAP = FALSE; 424 asObj = TRUE; 425 break; 426 } 427 428 if (!doLDAP) 429 t = 0; 430 431 if (asObjP != 0) 432 *asObjP = asObj; 433 434 if (statP != 0) 435 *statP = stat; 436 437 return (t); 438 } 439 440 /* 441 * Replace or remove the table entry identified by 'e'. 'tableName' is 442 * the name of the table (which could be a directory) in which the entry 443 * resides. 'obj' is an un-XDR:ed copy of the object in 'e', optionally 444 * supplied to save re-doing unpacking of the entry object. 'tobj' is 445 * a pointer to the table object; needed for table entries, but not 446 * for directory entries. 447 * 448 * 'ttime' contains the current time, to be supplied for the trans log 449 * entry. 450 * 451 * Returns LDAP_SUCCESS when entry successfully added/modified/deleted, 452 * LDAP_COMPARE_TRUE if an entry to be added/modified was the same as 453 * an already existing one, and a suitable error otherwise. 454 */ 455 int 456 db_mindex::updateTableEntry(entry_object *e, int replace, char *tableName, 457 nis_object *obj, nis_object *tobj, uint32_t ttime, 458 int *xid) { 459 int stat, freeObj = 0; 460 db_index_entry *dbie; 461 long count = 0; 462 bool_t valid = TRUE; 463 db_result *dbres; 464 db_query *qi; 465 nis_object *oldObj = 0; 466 char *myself = "db_mindex::updateTableEntry"; 467 468 if (table == 0 || e == 0) 469 return (LDAP_PARAM_ERROR); 470 471 qi = extract_index_values_from_object(e); 472 if (qi == 0) { 473 logmsg(MSG_NOMEM, LOG_ERR, 474 "%s: Out of memory for query index", 475 myself); 476 return (LDAP_NO_MEMORY); 477 } 478 479 dbie = satisfy_query(qi, &count, &valid, FALSE); 480 if (dbie != 0 && (count != 1 || !valid)) { 481 logmsg(MSG_NOTIMECHECK, LOG_INFO, 482 "%s: count=%d, valid=%s", 483 myself, count, valid ? "TRUE" : "FALSE"); 484 delete qi; 485 return (LDAP_OPERATIONS_ERROR); 486 } 487 488 /* 489 * Need a copy of the old object in order to log a removal 490 * (this is true even if we're modifying an existing entry). 491 */ 492 if (dbie != 0) { 493 oldObj = unmakePseudoEntryObj( 494 table->get_entry(dbie->getlocation()), tobj); 495 if (oldObj == 0) { 496 logmsg(MSG_NOTIMECHECK, LOG_ERR, 497 "%s: Error getting object from old pseudo-entry for \"%s\" in \"%s\"", 498 myself, NIL(obj->zo_name), 499 NIL(tableName)); 500 delete qi; 501 return (LDAP_OPERATIONS_ERROR); 502 } 503 } 504 505 if (replace) { 506 /* Need the object from the entry */ 507 if (dbie != 0 && obj == 0) { 508 obj = unmakePseudoEntryObj(e, tobj); 509 if (obj == 0) { 510 logmsg(MSG_NOTIMECHECK, LOG_ERR, 511 "%s: Error getting object from pseudo-entry for \"%s\" in \"%s\"", 512 myself, NIL(obj->zo_name), 513 NIL(tableName)); 514 delete qi; 515 nis_destroy_object(oldObj); 516 return (LDAP_OPERATIONS_ERROR); 517 } 518 freeObj = 1; 519 } 520 521 /* Is the new object a dup of the old ? */ 522 if (dbie != 0 && sameNisPlusObj(oldObj, obj)) { 523 /* Yes, it's a dup, so just update the timestamp */ 524 table->touchEntry(dbie->getlocation()); 525 delete qi; 526 if (freeObj) 527 nis_destroy_object(obj); 528 nis_destroy_object(oldObj); 529 return (LDAP_COMPARE_TRUE); 530 } else { 531 /* 532 * Not a dup, so go ahead and add it. Provided 533 * that 'qi' isn't NULL (which we've already 534 * checked), DB_ADD(_NOSYNC) does the right 535 * thing even if matching entries already 536 * exist. 537 */ 538 dbres = ((db *)dbptr.ptr)->log_action(DB_ADD_NOSYNC, 539 qi, e); 540 if (dbres == 0) 541 stat = LDAP_OPERATIONS_ERROR; 542 else if (dbres->status == DB_SUCCESS) 543 stat = LDAP_SUCCESS; 544 else 545 stat = LDAP_OPERATIONS_ERROR; 546 db_free_result(dbres); 547 } 548 } else { /* Removing */ 549 /* If the object doesn't exist, we're done */ 550 if (dbie == 0) { 551 delete qi; 552 return (LDAP_SUCCESS); 553 } 554 555 dbres = ((db *)dbptr.ptr)->log_action(DB_REMOVE_NOSYNC, qi, 0); 556 if (dbres == 0) 557 stat = LDAP_OPERATIONS_ERROR; 558 else if (dbres->status == DB_SUCCESS) 559 stat = LDAP_SUCCESS; 560 else 561 stat = LDAP_OPERATIONS_ERROR; 562 db_free_result(dbres); 563 } 564 565 /* Log the operation */ 566 if (stat == LDAP_SUCCESS) { 567 int ret, numAttrs; 568 nis_attr *attr, attrbuf[NIS_MAXCOLUMNS]; 569 570 /* If we haven't begun the transaction yet, do so now */ 571 if (*xid == 0) { 572 *xid = beginTransaction(); 573 if (*xid == 0) { 574 logmsg(MSG_NOTIMECHECK, LOG_ERR, 575 "%s: Error starting transaction for \"%s\"", 576 myself, NIL(tableName)); 577 delete qi; 578 if (oldObj != 0) 579 nis_destroy_object(oldObj); 580 return (LDAP_OPERATIONS_ERROR); 581 } 582 } 583 584 if (replace && obj == 0) { 585 obj = unmakePseudoEntryObj(e, tobj); 586 if (obj == 0) { 587 logmsg(MSG_NOTIMECHECK, LOG_ERR, 588 "%s: Error getting object from pseudo-entry for \"%s\" in \"%s\"", 589 myself, NIL(obj->zo_name), 590 NIL(tableName)); 591 delete qi; 592 if (oldObj != 0) 593 nis_destroy_object(oldObj); 594 return (LDAP_OPERATIONS_ERROR); 595 } 596 freeObj = 1; 597 } 598 599 /* 600 * The log stores nis_attr information, so we need to 601 * convert the scheme-query to a nis_attr array. 602 */ 603 attr = schemeQuery2nisAttr(qi, attrbuf, scheme, 604 table->mapping.tm, &numAttrs); 605 if (attr == 0) { 606 logmsg(MSG_NOTIMECHECK, LOG_ERR, 607 "%s: Error converting index query to nis_attr for \"%s\" in \"%s\"", 608 myself, NIL(obj->zo_name), NIL(tableName)); 609 if (freeObj) 610 nis_destroy_object(obj); 611 if (oldObj != 0) 612 nis_destroy_object(oldObj); 613 delete qi; 614 return (LDAP_OPERATIONS_ERROR); 615 } 616 617 if (replace) { 618 /* 619 * While the DB can handle a modify (replace) 620 * operation, the trans log stores this as a 621 * remove followed by an add (which allows 622 * backing out the change by removing the new 623 * object incarnation, and adding the old one). 624 */ 625 if (oldObj != 0) 626 ret = addUpdate(REM_IBASE, tableName, 627 numAttrs, attr, oldObj, 0, ttime); 628 else 629 ret = 0; 630 if (ret == 0) 631 ret = addUpdate(ADD_IBASE, tableName, 632 numAttrs, attr, obj, 0, ttime); 633 } else { /* Removal */ 634 ret = addUpdate(REM_IBASE, tableName, numAttrs, attr, 635 oldObj, 0, ttime); 636 } 637 if (ret != 0) { 638 logmsg(MSG_NOTIMECHECK, LOG_ERR, 639 "%s: Error adding trans log entry for \"%s\" in \"%s\"", 640 myself, NIL(obj->zo_name), NIL(tableName)); 641 stat = LDAP_OPERATIONS_ERROR; 642 } 643 } 644 645 delete qi; 646 647 if (oldObj != 0) 648 nis_destroy_object(oldObj); 649 if (freeObj) 650 nis_destroy_object(obj); 651 652 return (stat); 653 } 654 655 bool_t 656 db_mindex::touchEntry(entry_object *e) { 657 db_query *qi; 658 bool_t ret; 659 660 if (table == 0 || e == 0) 661 return (FALSE); 662 663 qi = extract_index_values_from_object(e); 664 if (qi == 0) 665 return (FALSE); 666 667 ret = touchEntry(qi); 668 669 delete qi; 670 671 return (ret); 672 } 673 674 bool_t 675 db_mindex::touchEntry(db_query *q) { 676 db_index_entry *dbie; 677 long count; 678 bool_t valid; 679 680 dbie = satisfy_query(q, &count, &valid, FALSE); 681 if (dbie != 0 && count == 1 && valid) 682 table->touchEntry(dbie->getlocation()); 683 else 684 return (FALSE); 685 686 return (TRUE); 687 } 688 689 /* 690 * Compose an object name from column zero of 'e' and 't->objName', 691 * and return the mapping for that object, if any. Also set '*name' 692 * to point to the dir entry name in 'e'. Note that this is a pointer 693 * to existing data, and shouldn't be freed other than as part of 694 * freeing 'e'. 695 */ 696 static __nis_table_mapping_t * 697 findDirEntryMapping(__nis_table_mapping_t *t, entry_object *e, char **name) { 698 __nis_table_mapping_t *x; 699 char *entryName; 700 char *myself = "findDirEntryMapping"; 701 __nis_buffer_t b = {0, 0}; 702 703 if (e == 0 || e->en_cols.en_cols_len != 2 || 704 e->en_cols.en_cols_val == 0) 705 return (0); 706 707 entryName = e->en_cols.en_cols_val[1].ec_value.ec_value_val; 708 if (name != 0) 709 *name = entryName; 710 711 if (t == 0 || entryName == 0 || t->objName == 0) 712 return (0); 713 714 bp2buf(myself, &b, "%s.%s", entryName, t->objName); 715 if (b.len == 0 || b.buf == 0) 716 return (0); 717 718 x = (__nis_table_mapping_t *)__nis_find_item_mt(b.buf, 719 &ldapMappingList, 0, 0); 720 721 sfree(b.buf); 722 723 return (x); 724 } 725 726 /* 727 * Query LDAP per the supplied (scheme-) query 'qin'. If 'doAsynch' is 728 * set, and the query is an enumeration (qin == 0), the query will be 729 * performed in a detached thread, and complete asynchronously. In this 730 * case, the return status reflects the setup and launch of the 731 * detached thread; the query will complete asynchronously. 732 * 733 * Returns an appropriate LDAP status code. 734 */ 735 int 736 db_mindex::queryLDAP(db_query *qin, char *dbId, int doAsynch) { 737 __nis_table_mapping_t *t; 738 int i, na, nq = 0, stat, stat2, numAttrs, ret; 739 int xid = 0; 740 long numEa; 741 bool_t asObj, doEnum; 742 db_query *q; 743 entry_object **ea; 744 nis_attr attr; 745 nis_object *dirObj; 746 db_status dstat; 747 char *myself = "db_mindex::queryLDAP"; 748 749 if (!useLDAPrespository || table == 0) 750 return (LDAP_SUCCESS); 751 752 /* 753 * Instances from the deferred dictionary shouldn't change, 754 * there's no point in querying LDAP. 755 */ 756 if (table->mapping.isDeferredTable) 757 return (LDAP_SUCCESS); 758 759 t = selectMapping(table, 0, qin, FALSE, &asObj, &stat); 760 761 if (t == 0) 762 return (stat); 763 764 #ifdef NISDB_LDAP_DEBUG 765 printf("%s: %s (%s)\n", 766 myself, NIL(t->objName), (asObj ? "object" : "entry")); 767 #endif /* NISDB_LDAP_DEBUG */ 768 769 if (qin != NULL) { 770 q = schemeQuery2Query(qin, scheme); 771 if (q == 0) 772 return (LDAP_PARAM_ERROR); 773 #ifdef NISDB_LDAP_DEBUG 774 q->print(); 775 #endif /* NISDB_LDAP_DEBUG */ 776 } else { 777 q = 0; 778 #ifdef NISDB_LDAP_DEBUG 779 printf("\tenumerating %s%s%s\n", 780 dbId ? dbId : "", dbId ? ":" : "", NIL(t->objName)); 781 #endif /* NISDB_LDAP_DEBUG */ 782 } 783 784 /* 785 * Do we have any active mappings for this particular query and 786 * dbId ? If not, we're done. 787 * 788 * Note that we don't care about the return value from 789 * selectTableMapping(), just wheter or not there are 790 * any valid mappings. 791 */ 792 i = 0; 793 sfree(selectTableMapping(t, q, 0, asObj, dbId, &i)); 794 if (i <= 0) { 795 freeQuery(q); 796 return (LDAP_SUCCESS); 797 } 798 799 /* Is the object a directory ? */ 800 if (asObj) { 801 nis_object *o; 802 entry_object *e, eo; 803 entry_col ec[2]; 804 int nea; 805 806 stat = objFromLDAP(t, &o, &ea, &nea); 807 numEa = nea; 808 809 if (stat == LDAP_NO_SUCH_OBJECT) { 810 /* Positive failure; remove the object */ 811 dstat = dbDeleteObj(t->objName); 812 if (dstat == DB_SUCCESS || dstat == DB_NOTFOUND) { 813 stat = LDAP_SUCCESS; 814 } else { 815 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 816 "%s: DB error %d deleting \"%s\"", 817 myself, dstat, NIL(t->objName)); 818 stat = LDAP_OPERATIONS_ERROR; 819 } 820 821 freeQuery(q); 822 823 return (stat); 824 } else if (stat != LDAP_SUCCESS) { 825 freeQuery(q); 826 return (stat); 827 } else if (o == 0) { 828 /* OK; this entry just isn't mapped */ 829 freeQuery(q); 830 return (LDAP_SUCCESS); 831 } 832 833 if (q != 0) { 834 /* 835 * We're updating one particular entry (described 836 * by 't') in the directory 'table->mapping.tm'. 837 */ 838 839 setOid(o); 840 dstat = dbRefreshObj(t->objName, o); 841 if (dstat == DB_SUCCESS) { 842 stat = LDAP_SUCCESS; 843 } else { 844 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 845 "%s: DB error %d updating \"%s\" in \"%s\"", 846 myself, NIL(t->objName), 847 NIL(table->mapping.tm->objName)); 848 stat = LDAP_OPERATIONS_ERROR; 849 } 850 851 freeEntryObjArray(ea, numEa); 852 freeQuery(q); 853 nis_destroy_object(o); 854 855 return (stat); 856 } 857 858 dirObj = o; 859 860 /* 861 * q == 0, so we're enumerating. Update the list of 862 * directory entries. 863 */ 864 865 /* 866 * Need to disable write-through to LDAP, for which we need 867 * a lock on our db_mindex ('this'); we're also updating the 868 * table, so we need a write lock on that as well. 869 */ 870 WRITELOCKNR(this, stat, "w db_mindex::queryLDAP"); 871 if (stat == 0) { 872 WRITELOCKNR(table, stat2, 873 "table w db_mindex::queryLDAP"); 874 } 875 if (stat != 0 || stat2 != 0) { 876 nis_destroy_object(dirObj); 877 logmsg(MSG_NOTIMECHECK, LOG_ERR, 878 "%s: lock error %d", myself, 879 stat != 0 ? stat : stat2); 880 return (LDAP_OPERATIONS_ERROR); 881 } 882 883 setNoWriteThrough(); 884 setNoLDAPquery(); 885 table->setEnumMode(0); 886 887 for (i = 0, na = 0; i < numEa; i++) { 888 int st; 889 __nis_table_mapping_t *x; 890 char *name = 0; 891 entry_obj *e; 892 893 if (ea[i] == 0) 894 continue; 895 896 /* 897 * We've got a list of dir entries. In the general, 898 * case, some are new, and some already exist. 899 * We definitely want to add the new ones, and to 900 * that end, we need a copy of the object for the 901 * entry. By definition, if an entry is new, we 902 * don't yet have a copy of the object for it, so 903 * it's LDAP or nothing. 904 * 905 * If the entry already exists, try to update the 906 * entry object. In this case, we again only need 907 * to look in LDAP for the object; if there already 908 * is one in the DB, it's in the dir entry which we 909 * want to update. 910 * 911 * So, whether adding or replacing, try to get the 912 * object from LDAP. 913 * 914 * If we can't get a copy of the object, there's not 915 * much point in adding or updating (since a dir 916 * entry just consists of the entry object and name), 917 * so we continue to the next entry. 918 * 919 * However, in that case, we do need to touch the 920 * dir entry; otherwise, it will be removed later 921 * on. 922 */ 923 924 x = findDirEntryMapping(t, ea[i], &name); 925 o = 0; 926 if (x == 0 || (st = objFromLDAP(x, &o, 0, 0)) != 927 LDAP_SUCCESS) { 928 if (x != 0) 929 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 930 "%s: Unable to obtain object for \"%s\" in \"%s\": %s", 931 myself, NIL(name), NIL(t->objName), 932 ldap_err2string(st)); 933 if (o != 0) 934 nis_destroy_object(o); 935 if (!touchEntry(ea[i])) { 936 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 937 "%s: Inconsistency: LDAP-derived directory \"%s\" " 938 "contains entry \"%s\", which is unknown locally, " 939 "and has no LDAP mapping", 940 myself, NIL(t->objName), 941 NIL(name)); 942 } 943 continue; 944 } 945 946 if (ea[i]->en_cols.en_cols_len != 2 || 947 ea[i]->en_cols.en_cols_val == 0 || 948 ea[i]->en_cols.en_cols_val[0]. 949 ec_value.ec_value_val != 0 || 950 ea[i]->en_cols.en_cols_val[0]. 951 ec_value.ec_value_len != 0) { 952 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 953 "%s: Illegal entry_obj col 0 for \"%s\" in \"%s\"", 954 myself, NIL(name), NIL(t->objName)); 955 nis_destroy_object(o); 956 touchEntry(ea[i]); 957 continue; 958 } 959 960 setOid(o); 961 e = makePseudoEntryObj(o, ea[i], 0); 962 if (e == 0) { 963 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 964 "%s: Unable to create pseudo entry object for \"%s\" in \"%s\"", 965 myself, NIL(name), NIL(t->objName)); 966 nis_destroy_object(o); 967 touchEntry(ea[i]); 968 continue; 969 } 970 971 st = updateTableEntry(e, 1, t->objName, o, 0, 972 o->zo_oid.mtime, &xid); 973 if (st == LDAP_SUCCESS) { 974 na++; 975 } else if (st == LDAP_COMPARE_TRUE) { 976 /* OK, same as existing entry */ 977 st = LDAP_SUCCESS; 978 } else { 979 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 980 "%s: Error updating directory entry for \"%s\" in \"%s\": %s", 981 myself, NIL(name), NIL(t->objName), 982 ldap_err2string(st)); 983 if (stat == LDAP_SUCCESS) 984 stat = st; 985 } 986 987 /* Free the XDR buffer */ 988 sfree(e->en_cols.en_cols_val[0]. 989 ec_value.ec_value_val); 990 /* Restore ea[i] */ 991 ea[i]->en_cols.en_cols_val[0]. 992 ec_value.ec_value_val = 0; 993 ea[i]->en_cols.en_cols_val[0]. 994 ec_value.ec_value_len = 0; 995 nis_destroy_object(o); 996 } 997 998 freeEntryObjArray(ea, numEa); 999 1000 /* Get list of entries to remove */ 1001 ea = table->endEnumMode(&numEa); 1002 if (ea != 0) { 1003 uint32_t nowt = time(0); 1004 1005 for (i = 0; i < numEa; i++) { 1006 int st; 1007 1008 if (ea[i] == 0) 1009 continue; 1010 1011 st = updateTableEntry(ea[i], 0, t->objName, 0, 1012 0, nowt, &xid); 1013 if (st == LDAP_SUCCESS) { 1014 na++; 1015 } else { 1016 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1017 "%s: Error removing directory entry for \"%s\": %s", 1018 myself, NIL(t->objName), 1019 ldap_err2string(st)); 1020 if (stat == LDAP_SUCCESS) 1021 stat = st; 1022 } 1023 } 1024 } 1025 1026 if (stat == LDAP_SUCCESS) { 1027 struct timeval now; 1028 (void) gettimeofday(&now, 0); 1029 table->mapping.enumExpire = now.tv_sec + 1030 table->mapping.ttl; 1031 } 1032 1033 if (na > 0) 1034 (void) ((db *)dbptr.ptr)->sync_log(); 1035 1036 if (xid != 0 && na > 0 && stat == LDAP_SUCCESS) { 1037 ret = endTransaction(xid, dirObj); 1038 if (ret != 0) { 1039 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1040 "%s: Error ending transaction for \"%s\"", 1041 myself, NIL(t->objName)); 1042 stat = LDAP_OPERATIONS_ERROR; 1043 } 1044 } else if (xid != 0) { 1045 ret = abort_transaction(xid); 1046 if (ret != 0) { 1047 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1048 "%s: Error aborting transaction for \"%s\"", 1049 myself, NIL(t->objName)); 1050 } 1051 } 1052 nis_destroy_object(dirObj); 1053 1054 sfree(ea); 1055 1056 clearNoLDAPquery(); 1057 clearNoWriteThrough(); 1058 1059 WRITEUNLOCK2(table, this, 1060 stat, stat, 1061 "table wu db_mindex::queryLDAP", 1062 "wu db_mindex::queryLDAP"); 1063 1064 return (stat); 1065 } 1066 1067 /* 1068 * In order to ping replicas, if any, we need to find the 1069 * directory containing the table to be updated. If we 1070 * can't find the directory object, we're sunk, so let's 1071 * start with that. 1072 */ 1073 if (t->isMaster) { 1074 dirObj = findObj(t->obj->zo_domain, &dstat, &stat); 1075 if (dirObj == 0) { 1076 if (stat == LDAP_SUCCESS) 1077 stat = LDAP_OPERATIONS_ERROR; 1078 return (stat); 1079 } 1080 } else { 1081 dirObj = 0; 1082 } 1083 1084 stat = entriesFromLDAP(t, qin, q, dbId, dirObj, doAsynch); 1085 1086 return (stat); 1087 } 1088 1089 extern db *tableDB(char *); 1090 1091 /* 1092 * Remove the LDAP entry/entries corresponding to 'qin'/'obj'. 1093 */ 1094 int 1095 db_mindex::removeLDAP(db_query *qin, nis_object *obj) { 1096 __nis_table_mapping_t *t; 1097 db_query *q; 1098 bool_t asObj; 1099 int stat; 1100 1101 if (!useLDAPrespository || table == 0) 1102 return (LDAP_SUCCESS); 1103 1104 /* Instances from the deferred dictionary should not update LDAP */ 1105 if (table->mapping.isDeferredTable) 1106 return (LDAP_SUCCESS); 1107 1108 t = selectMapping(table, 0, qin, TRUE, &asObj, &stat); 1109 if (t == 0 && stat != LDAP_SUCCESS) 1110 return (stat); 1111 1112 #ifdef NISDB_LDAP_DEBUG 1113 if (t != 0) 1114 printf("removeLDAP: %s\n", NIL(t->objName)); 1115 #endif /* NISDB_LDAP_DEBUG */ 1116 1117 if (qin != NULL) { 1118 if (asObj) { 1119 /* 1120 * selectMapping() gave us the mapping for the 1121 * directory entry. However, if 't' is NULL, this 1122 * could be due to the directory itself not being 1123 * mapped, in which case we must obtain the mapping 1124 * info from 'obj'. 1125 */ 1126 if (t == 0) { 1127 t = selectMapping(0, obj, 0, TRUE, &asObj, 1128 &stat); 1129 if (t == 0 && stat != LDAP_SUCCESS) 1130 return (stat); 1131 } 1132 1133 if (t != 0) { 1134 stat = deleteLDAPobj(t); 1135 /* 1136 * If we were successful, update the object 1137 * stored with the mapping. 1138 */ 1139 if (stat == LDAP_SUCCESS) 1140 (void) replaceMappingObj(t, 0); 1141 else 1142 return (stat); 1143 } 1144 1145 /* 1146 * Since it's a directory entry we've removed, we also 1147 * need to update the directory object itself. 1148 */ 1149 stat = storeLDAP(0, 0, 0, 0, 0); 1150 } else { 1151 q = schemeQuery2Query(qin, scheme); 1152 if (q == 0) 1153 return (LDAP_PARAM_ERROR); 1154 #ifdef NISDB_LDAP_DEBUG 1155 q->print(); 1156 #endif /* NISDB_LDAP_DEBUG */ 1157 stat = mapToLDAP(t, 1, &q, 0, 0, 0, 0); 1158 freeQuery(q); 1159 } 1160 } else { 1161 /* 1162 * This isn't the way to remove the LDAP entries 1163 * corresponding to the entire table. 1164 */ 1165 #ifdef NISDB_LDAP_DEBUG 1166 abort(); 1167 #endif /* NISDB_LDAP_DEBUG */ 1168 stat = LDAP_PARAM_ERROR; 1169 } 1170 1171 return (stat); 1172 } 1173 1174 /* 1175 * Helper function for storeLDAP() which handles updates for objects 1176 * other than table entries. 1177 */ 1178 int 1179 db_mindex::storeObjLDAP(__nis_table_mapping_t *t, nis_object *o) { 1180 int stat, assigned = 0; 1181 entry_object **ea; 1182 int numEa, doUnlock = 0; 1183 db *dbase = 0; 1184 db_mindex *dbm = 0; 1185 char *myself = "db_mindex::storeObjLDAP"; 1186 1187 if (t == 0 || o == 0) 1188 return (LDAP_SUCCESS); 1189 1190 /* 1191 * If the object to be stored is anything other than a 1192 * directory, we can just go ahead and write it to LDAP. 1193 * A directory object, however, also needs a directory 1194 * entry list, so we should to get hold of the db_table 1195 * that goes with the directory. 1196 */ 1197 if (o->zo_data.zo_type == NIS_DIRECTORY_OBJ) { 1198 dbase = tableDB(t->objName); 1199 if (dbase != 0) 1200 dbm = dbase->mindex(); 1201 if (dbase == 0 || dbm == 0 || dbm->table == 0) { 1202 /* By definition, no dir entries */ 1203 ea = 0; 1204 numEa = 0; 1205 dbase = 0; 1206 } else { 1207 entry_object **tea; 1208 long i, ntea; 1209 1210 /* 1211 * Read-lock the table so that 'tab' 1212 * doesn't change while we're using it. 1213 */ 1214 READLOCK(dbm->table, LDAP_OPERATIONS_ERROR, 1215 "r table db_mindex::storeLDAP"); 1216 doUnlock = 1; 1217 1218 tea = dbm->table->gettab(); 1219 ntea = dbm->table->getsize(); 1220 1221 /* 1222 * There may be empty slots in the table 'tab' 1223 * array, so get rid of those. 1224 */ 1225 if (tea != 0 && ntea > 0) { 1226 ea = (entry_object **)am(myself, 1227 ntea * sizeof (ea[0])); 1228 if (ea == 0) { 1229 READUNLOCK(dbm->table, LDAP_NO_MEMORY, 1230 "ru table db_mindex::storeLDAP"); 1231 return (LDAP_NO_MEMORY); 1232 } 1233 for (i = 0, numEa = 0; i < ntea; i++) { 1234 if (tea[i] != 0) { 1235 ea[numEa] = tea[i]; 1236 numEa++; 1237 } 1238 } 1239 if (numEa == 0) { 1240 /* No non-empty slots */ 1241 sfree(ea); 1242 ea = 0; 1243 READUNLOCK(dbm->table, 1244 LDAP_OPERATIONS_ERROR, 1245 "ru table db_mindex::storeLDAP"); 1246 doUnlock = 0; 1247 } 1248 } else { 1249 ea = 0; 1250 numEa = 0; 1251 READUNLOCK(dbm->table, 1252 LDAP_OPERATIONS_ERROR, 1253 "ru table db_mindex::storeLDAP"); 1254 doUnlock = 0; 1255 } 1256 } 1257 } else { 1258 ea = 0; 1259 numEa = 0; 1260 } 1261 1262 stat = objToLDAP(t, o, ea, numEa); 1263 1264 if (ea != 0) 1265 sfree(ea); 1266 if (doUnlock) { 1267 READUNLOCK(dbm->table, stat, 1268 "ru table db_mindex::storeLDAP"); 1269 } 1270 1271 return (stat); 1272 } 1273 1274 1275 /* 1276 * Store data specified by the index-query 'qin' to LDAP. If 'obj' is 1277 * non-null, it's a pointer to the pseudo-entry object corresponding to 1278 * 'qin'. As a short-cut/convenience, the caller can instead supply 1279 * the actual nis_object 'o'; if 'o' is NULL, it's derived from 'obj'. 1280 * 1281 * 'oldObj' is used for table entries if the store operation is 1282 * an update, and the corresponding NIS+ operation was a delete followed 1283 * by an add. In this case, oldObj contains the pre-delete incarnation of 1284 * the entry object to be modified. 1285 * 1286 * The 'dbId' string is used to select one dbId for mapping chains 1287 * that contain more than one. 1288 * 1289 * Returns an LDAP status code. 1290 */ 1291 int 1292 db_mindex::storeLDAP(db_query *qin, entry_object *obj, nis_object *o, 1293 entry_obj *oldObj, char *dbId) { 1294 __nis_table_mapping_t *t; 1295 bool_t asObj; 1296 db_query *q, *qo, **qa; 1297 __nis_rule_value_t *rv = 0; 1298 int stat; 1299 char *myself = "db_mindex::storeLDAP"; 1300 1301 if (!useLDAPrespository || table == 0) 1302 return (LDAP_SUCCESS); 1303 1304 /* Instances from the deferred dictionary should not update LDAP */ 1305 if (table->mapping.isDeferredTable) 1306 return (LDAP_SUCCESS); 1307 1308 t = selectMapping(table, 0, qin, TRUE, &asObj, &stat); 1309 if (t == 0 && stat != LDAP_SUCCESS) 1310 return (stat); 1311 1312 #ifdef NISDB_LDAP_DEBUG 1313 if (t != 0) 1314 printf("storeLDAP: %s%s%s\n", 1315 dbId ? dbId : "", dbId ? ":" : "", NIL(t->objName)); 1316 #endif /* NISDB_LDAP_DEBUG */ 1317 1318 /* 1319 * selectMapping() didn't have the object to look at, so we 1320 * must check if this is a directory entry or not. 1321 */ 1322 if (asObj) { 1323 if (o != 0) { 1324 if (o->zo_data.zo_type == NIS_ENTRY_OBJ) 1325 asObj = FALSE; 1326 } else if (obj != 0) { 1327 if (obj->en_type == 0 || 1328 strcmp(obj->en_type, "IN_DIRECTORY") != 0) 1329 asObj = FALSE; 1330 } 1331 } 1332 1333 if (asObj) { 1334 bool_t freeO = FALSE; 1335 1336 /* 1337 * If we don't have a mapping, that's probably because 1338 * the directory (represented by 'this') isn't mapped. 1339 * Try to get a mapping from 'o' or 'obj'. 1340 */ 1341 if (t == 0) { 1342 if (o == 0 && obj != 0) { 1343 o = unmakePseudoEntryObj(obj, 0); 1344 if (o == 0) 1345 return (LDAP_OPERATIONS_ERROR); 1346 freeO = TRUE; 1347 } 1348 if (o != 0) { 1349 t = selectMapping(0, o, 0, TRUE, &asObj, &stat); 1350 if (t == 0) { 1351 if (freeO) 1352 nis_destroy_object(o); 1353 return (stat); 1354 } 1355 } 1356 } 1357 1358 /* 1359 * If we found a mapping for the 'table' in this db_mindex, 1360 * store the object. 1361 */ 1362 if (t != 0) { 1363 if (o == 0) { 1364 if (obj != 0) { 1365 o = unmakePseudoEntryObj(obj, 0); 1366 freeO = TRUE; 1367 } else { 1368 db_status dstat; 1369 1370 o = dbFindObject(t->objName, &dstat); 1371 if (o == 0) 1372 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1373 "%s: DB error %d finding \"%s\"", 1374 myself, 1375 NIL(t->objName)); 1376 freeO = TRUE; 1377 } 1378 } 1379 if (o == 0) 1380 return (LDAP_OPERATIONS_ERROR); 1381 1382 stat = storeObjLDAP(t, o); 1383 1384 /* 1385 * Store the object with the mapping. If 'o' was 1386 * supplied by the caller, we first need to make 1387 * a copy. 1388 */ 1389 if (!freeO) { 1390 o = nis_clone_object(o, 0); 1391 if (o == 0) 1392 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1393 "%s: Unable to refresh mapping object for \"%s\"", 1394 myself, NIL(t->objName)); 1395 } 1396 if (o != 0) { 1397 if (!replaceMappingObj(t, o)) 1398 nis_destroy_object(o); 1399 } 1400 1401 /* 1402 * Object now either destroyed or stored in 't'. 1403 * Set pointer to NULL in order to avoid freeing 1404 * it below. 1405 */ 1406 o = 0; 1407 1408 if (stat != LDAP_SUCCESS) 1409 return (stat); 1410 } 1411 1412 if (freeO && o != 0) { 1413 nis_destroy_object(o); 1414 o = 0; 1415 } 1416 1417 /* 1418 * If the entry object 'obj' has the type "IN_DIRECTORY", 1419 * then it's a directory entry, and we should check if 1420 * the directory is mapped to LDAP, and update the dir 1421 * entry list accordingly. 1422 */ 1423 if (obj == 0 || obj->en_type == 0 || 1424 strcmp(obj->en_type, "IN_DIRECTORY") != 0) 1425 return (LDAP_SUCCESS); 1426 1427 /* Does it have a mapping ? */ 1428 t = selectMapping(table, 0, 0, TRUE, &asObj, &stat); 1429 if (t == 0) 1430 return (stat); 1431 1432 stat = storeObjLDAP(t, t->obj); 1433 1434 return (stat); 1435 } 1436 1437 /* Store table entries. If we don't have a mapping, we're done. */ 1438 if (t == 0) 1439 return (LDAP_SUCCESS); 1440 1441 if (qin != NULL && obj != NULL) { 1442 db_index_entry *dbie; 1443 int i, size, nq = 0; 1444 long l, count; 1445 bool_t valid; 1446 db_query qbuf, **qold; 1447 1448 rv = (__nis_rule_value_t *)am(myself, sizeof (*rv)); 1449 qa = (db_query **)am(myself, sizeof (qa[0])); 1450 if (oldObj != 0) { 1451 /* 1452 * Note that only qold[0] is a unique query pointer. 1453 * All the other qold[i]'s are copies of qa[i]. 1454 * Hence, we only free qold[0], as well as qold 1455 * itself. 1456 */ 1457 qold = (db_query **)am(myself, sizeof (qold[0])); 1458 } else { 1459 qold = 0; 1460 } 1461 if (rv == 0 || qa == 0 || (oldObj != 0 && qold == 0)) { 1462 sfree(rv); 1463 sfree(qa); 1464 sfree(qold); 1465 return (LDAP_NO_MEMORY); 1466 } 1467 1468 q = schemeQuery2Query(qin, scheme); 1469 if (q == 0) { 1470 sfree(rv); 1471 sfree(qa); 1472 return (LDAP_PARAM_ERROR); 1473 } 1474 1475 qa[0] = pseudoEntryObj2Query(obj, t->obj, &rv[0]); 1476 if (qa[0] == 0) { 1477 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1478 "%s: Unable to obtain query representation of new entry object for \"%s\"", 1479 myself, NIL(t->dbId)); 1480 freeQuery(q); 1481 sfree(rv); 1482 sfree(qa); 1483 sfree(qold); 1484 return (LDAP_OPERATIONS_ERROR); 1485 } 1486 if (oldObj != 0) { 1487 qold[0] = pseudoEntryObj2Query(oldObj, t->obj, 0); 1488 if (qold[0] == 0) { 1489 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1490 "%s: Unable to obtain query representation of old entry object for \"%s\"", 1491 myself, NIL(t->dbId)); 1492 freeQueries(qa, 1); 1493 freeQuery(q); 1494 sfree(rv); 1495 sfree(qa); 1496 sfree(qold); 1497 return (LDAP_OPERATIONS_ERROR); 1498 } 1499 } 1500 1501 nq++; 1502 1503 /* 1504 * In order to support many-to-one NIS+ to LDAP mapping, 1505 * we need to find all possible matches in the NIS+ DB, 1506 * and then merge to produce a single update. mapToLDAP() 1507 * takes care of the merging, so our job is to collect 1508 * the matches. Worst case is that we need to search 1509 * individually for each component in 'qin', so that's 1510 * what we'll do. 1511 * 1512 * mapToLDAP() has a mode that only performs an update 1513 * for the first DN, and that's what we want. In order 1514 * to make sure that it's the correct DN, we leave the 1515 * original query as the first one passed to mapToLDAP(). 1516 */ 1517 1518 size = qin->size(); 1519 1520 /* For each component of 'qin' */ 1521 for (i = 0; i < size; i++) { 1522 db_query *qc, **qat, **qoldt; 1523 long j; 1524 __nis_rule_value_t *rvt; 1525 1526 qc = queryFromComponent(qin, i, &qbuf); 1527 if (qc == 0) 1528 continue; 1529 1530 dbie = satisfy_query_dbonly(qc, &count, FALSE, &valid); 1531 if (dbie == 0 || !valid || count <= 0) 1532 continue; 1533 1534 rvt = (__nis_rule_value_t *)realloc(rv, 1535 (nq+count) * sizeof (rv[0])); 1536 qat = (db_query **)realloc(qa, 1537 (nq+count) * sizeof (qa[0])); 1538 if (qold != 0) 1539 qoldt = (db_query **)realloc(qold, 1540 (nq+count) * sizeof (qold[0])); 1541 if (rvt == 0 || qat == 0 || (qold != 0 && qoldt == 0)) { 1542 if (qat == 0) 1543 freeQueries(qa, nq); 1544 else 1545 freeQueries(qat, nq); 1546 if (rvt == 0) 1547 freeRuleValue(rv, nq); 1548 else 1549 freeRuleValue(rvt, nq); 1550 if (qold != 0) { 1551 if (qoldt == 0) 1552 freeQueries(qold, 1); 1553 else 1554 freeQueries(qoldt, 1); 1555 } 1556 freeQuery(q); 1557 (void) memset(&qbuf, 0, sizeof (qbuf)); 1558 logmsg(MSG_NOMEM, LOG_ERR, 1559 "%s: realloc(%d) failed", 1560 myself, (nq+count) * sizeof (void *)); 1561 return (LDAP_NO_MEMORY); 1562 } 1563 1564 rv = rvt; 1565 qa = qat; 1566 1567 (void) memset(&rv[nq], 0, count * sizeof (rv[0])); 1568 (void) memset(&qa[nq], 0, count * sizeof (qa[0])); 1569 if (qold != 0) { 1570 qold = qoldt; 1571 (void) memset(&qold[nq], 0, 1572 count * sizeof (qold[0])); 1573 } 1574 1575 for (j = 0; j < count; j++) { 1576 qa[nq] = pseudoEntryObj2Query( 1577 table->get_entry(dbie->getlocation()), 1578 t->obj, &rv[nq]); 1579 if (qa[nq] == 0) { 1580 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1581 "%s: Could not create query from entry obj for \"%s\"", 1582 myself, NIL(t->objName)); 1583 freeQueries(qa, nq); 1584 freeQueries(qold, 1); 1585 freeRuleValue(rv, nq); 1586 freeQuery(q); 1587 (void) memset(&qbuf, 0, sizeof (qbuf)); 1588 return (LDAP_PARAM_ERROR); 1589 } 1590 if (qold != 0) 1591 qold[nq] = qa[nq]; 1592 nq++; 1593 dbie = dbie->getnextresult(); 1594 if (dbie == 0) 1595 break; 1596 } 1597 } 1598 1599 stat = mapToLDAP(t, nq, (qold != 0 ? qold : qa), qa, rv, 1, 1600 dbId); 1601 1602 freeQueries(qa, nq); 1603 freeRuleValue(rv, nq); 1604 freeQuery(q); 1605 freeQueries(qold, 1); 1606 (void) memset(&qbuf, 0, sizeof (qbuf)); 1607 1608 } else if (qin == 0 && obj == 0 && t->objType == NIS_TABLE_OBJ) { 1609 long i, j, ntab; 1610 entry_object **tab; 1611 1612 READLOCK(table, LDAP_OPERATIONS_ERROR, 1613 "r table db_mindex::storeLDAP"); 1614 1615 tab = table->gettab(); 1616 ntab = table->getsize(); 1617 if (tab == 0 || ntab <= 0) { 1618 READUNLOCK(table, LDAP_OPERATIONS_ERROR, 1619 "ru table db_mindex::storeLDAP"); 1620 return (LDAP_SUCCESS); 1621 } 1622 1623 qa = (db_query **)am(myself, ntab * sizeof (qa[0])); 1624 rv = (__nis_rule_value_t *)am(myself, ntab * sizeof (rv[0])); 1625 if (qa == 0 || rv == 0) { 1626 sfree(qa); 1627 sfree(rv); 1628 READUNLOCK(table, LDAP_OPERATIONS_ERROR, 1629 "ru table db_mindex::storeLDAP"); 1630 return (LDAP_NO_MEMORY); 1631 } 1632 1633 for (i = 0; i < ntab; i++) { 1634 if (tab[i] == 0) 1635 continue; 1636 1637 qa[i] = pseudoEntryObj2Query(tab[i], t->obj, &rv[i]); 1638 if (qa[i] == 0) { 1639 freeQueries(qa, i); 1640 freeRuleValue(rv, i); 1641 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1642 "%s: Could not create query from entry for \"%s\"", 1643 myself, NIL(t->objName)); 1644 READUNLOCK(table, LDAP_OPERATIONS_ERROR, 1645 "ru table db_mindex::storeLDAP"); 1646 return (LDAP_OPERATIONS_ERROR); 1647 } 1648 } 1649 1650 stat = mapToLDAP(t, ntab, qa, qa, rv, 0, dbId); 1651 1652 freeQueries(qa, ntab); 1653 freeRuleValue(rv, ntab); 1654 1655 if (stat == LDAP_SUCCESS) { 1656 struct timeval now; 1657 int lstat, lck = 1; 1658 /* 1659 * Since we've just successfully uploaded everthing 1660 * in this table, we now consider our local copy 1661 * up-to-date as well. 1662 */ 1663 1664 (void) gettimeofday(&now, 0); 1665 WRITELOCKNR(table, lstat, 1666 "w table db_mindex::storeLDAP"); 1667 if (lstat == 0) { 1668 table->mapping.enumExpire = now.tv_sec + 1669 table->mapping.ttl; 1670 lck = 0; 1671 WRITEUNLOCKNR(table, lstat, 1672 "wu table db_mindex::storeLDAP"); 1673 } 1674 if (lstat != 0) { 1675 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1676 "%s: %sock error %d for \"%s\"%s", 1677 myself, lck?"L":"Unl", lstat, 1678 NIL(t->objName), 1679 lck ? 1680 "; unable to update enumeration expiration": 1681 ""); 1682 } 1683 } 1684 1685 READUNLOCK(table, stat, 1686 "ru table db_mindex::storeLDAP"); 1687 } 1688 1689 return (stat); 1690 } 1691