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 * nis_db.cc 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 29 #include <sys/param.h> 30 #include <strings.h> 31 #include <syslog.h> 32 #include "nisdb_mt.h" 33 #include "db_headers.h" 34 #include "db_entry.h" 35 #include "db.h" 36 #include "db_dictionary.h" 37 #include "db_pickle.h" 38 #include "nis_db.h" 39 #include "nis_ldap.h" 40 #include "ldap_util.h" 41 #include "ldap_parse.h" 42 #include "ldap_glob.h" 43 #include "ldap_xdr.h" 44 #include "ldap_glob.h" 45 46 db_dictionary curdict; 47 db_dictionary tempdict; /* a temporary one */ 48 49 db_dictionary *InUseDictionary = &curdict; 50 db_dictionary *FreeDictionary = &tempdict; 51 52 extern "C" { 53 static db_result *db_add_entry_x(char *tab, int numattrs, 54 nis_attr *attrname, entry_obj * newobj, 55 int skiplog, int nosync); 56 db_status db_table_exists(char *table_name); 57 58 /* 59 * (Imported from rpc.nisd/nis_xx_proc.c) 60 * 61 * 'tbl_prototype' is used to create a table that holds a directory. 62 */ 63 static table_col cols[2] = { 64 {"object", TA_BINARY+TA_XDR, 0}, 65 {"name", TA_CASE+TA_SEARCHABLE, 0} 66 }; 67 68 table_obj tbl_prototype = { "DIRECTORY", 2, ' ', {2, &cols[0]}, NULL }; 69 } 70 71 /* 72 * Free resources associated with a db_result structure 73 */ 74 void 75 db_free_result(db_result *dr) 76 { 77 int i; 78 79 if (dr == 0) 80 return; 81 82 /* Can't have valid objects */ 83 if (dr->status != DB_SUCCESS) { 84 free(dr); 85 return; 86 } 87 88 for (i = 0; i < dr->objects.objects_len; i++) 89 free_entry(dr->objects.objects_val[i]); 90 free(dr->objects.objects_val); 91 free(dr); 92 } 93 94 95 /* Return an empty db_result structure with its status field set to 's'. */ 96 db_result* 97 empty_result(db_status s) 98 { 99 db_result * res = new db_result; 100 if (res != NULL) { 101 res->status = s; 102 res->nextinfo.db_next_desc_len = 0; 103 res->nextinfo.db_next_desc_val = NULL; 104 res->objects.objects_len = 0; 105 res->objects.objects_val = NULL; 106 } else { 107 WARNING("nis_db::empty_result: cannot allocate space"); 108 } 109 return (res); 110 } 111 112 static db_result* 113 set_result(db_result* res, db_status s) 114 { 115 if (res != NULL) { 116 res->status = s; 117 } 118 return (res); 119 } 120 121 /* 122 * Given a FQ object name for a table or directory, return the (db *) 123 * corresponding to the object. 124 */ 125 db * 126 tableDB(char *tableName) { 127 db_table_desc *tbl = 0; 128 char *intName; 129 db *dbase; 130 131 intName = internalTableName(tableName); 132 if (intName == 0) 133 return (0); 134 135 dbase = InUseDictionary->find_table(intName, &tbl); 136 137 sfree(intName); 138 139 return (dbase); 140 } 141 142 extern "C" { 143 144 bool_t 145 db_in_dict_file(char *name) 146 { 147 return ((bool_t) InUseDictionary->find_table_desc(name)); 148 149 } 150 151 char 152 *db_perror(db_status dbstat) 153 { 154 char *str = NULL; 155 156 switch (dbstat) { 157 case DB_SUCCESS: 158 str = "Success"; 159 break; 160 case DB_NOTFOUND: 161 str = "Not Found"; 162 break; 163 case DB_BADTABLE: 164 str = "Bad Table"; 165 break; 166 case DB_BADQUERY: 167 str = "Bad Query"; 168 break; 169 case DB_BADOBJECT: 170 str = "Bad Object"; 171 break; 172 case DB_MEMORY_LIMIT: 173 str = "Memory limit exceeded"; 174 break; 175 case DB_STORAGE_LIMIT: 176 str = "Database storage limit exceeded"; 177 break; 178 case DB_INTERNAL_ERROR: 179 str = "Database internal error"; 180 break; 181 case DB_SYNC_FAILED: 182 str = "Sync of log file failed"; 183 break; 184 default: 185 str = "Unknown Error"; 186 break; 187 } 188 return (str); 189 } 190 191 bool_t 192 db_extract_dict_entries(char *newdict, char **fs, int fscnt) 193 { 194 /* 195 * Use the "FreeDictionary" ptr for the backup 196 * dictionary. 197 */ 198 if (!FreeDictionary->inittemp(newdict, *InUseDictionary)) 199 return (FALSE); 200 return (InUseDictionary->extract_entries (*FreeDictionary, 201 fs, fscnt)); 202 } 203 204 bool_t 205 db_copy_file(char *infile, char *outfile) 206 { 207 return (InUseDictionary->copyfile(infile, outfile)); 208 209 } 210 211 212 /* 213 * The tok and repl parameters will allow us to merge two dictionaries 214 * that reference tables from different domains (master/replica in live 215 * in different domains). If set to NULL, then the dictionary merge is 216 * done as normal (no name changing). 217 */ 218 db_status 219 db_begin_merge_dict(char *newdict, char *tok, char *repl) 220 { 221 db_status dbstat; 222 223 /* 224 * It is assumed that InUseDictionary has already been initialized. 225 */ 226 dbstat = InUseDictionary->checkpoint(); 227 if (dbstat != DB_SUCCESS) 228 return (dbstat); 229 230 /* 231 * Use the "FreeDictionary" ptr for the backup 232 * dictionary. 233 */ 234 if (!FreeDictionary->init(newdict)) 235 return (DB_INTERNAL_ERROR); 236 237 return (InUseDictionary->merge_dict(*FreeDictionary, 238 tok, repl)); 239 } 240 241 242 db_status 243 db_end_merge_dict() 244 { 245 db_status dbstat; 246 247 dbstat = InUseDictionary->checkpoint(); 248 if (dbstat != DB_SUCCESS) { 249 return (dbstat); 250 } 251 dbstat = InUseDictionary->db_shutdown(); 252 if (dbstat != DB_SUCCESS) { 253 return (dbstat); 254 } 255 dbstat = FreeDictionary->db_shutdown(); 256 if (dbstat != DB_SUCCESS) { 257 return (dbstat); 258 } 259 return (dbstat); 260 } 261 262 263 264 db_status 265 db_abort_merge_dict() 266 { 267 db_status dbstat; 268 269 dbstat = InUseDictionary->db_shutdown(); 270 if (dbstat != DB_SUCCESS) 271 return (dbstat); 272 dbstat = FreeDictionary->db_shutdown(); 273 if (dbstat != DB_SUCCESS) 274 return (dbstat); 275 } 276 277 278 /* 279 * Initialize system (dictionary) using file 'filename'. If system cannot 280 * be read from file, it is initialized to be empty. Returns TRUE if 281 * initialization succeeds, FALSE otherwise. 282 * This function must be called before any other. 283 */ 284 bool_t 285 db_initialize(char * filename) 286 { 287 return (InUseDictionary->init(filename)); 288 } 289 290 291 /* 292 * Massage the dictionary file by replacing the specified token with the 293 * the replacement string. This function is needed to provide backwards 294 * compatibility for providing a transportable dictionary file. The idea 295 * is that rpc.nisd will call this function when it wants to change the 296 * /var/nis/<hostname> strings with something like /var/nis/data. 297 * 298 */ 299 db_status 300 db_massage_dict(char *newdictname, char *tok, char *repl) 301 { 302 return (InUseDictionary->massage_dict(newdictname, tok, repl)); 303 } 304 305 306 307 /* 308 * Create new table using given table name and table descriptor. 309 * Returns DB_SUCCESS if successful; appropriate error code otherwise. 310 */ 311 db_status 312 db_create_table(char * table_name, table_obj * table_desc) 313 { 314 return (InUseDictionary->add_table(table_name, table_desc)); 315 } 316 317 /* 318 * Destroys table named by 'table_name.' Returns DB_SUCCESS if successful, 319 * error code otherwise. Note that currently, the removed table is no 320 * longer accessible from this interface and all files associated with it 321 * are removed from stable storage. 322 */ 323 db_status 324 db_destroy_table(char * table_name) 325 { 326 return (InUseDictionary->delete_table(table_name)); 327 } 328 329 330 /* 331 * Return a copy of the first entry in the specified table, that satisfies 332 * the given attributes. The returned structure 'db_result' contains the status, 333 * the copy of the object, and a 'db_next_desc' to be used for the 'next' 334 * operation. 335 */ 336 db_result * 337 db_first_entry(char * table_name, int numattrs, nis_attr * attrname) 338 { 339 db_result * safety = empty_result(DB_SUCCESS); 340 db_table_desc * tbl = NULL; 341 db * dbase = InUseDictionary->find_table(table_name, &tbl); 342 343 if (tbl == NULL || dbase == NULL) 344 return (set_result(safety, DB_BADTABLE)); 345 else { 346 db_result * res = NULL; 347 db_query *query = NULL; 348 349 if (numattrs != 0) { 350 query = InUseDictionary->translate_to_query(tbl, 351 numattrs, attrname); 352 if (query == NULL) 353 return (set_result(safety, 354 DB_BADQUERY)); 355 } 356 res = dbase->execute(DB_FIRST, query, NULL, NULL); 357 if (query) delete query; 358 if (safety) delete safety; 359 return (res); 360 } 361 } 362 363 /* 364 * Return a copy of the next entry in the specified table as specified by 365 * the 'next_desc'. The returned structure 'db_result' contains the status, 366 * a copy of the object, and a db_next_desc to be used for a subsequent 367 * 'next' operation. 368 */ 369 db_result * 370 db_next_entry(char * table_name, db_next_desc * next_desc) 371 { 372 db_result * safety = empty_result(DB_SUCCESS); 373 db * dbase = InUseDictionary->find_table(table_name); 374 375 if (dbase != NULL) { 376 if (safety) delete safety; 377 return (dbase->execute(DB_NEXT, NULL, NULL, next_desc)); 378 } else 379 return (set_result(safety, DB_BADTABLE)); 380 } 381 382 /* 383 * Indicate to the system that you are no longer interested in the rest of the 384 * results identified by [next_desc]. After executing this operation, the 385 * [next_desc] is no longer valid (cannot be used as an argument for next). 386 */ 387 388 db_result * 389 db_reset_next_entry(char * table_name, db_next_desc * next_desc) 390 { 391 db_result * safety = empty_result(DB_SUCCESS); 392 db * dbase = InUseDictionary->find_table(table_name); 393 394 if (dbase != NULL) { 395 if (safety) delete safety; 396 return (dbase->execute(DB_RESET_NEXT, 397 NULL, NULL, next_desc)); 398 } else 399 return (set_result(safety, DB_BADTABLE)); 400 } 401 402 /* 403 * Returns copies of entries that satisfy the given attributes from table. 404 * Returns the status and entries in a db_result structure. 405 * If no attributes are specified, DB_BADQUERY is returned. 406 */ 407 db_result * 408 __db_list_entries(char * table_name, int numattrs, nis_attr * attrname, 409 bool_t useDeferred) 410 { 411 db_result * safety = empty_result(DB_SUCCESS); 412 db_table_desc * tbl = NULL; 413 db * dbase = InUseDictionary->find_table(table_name, &tbl, 414 useDeferred); 415 416 if (tbl == NULL || dbase == NULL) 417 return (set_result(safety, DB_BADTABLE)); 418 else { 419 db_result * res = NULL; 420 if (numattrs != 0) { 421 db_query *query; 422 query = InUseDictionary->translate_to_query(tbl, 423 numattrs, attrname); 424 if (query == NULL) 425 return (set_result(safety, 426 DB_BADQUERY)); 427 res = dbase->execute(DB_LOOKUP, query, 428 NULL, NULL); 429 delete query; 430 } else { 431 res = dbase->execute(DB_ALL, NULL, NULL, NULL); 432 } 433 if (safety) delete safety; 434 return (res); 435 } 436 } 437 438 db_result * 439 db_list_entries(char *table_name, int numattrs, nis_attr *attrname) { 440 return (__db_list_entries(table_name, numattrs, attrname, TRUE)); 441 } 442 443 /* 444 * Input: A fully qualified object name (example: "x.y.z"). 445 * Output: Returns the first level of the object name ("x"). 446 * If 'tableP' is non-NULL, '*tableP' will contain 447 * the internal table name for "y.z". 448 * 449 * Both the return value and '*tableP' must be freed by the caller. 450 */ 451 char * 452 entryName(char *msg, char *objName, char **tableP) { 453 char *name, *table, *dir; 454 char *myself = "entryName"; 455 456 if (msg == 0) 457 msg = myself; 458 459 name = sdup(msg, T, objName); 460 if (name == 0) 461 return (0); 462 463 dir = strchr(name, '.'); 464 if (dir == 0) { 465 sfree(name); 466 return (0); 467 } 468 *(dir++) = '\0'; 469 470 if (tableP == 0) 471 return (name); 472 473 table = internalTableName(dir); 474 if (table == 0) { 475 sfree(name); 476 return (0); 477 } 478 479 *tableP = table; 480 481 return (name); 482 } 483 484 #define RETSTAT(obj, status) \ 485 { \ 486 if (statP != 0) \ 487 *statP = status; \ 488 return (obj); \ 489 } 490 491 /* 492 * Given a fully qualified object name, retrive a copy of the object, 493 * using the NIS+ DB only (i.e., no LDAP). Avoids using nis_leaf_of() 494 * etc., since they aren't re-entrant. 495 */ 496 nis_object * 497 dbFindObject(char *objName, db_status *statP) { 498 char buf[MAXPATHLEN+NIS_MAXNAMELEN+1]; 499 char *name, *table = 0; 500 nis_attr attr; 501 db *dbase; 502 db_result *res; 503 db_table_desc *tbl = 0; 504 db_query *query; 505 db_mindex *mindex; 506 nis_object *o; 507 int lstat; 508 char *myself = "dbFindObject"; 509 510 if (objName == 0) 511 RETSTAT(0, DB_BADQUERY); 512 513 /* The root dir is treated specially */ 514 table = internalTableName(objName); 515 if (table == 0) 516 RETSTAT(0, DB_BADQUERY); 517 if (strcmp(ROOTDIRFILE, table) == 0) { 518 sfree(table); 519 520 o = get_root_object(); 521 if (o == 0) 522 RETSTAT(0, DB_NOTFOUND); 523 524 RETSTAT(o, DB_SUCCESS); 525 } 526 527 /* If not the root dir, find the directory where the entry lives */ 528 529 sfree(table); 530 name = entryName(myself, objName, &table); 531 if (name == 0 || table == 0) { 532 sfree(name); 533 RETSTAT(0, DB_MEMORY_LIMIT); 534 } 535 536 dbase = InUseDictionary->find_table_noLDAP(table, &tbl, TRUE, TRUE); 537 sfree(table); 538 if (dbase != 0) 539 mindex = dbase->mindex(); 540 if (dbase == 0 || tbl == 0 || mindex == 0) { 541 sfree(name); 542 RETSTAT(0, DB_BADTABLE); 543 } 544 545 WRITELOCKNR(mindex, lstat, "mindex w dbFindObject"); 546 if (lstat != 0) { 547 sfree(name); 548 RETSTAT(0, DB_LOCK_ERROR); 549 } 550 551 attr.zattr_ndx = "name"; 552 attr.zattr_val.zattr_val_val = name; 553 attr.zattr_val.zattr_val_len = slen(name) + 1; 554 555 query = InUseDictionary->translate_to_query(tbl, 1, &attr); 556 if (query == 0) { 557 sfree(name); 558 WRITEUNLOCKNR(mindex, lstat, "mindex wu dbFindObject"); 559 RETSTAT(0, DB_BADQUERY); 560 } 561 562 /* Only want to look in the local DB */ 563 mindex->setNoLDAPquery(); 564 565 res = dbase->execute(DB_LOOKUP, query, 0, 0); 566 567 mindex->clearNoLDAPquery(); 568 569 delete query; 570 571 sfree(name); 572 573 WRITEUNLOCKNR(mindex, lstat, "mindex wu dbFindObject"); 574 if (lstat != 0) { 575 db_free_result(res); 576 RETSTAT(0, DB_LOCK_ERROR); 577 } 578 579 if (res == 0) 580 RETSTAT(0, DB_MEMORY_LIMIT); 581 582 if (res->status != DB_SUCCESS) { 583 db_status st = res->status; 584 585 db_free_result(res); 586 RETSTAT(0, st); 587 } 588 589 if (res->objects.objects_len != 1 || res->objects.objects_val == 0 || 590 res->objects.objects_val[0] == 0) { 591 db_free_result(res); 592 RETSTAT(0, DB_BADOBJECT); 593 } 594 595 o = unmakePseudoEntryObj(res->objects.objects_val[0], 0); 596 597 db_free_result(res); 598 599 if (o == 0) { 600 RETSTAT(0, DB_BADOBJECT); 601 } 602 603 RETSTAT(o, DB_SUCCESS); 604 } 605 606 /* 607 * Return the object specified by 't' or 'objName' from LDAP. Set 608 * the LDAP status in '*statP'. 609 */ 610 nis_object * 611 ldapFindObj(__nis_table_mapping_t *t, char *objName, int *statP) { 612 nis_object *o; 613 int stat; 614 char *myself = "ldapFindObj"; 615 616 if (t == 0) { 617 char *table, tbuf[MAXPATHLEN + NIS_MAXNAMELEN + 1]; 618 619 if (objName == 0) { 620 if (statP != 0) 621 *statP = LDAP_PARAM_ERROR; 622 return (0); 623 } 624 625 /* Look for mapping */ 626 table = internal_table_name(objName, tbuf); 627 if (table == 0) { 628 if (statP != 0) 629 *statP = LDAP_PARAM_ERROR; 630 return (0); 631 } 632 633 t = (__nis_table_mapping_t *)__nis_find_item_mt(table, 634 &ldapMappingList, 0, 0); 635 if (t == 0) { 636 /* Not really an error; just not mapped */ 637 *statP = LDAP_SUCCESS; 638 return (0); 639 } 640 } 641 642 o = 0; 643 stat = objFromLDAP(t, &o, 0, 0); 644 645 if (statP != 0) 646 *statP = stat; 647 648 return (o); 649 } 650 651 /* 652 * Look for the specified object, first locally, then in LDAP. 653 */ 654 nis_object * 655 findObj(char *name, db_status *statP, int *lstatP) { 656 nis_object *o; 657 db_status stat = DB_SUCCESS; 658 int lstat = LDAP_SUCCESS; 659 char *myself = "findObj"; 660 661 o = dbFindObject(name, &stat); 662 663 if (o == 0) { 664 if (stat != DB_NOTFOUND) 665 logmsg(MSG_NOTIMECHECK, LOG_INFO, 666 "%s: DB error %d looking for \"%s\"", 667 myself, stat, NIL(name)); 668 669 o = ldapFindObj(0, name, &lstat); 670 if (o == 0) { 671 if (lstat != LDAP_SUCCESS && 672 lstat != LDAP_NO_SUCH_OBJECT) 673 logmsg(MSG_NOTIMECHECK, LOG_INFO, 674 "%s: LDAP error looking for \"%s\": %s", 675 myself, NIL(name), 676 ldap_err2string(lstat)); 677 } 678 } 679 680 if (statP != 0) 681 *statP = stat; 682 if (lstatP != 0) 683 *lstatP = lstat; 684 685 return (o); 686 } 687 688 /* 689 * Delete the specified object from the local DB. 690 */ 691 db_status 692 dbDeleteObj(char *objName) { 693 nisdb_tsd_t *tsd = __nisdb_get_tsd(); 694 nis_object *o; 695 db_status stat; 696 nisdb_obj_del_t *nod, *tmp; 697 int xid; 698 char *myself = "dbDeleteObj"; 699 700 if (objName == 0) 701 return (DB_SUCCESS); 702 703 /* 704 * Since in-structure locks can't completely protect 705 * during structure deletion, we just note that the 706 * object should be deleted, and leave that for a 707 * (slightly) later time in rpc.nisd, where we can 708 * use the rpc.nisd's table/directory locks for 709 * protection. 710 */ 711 712 if (tsd == 0) 713 return (DB_INTERNAL_ERROR); 714 715 o = dbFindObject(objName, &stat); 716 if (o == 0) { 717 if (stat == DB_NOTFOUND) 718 return (DB_SUCCESS); 719 else 720 return (stat); 721 } 722 723 /* 724 * In order to prevent a chicken-and-egg problem (if the 725 * object doesn't exist in LDAP, is that because we just 726 * haven't written it to LDAP yet, or because it's been 727 * removed), we only allow object deletion if we're the 728 * master for it. 729 */ 730 731 nod = (nisdb_obj_del_t *)am(myself, sizeof (*nod)); 732 if (nod == 0) { 733 nis_destroy_object(o); 734 return (DB_MEMORY_LIMIT); 735 } 736 737 nod->objType = o->zo_data.zo_type; 738 nis_destroy_object(o); 739 740 nod->objName = sdup(myself, T, objName); 741 if (nod->objName == 0) { 742 sfree(nod); 743 return (DB_MEMORY_LIMIT); 744 } 745 746 /* Check for a dup */ 747 for (tmp = tsd->objDelList; tmp != 0; 748 tmp = (nisdb_obj_del_t *)tmp->next) { 749 if (strcmp(nod->objName, tmp->objName) == 0) { 750 sfree(nod->objName); 751 sfree(nod); 752 return (DB_SUCCESS); 753 } 754 } 755 756 /* Insert at start of list */ 757 nod->next = tsd->objDelList; 758 tsd->objDelList = nod; 759 760 return (DB_SUCCESS); 761 } 762 763 /* 764 * Touch (i.e., update the expiration time for) the specified object. 765 */ 766 db_status 767 dbTouchObj(char *objName) { 768 char *ent, *table; 769 db *dbase; 770 db_table_desc *tbl = 0; 771 db_mindex *mindex; 772 nis_attr attr; 773 db_query *query; 774 db_status stat; 775 char *myself = "dbTouchObj"; 776 777 table = internalTableName(objName); 778 if (table == 0) 779 return (DB_BADQUERY); 780 781 if (strcmp(ROOTDIRFILE, table) == 0) { 782 sfree(table); 783 784 if (touchRootDir() == 0) 785 return (DB_SUCCESS); 786 else 787 return (DB_INTERNAL_ERROR); 788 } 789 790 sfree(table); 791 table = 0; 792 ent = entryName(myself, objName, &table); 793 if (ent == 0 || table == 0) { 794 sfree(ent); 795 return (DB_MEMORY_LIMIT); 796 } 797 798 dbase = InUseDictionary->find_table(table, &tbl, TRUE); 799 if (dbase != 0) 800 mindex = dbase->mindex(); 801 if (dbase == 0 || tbl == 0 || mindex == 0) { 802 sfree(ent); 803 sfree(table); 804 return (DB_BADTABLE); 805 } 806 807 attr.zattr_ndx = "name"; 808 attr.zattr_val.zattr_val_val = ent; 809 attr.zattr_val.zattr_val_len = slen(ent) + 1; 810 811 query = InUseDictionary->translate_to_query(tbl, 1, &attr); 812 if (query == 0) { 813 sfree(ent); 814 sfree(table); 815 return (DB_BADQUERY); 816 } 817 818 mindex->touchEntry(query); 819 820 sfree(ent); 821 sfree(table); 822 delete query; 823 824 return (DB_SUCCESS); 825 } 826 827 /* 828 * Create a NIS_TABLE_OBJ. 829 * Borrows heavily from rpc.nisd/nis_db.c:__create_table(). 830 */ 831 db_status 832 dbCreateTable(char *intName, nis_object *obj) { 833 table_col tc[NIS_MAXCOLUMNS+1]; 834 table_obj tobj, *t; 835 int i; 836 char *myself = "dbCreateTable"; 837 838 if (intName == 0 || obj == 0) 839 return (DB_BADTABLE); 840 841 t = &(obj->TA_data); 842 843 /* Make sure there are searchable columns */ 844 for (i = 0; i < t->ta_cols.ta_cols_len; i++) { 845 if (t->ta_cols.ta_cols_val[i].tc_flags & TA_SEARCHABLE) 846 break; 847 } 848 if (i >= t->ta_cols.ta_cols_len) { 849 logmsg(MSG_NOTIMECHECK, LOG_INFO, 850 "%s: No searchable columns in \"%s\" (\"%s\")", 851 myself, NIL(obj->zo_name), NIL(intName)); 852 return (DB_BADTABLE); 853 } 854 855 tobj = *t; 856 /* Shift columns one step right */ 857 for (i = 0; i < tobj.ta_cols.ta_cols_len; i++) { 858 tc[i+1] = tobj.ta_cols.ta_cols_val[i]; 859 } 860 tc[0].tc_name = 0; 861 tc[0].tc_flags = TA_XDR | TA_BINARY; 862 tc[0].tc_rights = 0; 863 tobj.ta_cols.ta_cols_len += 1; 864 tobj.ta_cols.ta_cols_val = tc; 865 866 return (db_create_table(intName, &tobj)); 867 } 868 869 #define TABLE_COL(o, n) o->TA_data.ta_cols.ta_cols_val[n] 870 871 /* 872 * Refresh (if necessary, create), the specified object in the local DB. 873 */ 874 db_status 875 dbRefreshObj(char *name, nis_object *o) { 876 char *objName; 877 __nis_buffer_t b = {0, 0}; 878 nis_object *curObj; 879 db_status stat; 880 char *ent, *table, *objTable; 881 int rstat, isDir = 0, isTable = 0; 882 char *myself = "refreshObj"; 883 884 if (o == 0) 885 /* Delete it */ 886 return (dbDeleteObj(name)); 887 888 /* We don't work on entry objects */ 889 if (o->zo_data.zo_type == NIS_ENTRY_OBJ) 890 return (DB_BADOBJECT); 891 892 if (name != 0) 893 objName = name; 894 else { 895 bp2buf(myself, &b, "%s.%s", NIL(o->zo_name), NIL(o->zo_domain)); 896 objName = b.buf; 897 } 898 899 curObj = dbFindObject(objName, &stat); 900 if (curObj == 0 && stat != DB_NOTFOUND) { 901 sfree(b.buf); 902 return (stat); 903 } 904 905 /* 906 * If the object doesn't change, just touch it to update the 907 * expiration time. 908 */ 909 if (curObj != 0) { 910 if (sameNisPlusObj(o, curObj)) { 911 sfree(b.buf); 912 nis_destroy_object(curObj); 913 return (dbTouchObj(objName)); 914 } 915 916 /* Otherwise, check that the name and type is the same */ 917 if (o->zo_data.zo_type != curObj->zo_data.zo_type || 918 o->zo_name == 0 || curObj->zo_name == 0 || 919 o->zo_domain == 0 || curObj->zo_domain == 0 || 920 strcmp(o->zo_name, curObj->zo_name) != 0 || 921 strcmp(o->zo_domain, curObj->zo_domain) != 0) { 922 sfree(b.buf); 923 nis_destroy_object(curObj); 924 return (DB_BADOBJECT); 925 } 926 927 /* 928 * If the object is a table, we can't allow the scheme 929 * to change. 930 */ 931 if (o->zo_data.zo_type == NIS_TABLE_OBJ) { 932 int i; 933 934 if (o->TA_data.ta_maxcol != 935 curObj->TA_data.ta_maxcol) { 936 sfree(b.buf); 937 nis_destroy_object(curObj); 938 return (DB_BADOBJECT); 939 } 940 941 for (i = 0; i < o->TA_data.ta_maxcol; i++) { 942 if ((TABLE_COL(o, i).tc_flags & 943 TA_SEARCHABLE) != 944 (TABLE_COL(curObj, i).tc_flags & 945 TA_SEARCHABLE)) { 946 sfree(b.buf); 947 nis_destroy_object(curObj); 948 return (DB_BADOBJECT); 949 } 950 } 951 } 952 } else { 953 /* 954 * If we're creating a directory object, make a note 955 * so that we can add it to the serving list and create 956 * the disk file. Similarly, if creating a table, we 957 * also need to create the disk file. 958 */ 959 if (o->zo_data.zo_type == NIS_DIRECTORY_OBJ) 960 isDir = 1; 961 else if (o->zo_data.zo_type == NIS_TABLE_OBJ) 962 isTable = 1; 963 } 964 965 objTable = internalTableName(objName); 966 if (objTable == 0) { 967 sfree(b.buf); 968 if (curObj != 0) 969 nis_destroy_object(curObj); 970 return (DB_BADQUERY); 971 } 972 973 if (strcmp(ROOTDIRFILE, objTable) == 0) { 974 sfree(objTable); 975 976 rstat = update_root_object(ROOTOBJFILE, o); 977 if (rstat == 1) 978 stat = DB_SUCCESS; 979 else 980 stat = DB_INTERNAL_ERROR; 981 } else { 982 nis_attr attr; 983 entry_object *e, eo; 984 entry_col ec[2]; 985 db *dbase; 986 db_table_desc *tbl = 0; 987 db_mindex *mindex; 988 db_result *dbres; 989 int lstat; 990 991 /* Find parent */ 992 ent = entryName(myself, objName, &table); 993 if (ent == 0 || table == 0) { 994 sfree(b.buf); 995 sfree(objTable); 996 sfree(ent); 997 if (curObj != 0) 998 nis_destroy_object(curObj); 999 return (DB_MEMORY_LIMIT); 1000 } 1001 1002 /* 1003 * Calling vanilla find_table() here (which might go to 1004 * LDAP and recurse back to ourselves) so that it should 1005 * work to create a hierarchy of directories. 1006 */ 1007 dbase = InUseDictionary->find_table(table, &tbl, TRUE); 1008 if (dbase != 0) 1009 mindex = dbase->mindex(); 1010 if (dbase == 0 || tbl == 0 || mindex == 0) { 1011 sfree(b.buf); 1012 sfree(objTable); 1013 sfree(ent); 1014 sfree(table); 1015 if (curObj != 0) 1016 nis_destroy_object(curObj); 1017 return (DB_BADTABLE); 1018 } 1019 1020 /* Construct suitable nis_attr and entry_object */ 1021 attr.zattr_ndx = "name"; 1022 attr.zattr_val.zattr_val_val = ent; 1023 attr.zattr_val.zattr_val_len = slen(ent) + 1; 1024 1025 ec[1].ec_flags = 0; 1026 ec[1].ec_value.ec_value_val = ent; 1027 ec[1].ec_value.ec_value_len = attr.zattr_val.zattr_val_len; 1028 1029 eo.en_type = "IN_DIRECTORY"; 1030 eo.en_cols.en_cols_val = ec; 1031 eo.en_cols.en_cols_len = 2; 1032 1033 e = makePseudoEntryObj(o, &eo, 0); 1034 if (e == 0) { 1035 sfree(objTable); 1036 sfree(table); 1037 sfree(ent); 1038 if (curObj != 0) 1039 nis_destroy_object(curObj); 1040 return (DB_INTERNAL_ERROR); 1041 } 1042 1043 /* Only want to update the local DB */ 1044 1045 WRITELOCKNR(mindex, lstat, "mindex w dbRefreshObj"); 1046 if (lstat != 0) { 1047 sfree(objTable); 1048 sfree(table); 1049 sfree(ent); 1050 if (curObj != 0) 1051 nis_destroy_object(curObj); 1052 return (DB_LOCK_ERROR); 1053 } 1054 mindex->setNoWriteThrough(); 1055 mindex->setNoLDAPquery(); 1056 1057 dbres = db_add_entry_x(table, 1, &attr, e, 0, 0); 1058 1059 mindex->clearNoLDAPquery(); 1060 mindex->clearNoWriteThrough(); 1061 WRITEUNLOCKNR(mindex, lstat, "mindex wu dbRefreshObj"); 1062 if (lstat != 0) { 1063 sfree(objTable); 1064 sfree(table); 1065 sfree(ent); 1066 if (curObj != 0) 1067 nis_destroy_object(curObj); 1068 db_free_result(dbres); 1069 return (DB_LOCK_ERROR); 1070 } 1071 1072 sfree(ent); 1073 sfree(table); 1074 1075 if (dbres == 0) 1076 stat = DB_MEMORY_LIMIT; 1077 else 1078 stat = dbres->status; 1079 1080 db_free_result(dbres); 1081 1082 /* 1083 * If successful so far, add the transaction. 1084 */ 1085 if (stat == DB_SUCCESS) { 1086 int xid, st; 1087 db_status ds; 1088 nis_object *dirObj; 1089 1090 /* Find the directory where this is added */ 1091 dirObj = dbFindObject(o->zo_domain, &ds); 1092 if (dirObj == 0) { 1093 sfree(objTable); 1094 if (curObj != 0) 1095 nis_destroy_object(curObj); 1096 return (ds); 1097 } 1098 1099 xid = beginTransaction(); 1100 if (xid == 0) { 1101 sfree(objTable); 1102 if (curObj != 0) 1103 nis_destroy_object(curObj); 1104 nis_destroy_object(dirObj); 1105 return (DB_INTERNAL_ERROR); 1106 } 1107 1108 st = addUpdate((curObj == 0) ? ADD_NAME : MOD_NAME_NEW, 1109 objName, 0, 0, o, curObj, 0); 1110 if (st != 0) { 1111 (void) abort_transaction(xid); 1112 sfree(objTable); 1113 if (curObj != 0) 1114 nis_destroy_object(curObj); 1115 nis_destroy_object(dirObj); 1116 return (DB_INTERNAL_ERROR); 1117 } 1118 1119 st = endTransaction(xid, dirObj); 1120 if (st != 0) 1121 stat = DB_INTERNAL_ERROR; 1122 1123 if (curObj != 0) 1124 nis_destroy_object(curObj); 1125 nis_destroy_object(dirObj); 1126 } 1127 1128 /* 1129 * If it's a table or directory, create the DB file. 1130 * If a directory, also add it to the serving list. 1131 */ 1132 if (stat == DB_SUCCESS &&(isDir || isTable)) { 1133 if (isDir) { 1134 stat = db_create_table(objTable, 1135 &tbl_prototype); 1136 } else { 1137 stat = dbCreateTable(objTable, o); 1138 } 1139 } 1140 sfree(objTable); 1141 } 1142 1143 sfree(b.buf); 1144 1145 return (stat); 1146 } 1147 1148 /* 1149 * Replace the object stored with the mapping 't'. Return TRUE if 1150 * at least one object was replaced, FALSE otherwise. 1151 */ 1152 bool_t 1153 replaceMappingObj(__nis_table_mapping_t *t, nis_object *n) { 1154 __nis_table_mapping_t *x; 1155 nis_object *old = 0; 1156 int assigned = 0; 1157 1158 /* 1159 * The alternate mappings are usually mostly copies 1160 * of the original, so we try to make sure that we 1161 * don't free the same nis_object twice. 1162 */ 1163 for (x = t; x != 0; x = (__nis_table_mapping_t *)x->next) { 1164 if (old == 0) { 1165 old = x->obj; 1166 if (x->obj != 0) 1167 nis_destroy_object(x->obj); 1168 } else { 1169 if (x->obj != old && x->obj != 0) 1170 nis_destroy_object(x->obj); 1171 } 1172 x->obj = n; 1173 assigned++; 1174 } 1175 1176 return (assigned > 0); 1177 } 1178 1179 /* 1180 * Set object type, column info, and obj for the specified 1181 * mapping 't' from the object 'o'. Returns zero if 'o' was unused, 1182 * and should be freed by the caller, larger than zero otherwise. 1183 */ 1184 int 1185 setMappingObjTypeEtc(__nis_table_mapping_t *t, nis_object *o) { 1186 __nis_table_mapping_t *x; 1187 int ls, ret; 1188 int i; 1189 1190 if (t == 0 || o == 0) 1191 return (0); 1192 1193 t->objType = o->zo_data.zo_type; 1194 for (x = t; x != 0; x = (__nis_table_mapping_t *)x->next) { 1195 if (x != t) { 1196 x->objType = t->objType; 1197 } 1198 if (x->objType == NIS_TABLE_OBJ) { 1199 /* 1200 * If we have rules, this mapping is for table entries, 1201 * and we need the column names. Otherwise, remove the 1202 * column names (if any). 1203 */ 1204 1205 for (i = 0; i < x->numColumns; i++) 1206 sfree(x->column[i]); 1207 sfree(x->column); 1208 x->column = 0; 1209 x->numColumns = 0; 1210 } 1211 } 1212 ret = replaceMappingObj(t, o); 1213 1214 return (ret); 1215 } 1216 1217 /* 1218 * Retrieve the specified object (internal DB name) from LDAP, and 1219 * refresh/create as appropriate. 1220 */ 1221 db_status 1222 dbCreateFromLDAP(char *intName, int *ldapStat) { 1223 __nis_table_mapping_t *t; 1224 int lstat, doDestroy; 1225 nis_object *obj = 0; 1226 db_status dstat; 1227 char *myself = "dbCreateFromLDAP"; 1228 1229 if (!useLDAPrespository) { 1230 if (ldapStat != 0) 1231 *ldapStat = LDAP_SUCCESS; 1232 return (DB_SUCCESS); 1233 } 1234 1235 t = (__nis_table_mapping_t *)__nis_find_item_mt(intName, 1236 &ldapMappingList, 1237 0, 0); 1238 1239 /* No mapping isn't a failure */ 1240 if (t == 0) { 1241 if (ldapStat != 0) 1242 *ldapStat = LDAP_SUCCESS; 1243 return (DB_NOTFOUND); 1244 } 1245 1246 lstat = objFromLDAP(t, &obj, 0, 0); 1247 if (ldapStat != 0) 1248 *ldapStat = lstat; 1249 if (lstat != LDAP_SUCCESS) 1250 return (DB_NOTFOUND); 1251 1252 /* 1253 * If the LDAP operation was successful, but 'obj' is NULL, 1254 * there's no mapping for this object, and we're done. 1255 */ 1256 if (obj == 0) 1257 return (DB_SUCCESS); 1258 1259 /* Update the mapping with object info */ 1260 doDestroy = setMappingObjTypeEtc(t, obj) == 0; 1261 1262 dstat = dbRefreshObj(t->objName, obj); 1263 1264 if (doDestroy) 1265 nis_destroy_object(obj); 1266 1267 return (dstat); 1268 } 1269 1270 /* 1271 * Up- (fromLDAP==0) or down- (fromLDAP==1) load all LDAP mapped data. 1272 * Returns an LDAP error status. 1273 */ 1274 int 1275 loadAllLDAP(int fromLDAP, void *cookie, db_status *dstatP) { 1276 __nis_table_mapping_t *t, *start; 1277 int stat = LDAP_SUCCESS; 1278 db_status dstat = DB_SUCCESS; 1279 db *dbase; 1280 db_table_desc *tbl = 0; 1281 db_mindex *mindex; 1282 char *myself = "loadAllLDAP"; 1283 1284 /* 1285 * If the 'cookie' and '*cookie' are non-NULL, start scanning 1286 * the mappings from '*cookie'. When we return with an error, 1287 * we set '*cookie' to point to the mapping being processed. 1288 * This enables our caller to react appropriately, and retry 1289 * if desired. 1290 * 1291 * The cookie is opaque to our caller, who's only allowed to 1292 * initialize *cookie to NULL. 1293 */ 1294 if (cookie != 0) { 1295 start = *((__nis_table_mapping_t **)cookie); 1296 if (start == 0) 1297 start = ldapMappingSeq; 1298 } else { 1299 start = ldapMappingSeq; 1300 } 1301 1302 for (t = start; t != 0; t = (__nis_table_mapping_t *)t->seqNext) { 1303 __nis_table_mapping_t **tp; 1304 int nm; 1305 1306 if (fromLDAP) { 1307 /* Are there any mappings for the object proper ? */ 1308 tp = selectTableMapping(t, 0, 0, 1, t->dbId, &nm); 1309 if (tp != 0 && nm > 0) { 1310 dstat = dbCreateFromLDAP(t->objPath, &stat); 1311 if (dstat != DB_SUCCESS) { 1312 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1313 "%s: DB error %d creating \"%s\": %s", 1314 myself, dstat, NIL(t->objName), 1315 ldap_err2string(stat)); 1316 if (cookie != 0) 1317 *((__nis_table_mapping_t **) 1318 cookie) = t; 1319 if (dstatP != 0) 1320 *dstatP = dstat; 1321 else if (stat == LDAP_SUCCESS) 1322 stat = LDAP_OPERATIONS_ERROR; 1323 sfree(tp); 1324 return (stat); 1325 } 1326 } 1327 sfree(tp); 1328 1329 /* Any mappings for table entries ? */ 1330 tp = selectTableMapping(t, 0, 0, 0, t->dbId, &nm); 1331 if (tp == 0 || nm <= 0) { 1332 sfree(tp); 1333 continue; 1334 } 1335 sfree(tp); 1336 1337 /* 1338 * The object itself must exist in the local 1339 * DB by now. Get the db_mindex and let 1340 * db_mindex::queryLDAP() do the work; if 1341 * the object isn't a table, queryLDAP() 1342 * will do nothing and return success. 1343 */ 1344 dbase = InUseDictionary->find_table(t->objPath, 1345 &tbl, TRUE); 1346 if (dbase != 0) 1347 mindex = dbase->mindex(); 1348 if (dbase == 0 || tbl == 0 || mindex == 0) { 1349 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1350 "%s: No local DB entry for \"%s\" (%s:%s)", 1351 myself, NIL(t->objPath), 1352 NIL(t->dbId), NIL(t->objName)); 1353 if (cookie != 0) 1354 *((__nis_table_mapping_t **)cookie) = 1355 t; 1356 if (dstatP != 0) 1357 *dstatP = DB_BADTABLE; 1358 return ((dstatP != 0) ? 1359 LDAP_SUCCESS : LDAP_OPERATIONS_ERROR); 1360 } 1361 mindex->setInitialLoad(); 1362 stat = mindex->queryLDAP(0, t->dbId, 0); 1363 mindex->clearInitialLoad(); 1364 if (stat != LDAP_SUCCESS) { 1365 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1366 "%s: LDAP error retrieving entries for %s:%s: %s", 1367 myself, NIL(t->dbId), NIL(t->objName), 1368 ldap_err2string(stat)); 1369 if (cookie != 0) 1370 *((__nis_table_mapping_t **)cookie) = 1371 t; 1372 if (dstatP != 0) 1373 *dstatP = DB_SUCCESS; 1374 return (stat); 1375 } 1376 } else { 1377 nis_object *obj; 1378 char *ent, *objPath; 1379 int freeObjPath = 0; 1380 1381 /* 1382 * Up-loading to LDAP, so the object must 1383 * already exist in the local DB. 1384 */ 1385 obj = dbFindObject(t->objName, &dstat); 1386 if (obj == 0) { 1387 if (dstat == DB_NOTFOUND) 1388 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1389 "%s: No local DB object for \"%s\" (%s:%s); skipping up-load", 1390 myself, NIL(t->objPath), 1391 NIL(t->dbId), 1392 NIL(t->objName)); 1393 else 1394 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1395 "%s: DB error %d for \"%s\" (%s:%s); skipping up-load", 1396 myself, dstat, 1397 NIL(t->objPath), 1398 NIL(t->dbId), 1399 NIL(t->objName)); 1400 continue; 1401 } 1402 1403 /* 1404 * If it's a table or directory, there will be 1405 * a dictionary entry for the object itself. 1406 * Otherwise, we need the dictionary entry for 1407 * the parent directory. 1408 * 1409 * For a table, we need the db_mindex for both the 1410 * table object itself, as well as for the parent 1411 * directory (in order to store table entries). 1412 * We start with the latter. 1413 */ 1414 if (obj->zo_data.zo_type == NIS_DIRECTORY_OBJ) { 1415 objPath = t->objPath; 1416 ent = 0; 1417 } else { 1418 objPath = 0; 1419 ent = entryName(myself, t->objName, &objPath); 1420 if (ent == 0 || objPath == 0) { 1421 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1422 "%s: Error deriving entry/DB-table names for %s:%s; skipping up-load", 1423 myself, NIL(t->dbId), 1424 NIL(t->objName)); 1425 sfree(ent); 1426 sfree(objPath); 1427 nis_destroy_object(obj); 1428 obj = 0; 1429 continue; 1430 } 1431 freeObjPath = 1; 1432 } 1433 1434 dbase = InUseDictionary->find_table(objPath, 1435 &tbl, TRUE); 1436 if (dbase != 0) 1437 mindex = dbase->mindex(); 1438 if (dbase == 0 || tbl == 0 || mindex == 0) { 1439 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1440 "%s: No local DB entry for \"%s\" (%s:%s); skipping up-load", 1441 myself, objPath, 1442 NIL(t->dbId), NIL(t->objName)); 1443 sfree(ent); 1444 if (freeObjPath) 1445 sfree(objPath); 1446 nis_destroy_object(obj); 1447 obj = 0; 1448 continue; 1449 } 1450 1451 /* 1452 * Our next action(s) depend on the object type: 1453 * 1454 * directory Store dir object 1455 * 1456 * table Store table obj, as well 1457 * as any entries in the 1458 * table 1459 * 1460 * other Store object; we need to 1461 * build a db_query specifying 1462 * the first-level name of the 1463 * object. 1464 * 1465 * storeLDAP() will just do nothing and return 1466 * success if we try to, say, store a table object 1467 * when only the table entries are mapped. Hence, 1468 * we don't have to worry about those distinctions 1469 * here. 1470 */ 1471 if (obj->zo_data.zo_type == NIS_DIRECTORY_OBJ) { 1472 stat = mindex->storeLDAP(0, 0, obj, 0, t->dbId); 1473 } else { 1474 nis_attr attr; 1475 db_query *q; 1476 1477 attr.zattr_ndx = "name"; 1478 attr.zattr_val.zattr_val_val = ent; 1479 attr.zattr_val.zattr_val_len = slen(ent) + 1; 1480 1481 q = new db_query(mindex->getScheme(), 1, &attr); 1482 if (q == 0) { 1483 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1484 "%s: error creating db_query for \"%s\" in \"%s\"; skipping up-load", 1485 myself, ent, objPath); 1486 sfree(ent); 1487 if (freeObjPath) 1488 sfree(objPath); 1489 nis_destroy_object(obj); 1490 obj = 0; 1491 continue; 1492 } 1493 1494 stat = mindex->storeLDAP(q, 0, obj, 0, t->dbId); 1495 1496 delete q; 1497 1498 } 1499 1500 sfree(ent); 1501 if (freeObjPath) 1502 sfree(objPath); 1503 1504 if (stat != LDAP_SUCCESS) { 1505 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1506 "%s: Error storing %s:%s to LDAP: %s", 1507 myself, NIL(t->dbId), NIL(t->objName), 1508 ldap_err2string(stat)); 1509 nis_destroy_object(obj); 1510 obj = 0; 1511 if (cookie != 0) 1512 *((__nis_table_mapping_t **) 1513 cookie) = t; 1514 if (dstatP != 0) 1515 *dstatP = DB_SUCCESS; 1516 return (stat); 1517 } 1518 1519 /* Any mappings for table entries ? */ 1520 tp = selectTableMapping(t, 0, 0, 0, t->dbId, &nm); 1521 if (tp == 0 || nm <= 0) { 1522 sfree(tp); 1523 nis_destroy_object(obj); 1524 obj = 0; 1525 continue; 1526 } 1527 sfree(tp); 1528 1529 /* 1530 * If it's a table, we also need to store the table 1531 * entries. 1532 */ 1533 if (obj->zo_data.zo_type == NIS_TABLE_OBJ) { 1534 tbl = 0; 1535 dbase = InUseDictionary->find_table(t->objPath, 1536 &tbl, TRUE); 1537 if (dbase != 0) 1538 mindex = dbase->mindex(); 1539 if (dbase == 0 || tbl == 0 || mindex == 0) { 1540 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1541 "%s: No local DB entry for \"%s\" (%s:%s); skipping entry up-load", 1542 myself, NIL(t->objPath), 1543 NIL(t->dbId), NIL(t->objName)); 1544 nis_destroy_object(obj); 1545 obj = 0; 1546 continue; 1547 } 1548 1549 stat = mindex->storeLDAP(0, 0, obj, 0, t->dbId); 1550 1551 if (stat != LDAP_SUCCESS) { 1552 logmsg(MSG_NOTIMECHECK, LOG_ERR, 1553 "%s: Error storing %s:%s entries to LDAP: %s", 1554 myself, NIL(t->dbId), 1555 NIL(t->objName), 1556 ldap_err2string(stat)); 1557 nis_destroy_object(obj); 1558 obj = 0; 1559 if (cookie != 0) 1560 *((__nis_table_mapping_t **) 1561 cookie) = t; 1562 if (dstatP != 0) 1563 *dstatP = DB_SUCCESS; 1564 return (stat); 1565 } 1566 } 1567 nis_destroy_object(obj); 1568 obj = 0; 1569 } 1570 } 1571 1572 if (dstatP != 0) 1573 *dstatP = dstat; 1574 return (stat); 1575 } 1576 1577 /* 1578 * Object identified by given attribute name is added to specified table. 1579 * If object already exists, it is replaced. If more than one object 1580 * matches the given attribute name, DB_NOTUNIQUE is returned. 1581 */ 1582 static 1583 db_result * 1584 db_add_entry_x(char * tab, int numattrs, nis_attr * attrname, 1585 entry_obj * newobj, int skiplog, int nosync) 1586 { 1587 db_result * safety = empty_result(DB_SUCCESS); 1588 db_table_desc * tbl = NULL; 1589 db * dbase = InUseDictionary->find_table(tab, &tbl, FALSE); 1590 1591 if (tbl == NULL || dbase == NULL) { 1592 return (set_result(safety, DB_BADTABLE)); 1593 } else if (skiplog) { 1594 db_result * res; 1595 res = dbase->execute(DB_ADD_NOLOG, NULL, 1596 (entry_object *) newobj, NULL); 1597 if (safety) delete safety; 1598 return (res); 1599 } else { 1600 db_result *res; 1601 db_query * 1602 query = InUseDictionary->translate_to_query(tbl, 1603 numattrs, attrname); 1604 if (query == NULL) 1605 return (set_result(safety, DB_BADQUERY)); 1606 if (nosync) 1607 res = dbase->execute(DB_ADD_NOSYNC, 1608 query, (entry_object *) newobj, NULL); 1609 else 1610 res = dbase->execute(DB_ADD, query, 1611 (entry_object *) newobj, NULL); 1612 delete query; 1613 if (safety) delete safety; 1614 return (res); 1615 } 1616 } 1617 1618 db_result * 1619 db_add_entry(char * tab, int numattrs, nis_attr * attrname, 1620 entry_obj * newobj) 1621 { 1622 return (db_add_entry_x(tab, numattrs, attrname, newobj, 0, 0)); 1623 } 1624 1625 db_result * 1626 __db_add_entry_nolog(char * tab, int numattrs, nis_attr * attrname, 1627 entry_obj * newobj) 1628 { 1629 return (db_add_entry_x(tab, numattrs, attrname, newobj, 1, 0)); 1630 } 1631 1632 db_result * 1633 __db_add_entry_nosync(char * tab, int numattrs, nis_attr * attrname, 1634 entry_obj * newobj) 1635 { 1636 return (db_add_entry_x(tab, numattrs, attrname, newobj, 0, 1)); 1637 } 1638 1639 /* 1640 * Remove object identified by given attributes from specified table. 1641 * If no attribute is supplied, all entries in table are removed. 1642 * If attributes identify more than one object, all objects are removed. 1643 */ 1644 1645 db_result * 1646 db_remove_entry_x(char * table_name, int num_attrs, nis_attr * attrname, 1647 int nosync) 1648 { 1649 db_result * safety = empty_result(DB_SUCCESS); 1650 db_table_desc * tbl = NULL; 1651 db * dbase = InUseDictionary->find_table(table_name, &tbl, FALSE); 1652 db_result * res; 1653 1654 if (tbl == NULL || dbase == NULL) 1655 return (set_result(safety, DB_BADTABLE)); 1656 else { 1657 if (num_attrs != 0) { 1658 db_query *query; 1659 query = InUseDictionary->translate_to_query(tbl, 1660 num_attrs, attrname); 1661 if (query == NULL) 1662 return (set_result(safety, 1663 DB_BADQUERY)); 1664 if (nosync) 1665 res = dbase->execute(DB_REMOVE_NOSYNC, 1666 query, NULL, NULL); 1667 else 1668 res = dbase->execute(DB_REMOVE, query, 1669 NULL, NULL); 1670 delete query; 1671 } else { 1672 if (nosync) 1673 res = dbase->execute(DB_REMOVE_NOSYNC, 1674 NULL, NULL, NULL); 1675 else 1676 res = dbase->execute(DB_REMOVE, 1677 NULL, NULL, NULL); 1678 } 1679 if (safety) delete safety; 1680 return (res); 1681 } 1682 } 1683 1684 db_result * 1685 db_remove_entry(char * table_name, int num_attrs, nis_attr * attrname) 1686 { 1687 return (db_remove_entry_x(table_name, num_attrs, attrname, 0)); 1688 } 1689 1690 db_result * 1691 __db_remove_entry_nosync(char * table_name, int num_attrs, nis_attr * attrname) 1692 { 1693 return (db_remove_entry_x(table_name, num_attrs, attrname, 1)); 1694 } 1695 1696 /* Return a copy of the version of specified table. */ 1697 vers * 1698 db_version(char * table_name) 1699 { 1700 db * dbase = InUseDictionary->find_table(table_name); 1701 1702 if (dbase == NULL) 1703 return (NULL); 1704 vers* v = new vers(dbase->get_version()); 1705 if (v == NULL) 1706 WARNING("nis_db::db_version: cannot allocate space"); 1707 return (v); 1708 } 1709 1710 /* Return log entries since (later than) given version 'v' of table. */ 1711 db_log_list * 1712 db_log_entries_since(char * table_name, vers * v) 1713 { 1714 db * dbase = InUseDictionary->find_table(table_name); 1715 1716 if (dbase == NULL) 1717 return (NULL); 1718 return (dbase->get_log_entries_since(v)); 1719 } 1720 1721 db_status 1722 db_sync_log(char *table_name) { 1723 1724 db * dbase = InUseDictionary->find_table(table_name); 1725 1726 if (dbase == NULL) 1727 return (DB_BADTABLE); 1728 return (dbase->sync_log()); 1729 } 1730 1731 /* 1732 * Apply the given update specified in 'entry' to the specified table. 1733 * Returns DB_SUCCESS if update was executed. 1734 * Returns DB_NOTFOUND if update occurs too early to be applied. 1735 */ 1736 db_status 1737 db_apply_log_entry(char * table_name, db_log_entry * entry) 1738 { 1739 db * dbase = InUseDictionary->find_table(table_name, NULL, FALSE); 1740 1741 if (dbase == NULL) 1742 return (DB_BADTABLE); 1743 if (dbase->execute_log_entry(entry)) 1744 return (DB_SUCCESS); /* got executed */ 1745 else 1746 return (DB_NOTFOUND); /* not executed */ 1747 } 1748 1749 /* 1750 * Checkpoint specified table (i.e. incorporate logged updates to main 1751 * database file). If table_name is NULL, checkpoint all tables that 1752 * needs it. 1753 */ 1754 db_status 1755 db_checkpoint(char * table_name) 1756 { 1757 return (InUseDictionary->db_checkpoint(table_name)); 1758 } 1759 1760 /* Print names of tables in system. */ 1761 void 1762 db_print_table_names() 1763 { 1764 int i; 1765 db_table_names * answer = InUseDictionary->get_table_names(); 1766 1767 if (answer != NULL) { 1768 for (i = 0; i < answer->db_table_names_len; i++) { 1769 printf("%s\n", answer->db_table_names_val[i]); 1770 delete answer->db_table_names_val[i]; 1771 } 1772 delete answer->db_table_names_val; 1773 delete answer; 1774 } 1775 } 1776 1777 /* Print statistics of specified table to stdout. */ 1778 db_status 1779 db_stats(char * table_name) 1780 { 1781 db_table_desc * tbl = NULL; 1782 db *dbase = InUseDictionary->find_table(table_name, &tbl); 1783 1784 if (tbl == NULL || dbase == NULL || tbl->scheme == NULL) 1785 return (DB_BADTABLE); 1786 1787 dbase->print(); 1788 tbl->scheme->print(); 1789 return (DB_SUCCESS); 1790 } 1791 1792 1793 /* Print statistics of indices of specified table to stdout. */ 1794 db_status 1795 db_print_all_indices(char * table_name) 1796 { 1797 db * dbase = InUseDictionary->find_table(table_name); 1798 1799 if (dbase == NULL) 1800 return (DB_BADTABLE); 1801 dbase->print_all_indices(); 1802 return (DB_SUCCESS); 1803 } 1804 1805 /* Print specified index of table to stdout. */ 1806 db_status 1807 db_print_index(char * table_name, int which) 1808 { 1809 db * dbase = InUseDictionary->find_table(table_name); 1810 1811 if (dbase == NULL) 1812 return (DB_BADTABLE); 1813 dbase->print_index(which); 1814 return (DB_SUCCESS); 1815 } 1816 1817 /* close open files */ 1818 db_status 1819 db_standby(char * table_name) 1820 { 1821 return (InUseDictionary->db_standby(table_name)); 1822 } 1823 1824 /* Returns DB_SUCCESS if table exists; DB_BADTABLE if table does not exist. */ 1825 db_status 1826 db_table_exists(char * table_name) 1827 { 1828 db_table_desc *dbtab = InUseDictionary->find_table_desc(table_name); 1829 1830 if (dbtab == NULL) 1831 return (DB_BADTABLE); 1832 return (DB_SUCCESS); 1833 } 1834 1835 /* 1836 * Returns DB_SUCCESS if table exists; DB_BADTABLE if table does not exist. 1837 * If table already loaded, unload it. 1838 */ 1839 db_status 1840 db_unload_table(char * table_name) 1841 { 1842 db_table_desc * 1843 dbtab = InUseDictionary->find_table_desc(table_name); 1844 if (dbtab == NULL) 1845 return (DB_BADTABLE); 1846 // unload 1847 if (dbtab->database != NULL) { 1848 delete dbtab->database; 1849 dbtab->database = NULL; 1850 } 1851 return (DB_SUCCESS); 1852 } 1853 1854 /* 1855 * Put the specified table in deferred mode, which means that updates go 1856 * to the original table, but reads are satisfied out of a copy (which we 1857 * make here). Thus, "defer" refers to the table as seen by read requests, 1858 * since for them, changes are deferred. 1859 */ 1860 db_status 1861 __db_defer(char *table_name) { 1862 db_status stat; 1863 1864 stat = InUseDictionary->defer(table_name); 1865 return (stat); 1866 } 1867 1868 /* 1869 * Commit deferred changes for the specified table. I.e., make visible 1870 * any updates made since the table was deferred. 1871 */ 1872 db_status 1873 __db_commit(char *table_name) { 1874 db_status stat; 1875 1876 stat = InUseDictionary->commit(table_name); 1877 return (stat); 1878 } 1879 1880 /* 1881 * Rollback, i.e., return to the state before we entered deferred mode. 1882 */ 1883 db_status 1884 __db_rollback(char *table_name) { 1885 db_status stat; 1886 1887 stat = InUseDictionary->rollback(table_name); 1888 return (stat); 1889 } 1890 1891 db_status 1892 __db_configure(char *table_name) { 1893 db_status stat; 1894 char tablePath[MAXPATHLEN + NIS_MAXNAMELEN + 1]; 1895 db *dbase = InUseDictionary->find_table(table_name, NULL); 1896 1897 if (dbase == NULL || table_name == 0) 1898 return (DB_BADTABLE); 1899 1900 if (strlen(table_name) >= sizeof (tablePath)) 1901 return (DB_BADQUERY); 1902 1903 if (internal_table_name(table_name, tablePath) == 0) 1904 return (DB_STORAGE_LIMIT); 1905 1906 if (dbase->configure(tablePath)) 1907 stat = DB_SUCCESS; 1908 else 1909 stat = DB_INTERNAL_ERROR; 1910 1911 return (stat); 1912 } 1913 1914 /* 1915 * During some rpc.nisd operations (such as when recovering the trans.log), 1916 * we don't want to use the LDAP repository, so we provide a main switch. 1917 * Note that we expect this to be used only when rpc.nisd is single-threaded, 1918 * so there is no need for synchronization when reading or modifying the 1919 * value of the main switch. 1920 */ 1921 int useLDAPrespository = 1; 1922 1923 void 1924 __db_disallowLDAP(void) { 1925 useLDAPrespository = 0; 1926 } 1927 1928 void 1929 __db_allowLDAP(void) { 1930 useLDAPrespository = 1; 1931 } 1932 1933 } /* extern "C" */ 1934