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