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.
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.
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]
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
27 * Copyright 2015 RackTop Systems.
31 #include <sys/param.h>
35 #include "db_headers.h"
38 #include "db_dictionary.h"
39 #include "db_pickle.h"
42 #include "ldap_util.h"
43 #include "ldap_parse.h"
44 #include "ldap_glob.h"
46 #include "ldap_glob.h"
48 db_dictionary curdict
;
49 db_dictionary tempdict
; /* a temporary one */
51 db_dictionary
*InUseDictionary
= &curdict
;
52 db_dictionary
*FreeDictionary
= &tempdict
;
55 static db_result
*db_add_entry_x(char *tab
, int numattrs
,
56 nis_attr
*attrname
, entry_obj
* newobj
,
57 int skiplog
, int nosync
);
58 db_status
db_table_exists(char *table_name
);
61 * (Imported from rpc.nisd/nis_xx_proc.c)
63 * 'tbl_prototype' is used to create a table that holds a directory.
65 static table_col cols
[2] = {
66 {(char *)"object", TA_BINARY
+TA_XDR
, 0},
67 {(char *)"name", TA_CASE
+TA_SEARCHABLE
, 0}
70 table_obj tbl_prototype
= { (char *)"DIRECTORY", 2, ' ', {2, &cols
[0]}, NULL
};
74 * Free resources associated with a db_result structure
77 db_free_result(db_result
*dr
)
84 /* Can't have valid objects */
85 if (dr
->status
!= DB_SUCCESS
) {
90 for (i
= 0; i
< dr
->objects
.objects_len
; i
++)
91 free_entry(dr
->objects
.objects_val
[i
]);
92 free(dr
->objects
.objects_val
);
97 /* Return an empty db_result structure with its status field set to 's'. */
99 empty_result(db_status s
)
101 db_result
* res
= new db_result
;
104 res
->nextinfo
.db_next_desc_len
= 0;
105 res
->nextinfo
.db_next_desc_val
= NULL
;
106 res
->objects
.objects_len
= 0;
107 res
->objects
.objects_val
= NULL
;
109 WARNING("nis_db::empty_result: cannot allocate space");
115 set_result(db_result
* res
, db_status s
)
124 * Given a FQ object name for a table or directory, return the (db *)
125 * corresponding to the object.
128 tableDB(char *tableName
) {
129 db_table_desc
*tbl
= 0;
133 intName
= internalTableName(tableName
);
137 dbase
= InUseDictionary
->find_table(intName
, &tbl
);
147 db_in_dict_file(char *name
)
149 return (InUseDictionary
->find_table_desc(name
) != NULL
);
154 *db_perror(db_status dbstat
)
156 const char *str
= NULL
;
174 case DB_MEMORY_LIMIT
:
175 str
= "Memory limit exceeded";
177 case DB_STORAGE_LIMIT
:
178 str
= "Database storage limit exceeded";
180 case DB_INTERNAL_ERROR
:
181 str
= "Database internal error";
184 str
= "Sync of log file failed";
187 str
= "Unknown Error";
194 db_extract_dict_entries(char *newdict
, char **fs
, int fscnt
)
197 * Use the "FreeDictionary" ptr for the backup
200 if (!FreeDictionary
->inittemp(newdict
, *InUseDictionary
))
202 return (InUseDictionary
->extract_entries (*FreeDictionary
,
207 db_copy_file(char *infile
, char *outfile
)
209 return (InUseDictionary
->copyfile(infile
, outfile
));
215 * The tok and repl parameters will allow us to merge two dictionaries
216 * that reference tables from different domains (master/replica in live
217 * in different domains). If set to NULL, then the dictionary merge is
218 * done as normal (no name changing).
221 db_begin_merge_dict(char *newdict
, char *tok
, char *repl
)
226 * It is assumed that InUseDictionary has already been initialized.
228 dbstat
= InUseDictionary
->checkpoint();
229 if (dbstat
!= DB_SUCCESS
)
233 * Use the "FreeDictionary" ptr for the backup
236 if (!FreeDictionary
->init(newdict
))
237 return (DB_INTERNAL_ERROR
);
239 return (InUseDictionary
->merge_dict(*FreeDictionary
,
249 dbstat
= InUseDictionary
->checkpoint();
250 if (dbstat
!= DB_SUCCESS
) {
253 dbstat
= InUseDictionary
->db_shutdown();
254 if (dbstat
!= DB_SUCCESS
) {
257 dbstat
= FreeDictionary
->db_shutdown();
258 if (dbstat
!= DB_SUCCESS
) {
267 db_abort_merge_dict()
271 dbstat
= InUseDictionary
->db_shutdown();
272 if (dbstat
!= DB_SUCCESS
)
274 dbstat
= FreeDictionary
->db_shutdown();
275 if (dbstat
!= DB_SUCCESS
)
281 * Initialize system (dictionary) using file 'filename'. If system cannot
282 * be read from file, it is initialized to be empty. Returns TRUE if
283 * initialization succeeds, FALSE otherwise.
284 * This function must be called before any other.
287 db_initialize(char * filename
)
289 return (InUseDictionary
->init(filename
));
294 * Massage the dictionary file by replacing the specified token with the
295 * the replacement string. This function is needed to provide backwards
296 * compatibility for providing a transportable dictionary file. The idea
297 * is that rpc.nisd will call this function when it wants to change the
298 * /var/nis/<hostname> strings with something like /var/nis/data.
302 db_massage_dict(char *newdictname
, char *tok
, char *repl
)
304 return (InUseDictionary
->massage_dict(newdictname
, tok
, repl
));
310 * Create new table using given table name and table descriptor.
311 * Returns DB_SUCCESS if successful; appropriate error code otherwise.
314 db_create_table(char * table_name
, table_obj
* table_desc
)
316 return (InUseDictionary
->add_table(table_name
, table_desc
));
320 * Destroys table named by 'table_name.' Returns DB_SUCCESS if successful,
321 * error code otherwise. Note that currently, the removed table is no
322 * longer accessible from this interface and all files associated with it
323 * are removed from stable storage.
326 db_destroy_table(char * table_name
)
328 return (InUseDictionary
->delete_table(table_name
));
333 * Return a copy of the first entry in the specified table, that satisfies
334 * the given attributes. The returned structure 'db_result' contains the status,
335 * the copy of the object, and a 'db_next_desc' to be used for the 'next'
339 db_first_entry(char * table_name
, int numattrs
, nis_attr
* attrname
)
341 db_result
* safety
= empty_result(DB_SUCCESS
);
342 db_table_desc
* tbl
= NULL
;
343 db
* dbase
= InUseDictionary
->find_table(table_name
, &tbl
);
345 if (tbl
== NULL
|| dbase
== NULL
)
346 return (set_result(safety
, DB_BADTABLE
));
348 db_result
* res
= NULL
;
349 db_query
*query
= NULL
;
352 query
= InUseDictionary
->translate_to_query(tbl
,
355 return (set_result(safety
,
358 res
= dbase
->execute(DB_FIRST
, query
, NULL
, NULL
);
359 if (query
) delete query
;
360 if (safety
) delete safety
;
366 * Return a copy of the next entry in the specified table as specified by
367 * the 'next_desc'. The returned structure 'db_result' contains the status,
368 * a copy of the object, and a db_next_desc to be used for a subsequent
372 db_next_entry(char * table_name
, db_next_desc
* next_desc
)
374 db_result
* safety
= empty_result(DB_SUCCESS
);
375 db
* dbase
= InUseDictionary
->find_table(table_name
);
378 if (safety
) delete safety
;
379 return (dbase
->execute(DB_NEXT
, NULL
, NULL
, next_desc
));
381 return (set_result(safety
, DB_BADTABLE
));
385 * Indicate to the system that you are no longer interested in the rest of the
386 * results identified by [next_desc]. After executing this operation, the
387 * [next_desc] is no longer valid (cannot be used as an argument for next).
391 db_reset_next_entry(char * table_name
, db_next_desc
* next_desc
)
393 db_result
* safety
= empty_result(DB_SUCCESS
);
394 db
* dbase
= InUseDictionary
->find_table(table_name
);
397 if (safety
) delete safety
;
398 return (dbase
->execute(DB_RESET_NEXT
,
399 NULL
, NULL
, next_desc
));
401 return (set_result(safety
, DB_BADTABLE
));
405 * Returns copies of entries that satisfy the given attributes from table.
406 * Returns the status and entries in a db_result structure.
407 * If no attributes are specified, DB_BADQUERY is returned.
410 __db_list_entries(char * table_name
, int numattrs
, nis_attr
* attrname
,
413 db_result
* safety
= empty_result(DB_SUCCESS
);
414 db_table_desc
* tbl
= NULL
;
415 db
* dbase
= InUseDictionary
->find_table(table_name
, &tbl
,
418 if (tbl
== NULL
|| dbase
== NULL
)
419 return (set_result(safety
, DB_BADTABLE
));
421 db_result
* res
= NULL
;
424 query
= InUseDictionary
->translate_to_query(tbl
,
427 return (set_result(safety
,
429 res
= dbase
->execute(DB_LOOKUP
, query
,
433 res
= dbase
->execute(DB_ALL
, NULL
, NULL
, NULL
);
435 if (safety
) delete safety
;
441 db_list_entries(char *table_name
, int numattrs
, nis_attr
*attrname
) {
442 return (__db_list_entries(table_name
, numattrs
, attrname
, TRUE
));
446 * Input: A fully qualified object name (example: "x.y.z").
447 * Output: Returns the first level of the object name ("x").
448 * If 'tableP' is non-NULL, '*tableP' will contain
449 * the internal table name for "y.z".
451 * Both the return value and '*tableP' must be freed by the caller.
454 entryName(const char *msg
, char *objName
, char **tableP
) {
455 char *name
, *table
, *dir
;
456 const char *myself
= "entryName";
461 name
= sdup(msg
, T
, objName
);
465 dir
= strchr(name
, '.');
475 table
= internalTableName(dir
);
486 #define RETSTAT(obj, status) \
494 * Given a fully qualified object name, retrive a copy of the object,
495 * using the NIS+ DB only (i.e., no LDAP). Avoids using nis_leaf_of()
496 * etc., since they aren't re-entrant.
499 dbFindObject(char *objName
, db_status
*statP
) {
500 char buf
[MAXPATHLEN
+NIS_MAXNAMELEN
+1];
501 char *name
, *table
= 0;
505 db_table_desc
*tbl
= 0;
510 const char *myself
= "dbFindObject";
513 RETSTAT(0, DB_BADQUERY
);
515 /* The root dir is treated specially */
516 table
= internalTableName(objName
);
518 RETSTAT(0, DB_BADQUERY
);
519 if (strcmp(ROOTDIRFILE
, table
) == 0) {
522 o
= get_root_object();
524 RETSTAT(0, DB_NOTFOUND
);
526 RETSTAT(o
, DB_SUCCESS
);
529 /* If not the root dir, find the directory where the entry lives */
532 name
= entryName(myself
, objName
, &table
);
533 if (name
== 0 || table
== 0) {
535 RETSTAT(0, DB_MEMORY_LIMIT
);
538 dbase
= InUseDictionary
->find_table_noLDAP(table
, &tbl
, TRUE
, TRUE
);
541 mindex
= dbase
->mindex();
542 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
544 RETSTAT(0, DB_BADTABLE
);
547 WRITELOCKNR(mindex
, lstat
, "mindex w dbFindObject");
550 RETSTAT(0, DB_LOCK_ERROR
);
553 attr
.zattr_ndx
= (char *)"name";
554 attr
.zattr_val
.zattr_val_val
= name
;
555 attr
.zattr_val
.zattr_val_len
= slen(name
) + 1;
557 query
= InUseDictionary
->translate_to_query(tbl
, 1, &attr
);
560 WRITEUNLOCKNR(mindex
, lstat
, "mindex wu dbFindObject");
561 RETSTAT(0, DB_BADQUERY
);
564 /* Only want to look in the local DB */
565 mindex
->setNoLDAPquery();
567 res
= dbase
->execute(DB_LOOKUP
, query
, 0, 0);
569 mindex
->clearNoLDAPquery();
575 WRITEUNLOCKNR(mindex
, lstat
, "mindex wu dbFindObject");
578 RETSTAT(0, DB_LOCK_ERROR
);
582 RETSTAT(0, DB_MEMORY_LIMIT
);
584 if (res
->status
!= DB_SUCCESS
) {
585 db_status st
= res
->status
;
591 if (res
->objects
.objects_len
!= 1 || res
->objects
.objects_val
== 0 ||
592 res
->objects
.objects_val
[0] == 0) {
594 RETSTAT(0, DB_BADOBJECT
);
597 o
= unmakePseudoEntryObj(res
->objects
.objects_val
[0], 0);
602 RETSTAT(0, DB_BADOBJECT
);
605 RETSTAT(o
, DB_SUCCESS
);
609 * Return the object specified by 't' or 'objName' from LDAP. Set
610 * the LDAP status in '*statP'.
613 ldapFindObj(__nis_table_mapping_t
*t
, char *objName
, int *statP
) {
616 const char *myself
= "ldapFindObj";
619 char *table
, tbuf
[MAXPATHLEN
+ NIS_MAXNAMELEN
+ 1];
623 *statP
= LDAP_PARAM_ERROR
;
627 /* Look for mapping */
628 table
= internal_table_name(objName
, tbuf
);
631 *statP
= LDAP_PARAM_ERROR
;
635 t
= (__nis_table_mapping_t
*)__nis_find_item_mt(table
,
636 &ldapMappingList
, 0, 0);
638 /* Not really an error; just not mapped */
639 *statP
= LDAP_SUCCESS
;
645 stat
= objFromLDAP(t
, &o
, 0, 0);
654 * Look for the specified object, first locally, then in LDAP.
657 findObj(char *name
, db_status
*statP
, int *lstatP
) {
659 db_status stat
= DB_SUCCESS
;
660 int lstat
= LDAP_SUCCESS
;
661 const char *myself
= "findObj";
663 o
= dbFindObject(name
, &stat
);
666 if (stat
!= DB_NOTFOUND
)
667 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
668 "%s: DB error %d looking for \"%s\"",
669 myself
, stat
, NIL(name
));
671 o
= ldapFindObj(0, name
, &lstat
);
673 if (lstat
!= LDAP_SUCCESS
&&
674 lstat
!= LDAP_NO_SUCH_OBJECT
)
675 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
676 "%s: LDAP error looking for \"%s\": %s",
678 ldap_err2string(lstat
));
691 * Delete the specified object from the local DB.
694 dbDeleteObj(char *objName
) {
695 nisdb_tsd_t
*tsd
= __nisdb_get_tsd();
698 nisdb_obj_del_t
*nod
, *tmp
;
700 const char *myself
= "dbDeleteObj";
706 * Since in-structure locks can't completely protect
707 * during structure deletion, we just note that the
708 * object should be deleted, and leave that for a
709 * (slightly) later time in rpc.nisd, where we can
710 * use the rpc.nisd's table/directory locks for
715 return (DB_INTERNAL_ERROR
);
717 o
= dbFindObject(objName
, &stat
);
719 if (stat
== DB_NOTFOUND
)
726 * In order to prevent a chicken-and-egg problem (if the
727 * object doesn't exist in LDAP, is that because we just
728 * haven't written it to LDAP yet, or because it's been
729 * removed), we only allow object deletion if we're the
733 nod
= (nisdb_obj_del_t
*)am(myself
, sizeof (*nod
));
735 nis_destroy_object(o
);
736 return (DB_MEMORY_LIMIT
);
739 nod
->objType
= o
->zo_data
.zo_type
;
740 nis_destroy_object(o
);
742 nod
->objName
= sdup(myself
, T
, objName
);
743 if (nod
->objName
== 0) {
745 return (DB_MEMORY_LIMIT
);
748 /* Check for a dup */
749 for (tmp
= tsd
->objDelList
; tmp
!= 0;
750 tmp
= (nisdb_obj_del_t
*)tmp
->next
) {
751 if (strcmp(nod
->objName
, tmp
->objName
) == 0) {
758 /* Insert at start of list */
759 nod
->next
= tsd
->objDelList
;
760 tsd
->objDelList
= nod
;
766 * Touch (i.e., update the expiration time for) the specified object.
769 dbTouchObj(char *objName
) {
772 db_table_desc
*tbl
= 0;
777 const char *myself
= "dbTouchObj";
779 table
= internalTableName(objName
);
781 return (DB_BADQUERY
);
783 if (strcmp(ROOTDIRFILE
, table
) == 0) {
786 if (touchRootDir() == 0)
789 return (DB_INTERNAL_ERROR
);
794 ent
= entryName(myself
, objName
, &table
);
795 if (ent
== 0 || table
== 0) {
797 return (DB_MEMORY_LIMIT
);
800 dbase
= InUseDictionary
->find_table(table
, &tbl
, TRUE
);
802 mindex
= dbase
->mindex();
803 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
806 return (DB_BADTABLE
);
809 attr
.zattr_ndx
= (char *)"name";
810 attr
.zattr_val
.zattr_val_val
= ent
;
811 attr
.zattr_val
.zattr_val_len
= slen(ent
) + 1;
813 query
= InUseDictionary
->translate_to_query(tbl
, 1, &attr
);
817 return (DB_BADQUERY
);
820 mindex
->touchEntry(query
);
830 * Create a NIS_TABLE_OBJ.
831 * Borrows heavily from rpc.nisd/nis_db.c:__create_table().
834 dbCreateTable(char *intName
, nis_object
*obj
) {
835 table_col tc
[NIS_MAXCOLUMNS
+1];
838 const char *myself
= "dbCreateTable";
840 if (intName
== 0 || obj
== 0)
841 return (DB_BADTABLE
);
845 /* Make sure there are searchable columns */
846 for (i
= 0; i
< t
->ta_cols
.ta_cols_len
; i
++) {
847 if (t
->ta_cols
.ta_cols_val
[i
].tc_flags
& TA_SEARCHABLE
)
850 if (i
>= t
->ta_cols
.ta_cols_len
) {
851 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
852 "%s: No searchable columns in \"%s\" (\"%s\")",
853 myself
, NIL(obj
->zo_name
), NIL(intName
));
854 return (DB_BADTABLE
);
858 /* Shift columns one step right */
859 for (i
= 0; i
< tobj
.ta_cols
.ta_cols_len
; i
++) {
860 tc
[i
+1] = tobj
.ta_cols
.ta_cols_val
[i
];
863 tc
[0].tc_flags
= TA_XDR
| TA_BINARY
;
865 tobj
.ta_cols
.ta_cols_len
+= 1;
866 tobj
.ta_cols
.ta_cols_val
= tc
;
868 return (db_create_table(intName
, &tobj
));
871 #define TABLE_COL(o, n) o->TA_data.ta_cols.ta_cols_val[n]
874 * Refresh (if necessary, create), the specified object in the local DB.
877 dbRefreshObj(char *name
, nis_object
*o
) {
879 __nis_buffer_t b
= {0, 0};
882 char *ent
, *table
, *objTable
;
883 int rstat
, isDir
= 0, isTable
= 0;
884 const char *myself
= "refreshObj";
888 return (dbDeleteObj(name
));
890 /* We don't work on entry objects */
891 if (o
->zo_data
.zo_type
== NIS_ENTRY_OBJ
)
892 return (DB_BADOBJECT
);
897 bp2buf(myself
, &b
, "%s.%s", NIL(o
->zo_name
), NIL(o
->zo_domain
));
901 curObj
= dbFindObject(objName
, &stat
);
902 if (curObj
== 0 && stat
!= DB_NOTFOUND
) {
908 * If the object doesn't change, just touch it to update the
912 if (sameNisPlusObj(o
, curObj
)) {
914 nis_destroy_object(curObj
);
915 return (dbTouchObj(objName
));
918 /* Otherwise, check that the name and type is the same */
919 if (o
->zo_data
.zo_type
!= curObj
->zo_data
.zo_type
||
920 o
->zo_name
== 0 || curObj
->zo_name
== 0 ||
921 o
->zo_domain
== 0 || curObj
->zo_domain
== 0 ||
922 strcmp(o
->zo_name
, curObj
->zo_name
) != 0 ||
923 strcmp(o
->zo_domain
, curObj
->zo_domain
) != 0) {
925 nis_destroy_object(curObj
);
926 return (DB_BADOBJECT
);
930 * If the object is a table, we can't allow the scheme
933 if (o
->zo_data
.zo_type
== NIS_TABLE_OBJ
) {
936 if (o
->TA_data
.ta_maxcol
!=
937 curObj
->TA_data
.ta_maxcol
) {
939 nis_destroy_object(curObj
);
940 return (DB_BADOBJECT
);
943 for (i
= 0; i
< o
->TA_data
.ta_maxcol
; i
++) {
944 if ((TABLE_COL(o
, i
).tc_flags
&
946 (TABLE_COL(curObj
, i
).tc_flags
&
949 nis_destroy_object(curObj
);
950 return (DB_BADOBJECT
);
956 * If we're creating a directory object, make a note
957 * so that we can add it to the serving list and create
958 * the disk file. Similarly, if creating a table, we
959 * also need to create the disk file.
961 if (o
->zo_data
.zo_type
== NIS_DIRECTORY_OBJ
)
963 else if (o
->zo_data
.zo_type
== NIS_TABLE_OBJ
)
967 objTable
= internalTableName(objName
);
971 nis_destroy_object(curObj
);
972 return (DB_BADQUERY
);
975 if (strcmp(ROOTDIRFILE
, objTable
) == 0) {
978 rstat
= update_root_object((nis_name
)ROOTOBJFILE
, o
);
982 stat
= DB_INTERNAL_ERROR
;
988 db_table_desc
*tbl
= 0;
994 ent
= entryName(myself
, objName
, &table
);
995 if (ent
== 0 || table
== 0) {
1000 nis_destroy_object(curObj
);
1001 return (DB_MEMORY_LIMIT
);
1005 * Calling vanilla find_table() here (which might go to
1006 * LDAP and recurse back to ourselves) so that it should
1007 * work to create a hierarchy of directories.
1009 dbase
= InUseDictionary
->find_table(table
, &tbl
, TRUE
);
1011 mindex
= dbase
->mindex();
1012 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
1018 nis_destroy_object(curObj
);
1019 return (DB_BADTABLE
);
1022 /* Construct suitable nis_attr and entry_object */
1023 attr
.zattr_ndx
= (char *)"name";
1024 attr
.zattr_val
.zattr_val_val
= ent
;
1025 attr
.zattr_val
.zattr_val_len
= slen(ent
) + 1;
1028 ec
[1].ec_value
.ec_value_val
= ent
;
1029 ec
[1].ec_value
.ec_value_len
= attr
.zattr_val
.zattr_val_len
;
1031 eo
.en_type
= (char *)"IN_DIRECTORY";
1032 eo
.en_cols
.en_cols_val
= ec
;
1033 eo
.en_cols
.en_cols_len
= 2;
1035 e
= makePseudoEntryObj(o
, &eo
, 0);
1041 nis_destroy_object(curObj
);
1042 return (DB_INTERNAL_ERROR
);
1045 /* Only want to update the local DB */
1047 WRITELOCKNR(mindex
, lstat
, "mindex w dbRefreshObj");
1053 nis_destroy_object(curObj
);
1054 return (DB_LOCK_ERROR
);
1056 mindex
->setNoWriteThrough();
1057 mindex
->setNoLDAPquery();
1059 dbres
= db_add_entry_x(table
, 1, &attr
, e
, 0, 0);
1061 mindex
->clearNoLDAPquery();
1062 mindex
->clearNoWriteThrough();
1063 WRITEUNLOCKNR(mindex
, lstat
, "mindex wu dbRefreshObj");
1069 nis_destroy_object(curObj
);
1070 db_free_result(dbres
);
1071 return (DB_LOCK_ERROR
);
1078 stat
= DB_MEMORY_LIMIT
;
1080 stat
= dbres
->status
;
1082 db_free_result(dbres
);
1085 * If successful so far, add the transaction.
1087 if (stat
== DB_SUCCESS
) {
1092 /* Find the directory where this is added */
1093 dirObj
= dbFindObject(o
->zo_domain
, &ds
);
1097 nis_destroy_object(curObj
);
1101 xid
= beginTransaction();
1105 nis_destroy_object(curObj
);
1106 nis_destroy_object(dirObj
);
1107 return (DB_INTERNAL_ERROR
);
1110 st
= addUpdate((curObj
== 0) ? ADD_NAME
: MOD_NAME_NEW
,
1111 objName
, 0, 0, o
, curObj
, 0);
1113 (void) abort_transaction(xid
);
1116 nis_destroy_object(curObj
);
1117 nis_destroy_object(dirObj
);
1118 return (DB_INTERNAL_ERROR
);
1121 st
= endTransaction(xid
, dirObj
);
1123 stat
= DB_INTERNAL_ERROR
;
1126 nis_destroy_object(curObj
);
1127 nis_destroy_object(dirObj
);
1131 * If it's a table or directory, create the DB file.
1132 * If a directory, also add it to the serving list.
1134 if (stat
== DB_SUCCESS
&&(isDir
|| isTable
)) {
1136 stat
= db_create_table(objTable
,
1139 stat
= dbCreateTable(objTable
, o
);
1151 * Replace the object stored with the mapping 't'. Return TRUE if
1152 * at least one object was replaced, FALSE otherwise.
1155 replaceMappingObj(__nis_table_mapping_t
*t
, nis_object
*n
) {
1156 __nis_table_mapping_t
*x
;
1157 nis_object
*old
= 0;
1161 * The alternate mappings are usually mostly copies
1162 * of the original, so we try to make sure that we
1163 * don't free the same nis_object twice.
1165 for (x
= t
; x
!= 0; x
= (__nis_table_mapping_t
*)x
->next
) {
1169 nis_destroy_object(x
->obj
);
1171 if (x
->obj
!= old
&& x
->obj
!= 0)
1172 nis_destroy_object(x
->obj
);
1178 return (assigned
> 0);
1182 * Set object type, column info, and obj for the specified
1183 * mapping 't' from the object 'o'. Returns zero if 'o' was unused,
1184 * and should be freed by the caller, larger than zero otherwise.
1187 setMappingObjTypeEtc(__nis_table_mapping_t
*t
, nis_object
*o
) {
1188 __nis_table_mapping_t
*x
;
1192 if (t
== 0 || o
== 0)
1195 t
->objType
= o
->zo_data
.zo_type
;
1196 for (x
= t
; x
!= 0; x
= (__nis_table_mapping_t
*)x
->next
) {
1198 x
->objType
= t
->objType
;
1200 if (x
->objType
== NIS_TABLE_OBJ
) {
1202 * If we have rules, this mapping is for table entries,
1203 * and we need the column names. Otherwise, remove the
1204 * column names (if any).
1207 for (i
= 0; i
< x
->numColumns
; i
++)
1208 sfree(x
->column
[i
]);
1214 ret
= replaceMappingObj(t
, o
);
1220 * Retrieve the specified object (internal DB name) from LDAP, and
1221 * refresh/create as appropriate.
1224 dbCreateFromLDAP(char *intName
, int *ldapStat
) {
1225 __nis_table_mapping_t
*t
;
1226 int lstat
, doDestroy
;
1227 nis_object
*obj
= 0;
1229 const char *myself
= "dbCreateFromLDAP";
1231 if (!useLDAPrespository
) {
1233 *ldapStat
= LDAP_SUCCESS
;
1234 return (DB_SUCCESS
);
1237 t
= (__nis_table_mapping_t
*)__nis_find_item_mt(intName
,
1241 /* No mapping isn't a failure */
1244 *ldapStat
= LDAP_SUCCESS
;
1245 return (DB_NOTFOUND
);
1248 lstat
= objFromLDAP(t
, &obj
, 0, 0);
1251 if (lstat
!= LDAP_SUCCESS
)
1252 return (DB_NOTFOUND
);
1255 * If the LDAP operation was successful, but 'obj' is NULL,
1256 * there's no mapping for this object, and we're done.
1259 return (DB_SUCCESS
);
1261 /* Update the mapping with object info */
1262 doDestroy
= setMappingObjTypeEtc(t
, obj
) == 0;
1264 dstat
= dbRefreshObj(t
->objName
, obj
);
1267 nis_destroy_object(obj
);
1273 * Up- (fromLDAP==0) or down- (fromLDAP==1) load all LDAP mapped data.
1274 * Returns an LDAP error status.
1277 loadAllLDAP(int fromLDAP
, void *cookie
, db_status
*dstatP
) {
1278 __nis_table_mapping_t
*t
, *start
;
1279 int stat
= LDAP_SUCCESS
;
1280 db_status dstat
= DB_SUCCESS
;
1282 db_table_desc
*tbl
= 0;
1284 const char *myself
= "loadAllLDAP";
1287 * If the 'cookie' and '*cookie' are non-NULL, start scanning
1288 * the mappings from '*cookie'. When we return with an error,
1289 * we set '*cookie' to point to the mapping being processed.
1290 * This enables our caller to react appropriately, and retry
1293 * The cookie is opaque to our caller, who's only allowed to
1294 * initialize *cookie to NULL.
1297 start
= *((__nis_table_mapping_t
**)cookie
);
1299 start
= ldapMappingSeq
;
1301 start
= ldapMappingSeq
;
1304 for (t
= start
; t
!= 0; t
= (__nis_table_mapping_t
*)t
->seqNext
) {
1305 __nis_table_mapping_t
**tp
;
1309 /* Are there any mappings for the object proper ? */
1310 tp
= selectTableMapping(t
, 0, 0, 1, t
->dbId
, &nm
);
1311 if (tp
!= 0 && nm
> 0) {
1312 dstat
= dbCreateFromLDAP(t
->objPath
, &stat
);
1313 if (dstat
!= DB_SUCCESS
) {
1314 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1315 "%s: DB error %d creating \"%s\": %s",
1316 myself
, dstat
, NIL(t
->objName
),
1317 ldap_err2string(stat
));
1319 *((__nis_table_mapping_t
**)
1323 else if (stat
== LDAP_SUCCESS
)
1324 stat
= LDAP_OPERATIONS_ERROR
;
1331 /* Any mappings for table entries ? */
1332 tp
= selectTableMapping(t
, 0, 0, 0, t
->dbId
, &nm
);
1333 if (tp
== 0 || nm
<= 0) {
1340 * The object itself must exist in the local
1341 * DB by now. Get the db_mindex and let
1342 * db_mindex::queryLDAP() do the work; if
1343 * the object isn't a table, queryLDAP()
1344 * will do nothing and return success.
1346 dbase
= InUseDictionary
->find_table(t
->objPath
,
1349 mindex
= dbase
->mindex();
1350 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
1351 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1352 "%s: No local DB entry for \"%s\" (%s:%s)",
1353 myself
, NIL(t
->objPath
),
1354 NIL(t
->dbId
), NIL(t
->objName
));
1356 *((__nis_table_mapping_t
**)cookie
) =
1359 *dstatP
= DB_BADTABLE
;
1360 return ((dstatP
!= 0) ?
1361 LDAP_SUCCESS
: LDAP_OPERATIONS_ERROR
);
1363 mindex
->setInitialLoad();
1364 stat
= mindex
->queryLDAP(0, t
->dbId
, 0);
1365 mindex
->clearInitialLoad();
1366 if (stat
!= LDAP_SUCCESS
) {
1367 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1368 "%s: LDAP error retrieving entries for %s:%s: %s",
1369 myself
, NIL(t
->dbId
), NIL(t
->objName
),
1370 ldap_err2string(stat
));
1372 *((__nis_table_mapping_t
**)cookie
) =
1375 *dstatP
= DB_SUCCESS
;
1380 char *ent
, *objPath
;
1381 int freeObjPath
= 0;
1384 * Up-loading to LDAP, so the object must
1385 * already exist in the local DB.
1387 obj
= dbFindObject(t
->objName
, &dstat
);
1389 if (dstat
== DB_NOTFOUND
)
1390 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1391 "%s: No local DB object for \"%s\" (%s:%s); skipping up-load",
1392 myself
, NIL(t
->objPath
),
1396 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1397 "%s: DB error %d for \"%s\" (%s:%s); skipping up-load",
1406 * If it's a table or directory, there will be
1407 * a dictionary entry for the object itself.
1408 * Otherwise, we need the dictionary entry for
1409 * the parent directory.
1411 * For a table, we need the db_mindex for both the
1412 * table object itself, as well as for the parent
1413 * directory (in order to store table entries).
1414 * We start with the latter.
1416 if (obj
->zo_data
.zo_type
== NIS_DIRECTORY_OBJ
) {
1417 objPath
= t
->objPath
;
1421 ent
= entryName(myself
, t
->objName
,
1423 if (ent
== 0 || objPath
== 0) {
1424 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1425 "%s: Error deriving entry/DB-table names for %s:%s; skipping up-load",
1426 myself
, NIL(t
->dbId
),
1430 nis_destroy_object(obj
);
1437 dbase
= InUseDictionary
->find_table(objPath
,
1440 mindex
= dbase
->mindex();
1441 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
1442 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1443 "%s: No local DB entry for \"%s\" (%s:%s); skipping up-load",
1445 NIL(t
->dbId
), NIL(t
->objName
));
1449 nis_destroy_object(obj
);
1455 * Our next action(s) depend on the object type:
1457 * directory Store dir object
1459 * table Store table obj, as well
1460 * as any entries in the
1463 * other Store object; we need to
1464 * build a db_query specifying
1465 * the first-level name of the
1468 * storeLDAP() will just do nothing and return
1469 * success if we try to, say, store a table object
1470 * when only the table entries are mapped. Hence,
1471 * we don't have to worry about those distinctions
1474 if (obj
->zo_data
.zo_type
== NIS_DIRECTORY_OBJ
) {
1475 stat
= mindex
->storeLDAP(0, 0, obj
, 0, t
->dbId
);
1480 attr
.zattr_ndx
= (char *)"name";
1481 attr
.zattr_val
.zattr_val_val
= ent
;
1482 attr
.zattr_val
.zattr_val_len
= slen(ent
) + 1;
1484 q
= new db_query(mindex
->getScheme(), 1, &attr
);
1486 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1487 "%s: error creating db_query for \"%s\" in \"%s\"; skipping up-load",
1488 myself
, ent
, objPath
);
1492 nis_destroy_object(obj
);
1497 stat
= mindex
->storeLDAP(q
, 0, obj
, 0, t
->dbId
);
1507 if (stat
!= LDAP_SUCCESS
) {
1508 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1509 "%s: Error storing %s:%s to LDAP: %s",
1510 myself
, NIL(t
->dbId
), NIL(t
->objName
),
1511 ldap_err2string(stat
));
1512 nis_destroy_object(obj
);
1515 *((__nis_table_mapping_t
**)
1518 *dstatP
= DB_SUCCESS
;
1522 /* Any mappings for table entries ? */
1523 tp
= selectTableMapping(t
, 0, 0, 0, t
->dbId
, &nm
);
1524 if (tp
== 0 || nm
<= 0) {
1526 nis_destroy_object(obj
);
1533 * If it's a table, we also need to store the table
1536 if (obj
->zo_data
.zo_type
== NIS_TABLE_OBJ
) {
1538 dbase
= InUseDictionary
->find_table(t
->objPath
,
1541 mindex
= dbase
->mindex();
1542 if (dbase
== 0 || tbl
== 0 || mindex
== 0) {
1543 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1544 "%s: No local DB entry for \"%s\" (%s:%s); skipping entry up-load",
1545 myself
, NIL(t
->objPath
),
1546 NIL(t
->dbId
), NIL(t
->objName
));
1547 nis_destroy_object(obj
);
1552 stat
= mindex
->storeLDAP(0, 0, obj
, 0, t
->dbId
);
1554 if (stat
!= LDAP_SUCCESS
) {
1555 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1556 "%s: Error storing %s:%s entries to LDAP: %s",
1557 myself
, NIL(t
->dbId
),
1559 ldap_err2string(stat
));
1560 nis_destroy_object(obj
);
1563 *((__nis_table_mapping_t
**)
1566 *dstatP
= DB_SUCCESS
;
1570 nis_destroy_object(obj
);
1581 * Object identified by given attribute name is added to specified table.
1582 * If object already exists, it is replaced. If more than one object
1583 * matches the given attribute name, DB_NOTUNIQUE is returned.
1587 db_add_entry_x(char * tab
, int numattrs
, nis_attr
* attrname
,
1588 entry_obj
* newobj
, int skiplog
, int nosync
)
1590 db_result
* safety
= empty_result(DB_SUCCESS
);
1591 db_table_desc
* tbl
= NULL
;
1592 db
* dbase
= InUseDictionary
->find_table(tab
, &tbl
, FALSE
);
1594 if (tbl
== NULL
|| dbase
== NULL
) {
1595 return (set_result(safety
, DB_BADTABLE
));
1596 } else if (skiplog
) {
1598 res
= dbase
->execute(DB_ADD_NOLOG
, NULL
,
1599 (entry_object
*) newobj
, NULL
);
1600 if (safety
) delete safety
;
1605 query
= InUseDictionary
->translate_to_query(tbl
,
1606 numattrs
, attrname
);
1608 return (set_result(safety
, DB_BADQUERY
));
1610 res
= dbase
->execute(DB_ADD_NOSYNC
,
1611 query
, (entry_object
*) newobj
, NULL
);
1613 res
= dbase
->execute(DB_ADD
, query
,
1614 (entry_object
*) newobj
, NULL
);
1616 if (safety
) delete safety
;
1622 db_add_entry(char * tab
, int numattrs
, nis_attr
* attrname
,
1625 return (db_add_entry_x(tab
, numattrs
, attrname
, newobj
, 0, 0));
1629 __db_add_entry_nolog(char * tab
, int numattrs
, nis_attr
* attrname
,
1632 return (db_add_entry_x(tab
, numattrs
, attrname
, newobj
, 1, 0));
1636 __db_add_entry_nosync(char * tab
, int numattrs
, nis_attr
* attrname
,
1639 return (db_add_entry_x(tab
, numattrs
, attrname
, newobj
, 0, 1));
1643 * Remove object identified by given attributes from specified table.
1644 * If no attribute is supplied, all entries in table are removed.
1645 * If attributes identify more than one object, all objects are removed.
1649 db_remove_entry_x(char * table_name
, int num_attrs
, nis_attr
* attrname
,
1652 db_result
* safety
= empty_result(DB_SUCCESS
);
1653 db_table_desc
* tbl
= NULL
;
1654 db
* dbase
= InUseDictionary
->find_table(table_name
, &tbl
, FALSE
);
1657 if (tbl
== NULL
|| dbase
== NULL
)
1658 return (set_result(safety
, DB_BADTABLE
));
1660 if (num_attrs
!= 0) {
1662 query
= InUseDictionary
->translate_to_query(tbl
,
1663 num_attrs
, attrname
);
1665 return (set_result(safety
,
1668 res
= dbase
->execute(DB_REMOVE_NOSYNC
,
1671 res
= dbase
->execute(DB_REMOVE
, query
,
1676 res
= dbase
->execute(DB_REMOVE_NOSYNC
,
1679 res
= dbase
->execute(DB_REMOVE
,
1682 if (safety
) delete safety
;
1688 db_remove_entry(char * table_name
, int num_attrs
, nis_attr
* attrname
)
1690 return (db_remove_entry_x(table_name
, num_attrs
, attrname
, 0));
1694 __db_remove_entry_nosync(char * table_name
, int num_attrs
, nis_attr
* attrname
)
1696 return (db_remove_entry_x(table_name
, num_attrs
, attrname
, 1));
1699 /* Return a copy of the version of specified table. */
1701 db_version(char * table_name
)
1703 db
* dbase
= InUseDictionary
->find_table(table_name
);
1707 vers
* v
= new vers(dbase
->get_version());
1709 WARNING("nis_db::db_version: cannot allocate space");
1713 /* Return log entries since (later than) given version 'v' of table. */
1715 db_log_entries_since(char * table_name
, vers
* v
)
1717 db
* dbase
= InUseDictionary
->find_table(table_name
);
1721 return (dbase
->get_log_entries_since(v
));
1725 db_sync_log(char *table_name
) {
1727 db
* dbase
= InUseDictionary
->find_table(table_name
);
1730 return (DB_BADTABLE
);
1731 return (dbase
->sync_log());
1735 * Apply the given update specified in 'entry' to the specified table.
1736 * Returns DB_SUCCESS if update was executed.
1737 * Returns DB_NOTFOUND if update occurs too early to be applied.
1740 db_apply_log_entry(char * table_name
, db_log_entry
* entry
)
1742 db
* dbase
= InUseDictionary
->find_table(table_name
, NULL
, FALSE
);
1745 return (DB_BADTABLE
);
1746 if (dbase
->execute_log_entry(entry
))
1747 return (DB_SUCCESS
); /* got executed */
1749 return (DB_NOTFOUND
); /* not executed */
1753 * Checkpoint specified table (i.e. incorporate logged updates to main
1754 * database file). If table_name is NULL, checkpoint all tables that
1758 db_checkpoint(char * table_name
)
1760 return (InUseDictionary
->db_checkpoint(table_name
));
1763 /* Print names of tables in system. */
1765 db_print_table_names()
1768 db_table_names
* answer
= InUseDictionary
->get_table_names();
1770 if (answer
!= NULL
) {
1771 for (i
= 0; i
< answer
->db_table_names_len
; i
++) {
1772 printf("%s\n", answer
->db_table_names_val
[i
]);
1773 delete answer
->db_table_names_val
[i
];
1775 delete answer
->db_table_names_val
;
1780 /* Print statistics of specified table to stdout. */
1782 db_stats(char * table_name
)
1784 db_table_desc
* tbl
= NULL
;
1785 db
*dbase
= InUseDictionary
->find_table(table_name
, &tbl
);
1787 if (tbl
== NULL
|| dbase
== NULL
|| tbl
->scheme
== NULL
)
1788 return (DB_BADTABLE
);
1791 tbl
->scheme
->print();
1792 return (DB_SUCCESS
);
1796 /* Print statistics of indices of specified table to stdout. */
1798 db_print_all_indices(char * table_name
)
1800 db
* dbase
= InUseDictionary
->find_table(table_name
);
1803 return (DB_BADTABLE
);
1804 dbase
->print_all_indices();
1805 return (DB_SUCCESS
);
1808 /* Print specified index of table to stdout. */
1810 db_print_index(char * table_name
, int which
)
1812 db
* dbase
= InUseDictionary
->find_table(table_name
);
1815 return (DB_BADTABLE
);
1816 dbase
->print_index(which
);
1817 return (DB_SUCCESS
);
1820 /* close open files */
1822 db_standby(char * table_name
)
1824 return (InUseDictionary
->db_standby(table_name
));
1827 /* Returns DB_SUCCESS if table exists; DB_BADTABLE if table does not exist. */
1829 db_table_exists(char * table_name
)
1831 db_table_desc
*dbtab
= InUseDictionary
->find_table_desc(table_name
);
1834 return (DB_BADTABLE
);
1835 return (DB_SUCCESS
);
1839 * Returns DB_SUCCESS if table exists; DB_BADTABLE if table does not exist.
1840 * If table already loaded, unload it.
1843 db_unload_table(char * table_name
)
1846 dbtab
= InUseDictionary
->find_table_desc(table_name
);
1848 return (DB_BADTABLE
);
1850 if (dbtab
->database
!= NULL
) {
1851 delete dbtab
->database
;
1852 dbtab
->database
= NULL
;
1854 return (DB_SUCCESS
);
1858 * Put the specified table in deferred mode, which means that updates go
1859 * to the original table, but reads are satisfied out of a copy (which we
1860 * make here). Thus, "defer" refers to the table as seen by read requests,
1861 * since for them, changes are deferred.
1864 __db_defer(char *table_name
) {
1867 stat
= InUseDictionary
->defer(table_name
);
1872 * Commit deferred changes for the specified table. I.e., make visible
1873 * any updates made since the table was deferred.
1876 __db_commit(char *table_name
) {
1879 stat
= InUseDictionary
->commit(table_name
);
1884 * Rollback, i.e., return to the state before we entered deferred mode.
1887 __db_rollback(char *table_name
) {
1890 stat
= InUseDictionary
->rollback(table_name
);
1895 __db_configure(char *table_name
) {
1897 char tablePath
[MAXPATHLEN
+ NIS_MAXNAMELEN
+ 1];
1898 db
*dbase
= InUseDictionary
->find_table(table_name
, NULL
);
1900 if (dbase
== NULL
|| table_name
== 0)
1901 return (DB_BADTABLE
);
1903 if (strlen(table_name
) >= sizeof (tablePath
))
1904 return (DB_BADQUERY
);
1906 if (internal_table_name(table_name
, tablePath
) == 0)
1907 return (DB_STORAGE_LIMIT
);
1909 if (dbase
->configure(tablePath
))
1912 stat
= DB_INTERNAL_ERROR
;
1918 * During some rpc.nisd operations (such as when recovering the trans.log),
1919 * we don't want to use the LDAP repository, so we provide a main switch.
1920 * Note that we expect this to be used only when rpc.nisd is single-threaded,
1921 * so there is no need for synchronization when reading or modifying the
1922 * value of the main switch.
1924 int useLDAPrespository
= 1;
1927 __db_disallowLDAP(void) {
1928 useLDAPrespository
= 0;
1932 __db_allowLDAP(void) {
1933 useLDAPrespository
= 1;