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