4 * Copyright 1997 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 * Copyright (C) 1998 by the FundsXpress, INC.
31 * All rights reserved.
33 * Export of this software from the United States of America may require
34 * a specific license from the United States Government. It is the
35 * responsibility of any person or organization contemplating export to
36 * obtain such a license before exporting.
38 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39 * distribute this software and its documentation for any purpose and
40 * without fee is hereby granted, provided that the above copyright
41 * notice appear in all copies and that both that copyright notice and
42 * this permission notice appear in supporting documentation, and that
43 * the name of FundsXpress. not be used in advertising or publicity pertaining
44 * to distribution of the software without specific, written prior
45 * permission. FundsXpress makes no representations about the suitability of
46 * this software for any purpose. It is provided "as is" without express
47 * or implied warranty.
49 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
64 #define OLD_COMPAT_VERSION_1
66 #ifdef OLD_COMPAT_VERSION_1
67 #include "kdb_compat.h"
72 static char *gen_dbsuffix
74 static krb5_error_code krb5_db2_db_start_update
76 static krb5_error_code krb5_db2_db_end_update
78 static krb5_error_code krb5_db2_db_set_hashfirst
81 static char default_db_name[] = DEFAULT_KDB_FILE;
86 * There are two distinct locking protocols used. One is designed to
87 * lock against processes (the admin_server, for one) which make
88 * incremental changes to the database; the other is designed to lock
89 * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
90 * entire database in one fell swoop.
92 * The first locking protocol is implemented using flock() in the
93 * krb_dbl_lock() and krb_dbl_unlock routines.
95 * The second locking protocol is necessary because DBM "files" are
96 * actually implemented as two separate files, and it is impossible to
97 * atomically rename two files simultaneously. It assumes that the
98 * database is replaced only very infrequently in comparison to the time
99 * needed to do a database read operation.
101 * A third file is used as a "version" semaphore; the modification
102 * time of this file is the "version number" of the database.
103 * At the start of a read operation, the reader checks the version
104 * number; at the end of the read operation, it checks again. If the
105 * version number changed, or if the semaphore was nonexistant at
106 * either time, the reader sleeps for a second to let things
107 * stabilize, and then tries again; if it does not succeed after
108 * KRB5_DBM_MAX_RETRY attempts, it gives up.
110 * On update, the semaphore file is deleted (if it exists) before any
111 * update takes place; at the end of the update, it is replaced, with
112 * a version number strictly greater than the version number which
113 * existed at the start of the update.
115 * If the system crashes in the middle of an update, the semaphore
116 * file is not automatically created on reboot; this is a feature, not
117 * a bug, since the database may be inconsistant. Note that the
118 * absence of a semaphore file does not prevent another _update_ from
119 * taking place later. Database replacements take place automatically
120 * only on slave servers; a crash in the middle of an update will be
121 * fixed by the next slave propagation. A crash in the middle of an
122 * update on the master would be somewhat more serious, but this would
123 * likely be noticed by an administrator, who could fix the problem and
124 * retry the operation.
127 #define free_dbsuffix(name) free(name)
130 * Routines to deal with context.
132 #define k5db2_inited(c) (c && c->db_context && \
133 ((krb5_db2_context *) c->db_context)->db_inited)
136 * Restore the default context.
139 k5db2_clear_context(dbctx)
140 krb5_db2_context *dbctx;
143 * Free any dynamically allocated memory. File descriptors and locks
144 * are the caller's problem.
146 if (dbctx->db_lf_name)
147 free(dbctx->db_lf_name);
148 if (dbctx->db_name && (dbctx->db_name != default_db_name))
149 free(dbctx->db_name);
151 * Clear the structure and reset the defaults.
153 memset((char *) dbctx, 0, sizeof(krb5_db2_context));
154 dbctx->db_name = default_db_name;
155 dbctx->db_nb_locks = FALSE;
158 static krb5_error_code
159 k5db2_init_context(context)
160 krb5_context context;
162 krb5_db2_context *db_ctx;
164 if (context->db_context == NULL) {
165 db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
169 memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
170 k5db2_clear_context((krb5_db2_context *)db_ctx);
171 context->db_context = (void *) db_ctx;
178 * Utility routine: generate name of database file.
182 gen_dbsuffix(db_name, sfx)
189 return((char *) NULL);
191 dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1);
194 (void) strcpy(dbsuffix, db_name);
195 (void) strcat(dbsuffix, sfx);
200 k5db2_dbopen(dbc, fname, flags, mode)
201 krb5_db2_context *dbc;
225 db = dbopen(fname, flags, mode,
226 dbc->hashfirst ? DB_HASH : DB_BTREE,
227 dbc->hashfirst ? (void *) &hashi : (void *) &bti);
235 db = dbopen(fname, flags, mode,
236 dbc->hashfirst ? DB_BTREE : DB_HASH,
237 dbc->hashfirst ? (void *) &bti : (void *) &hashi);
239 dbc->hashfirst = !dbc->hashfirst;
245 static krb5_error_code
246 krb5_db2_db_set_hashfirst(context, hashfirst)
247 krb5_context context;
250 krb5_db2_context *dbc;
252 if (k5db2_inited(context))
253 return KRB5_KDB_DBNOTINITED;
254 dbc = (krb5_db2_context *) context->db_context;
255 dbc->hashfirst = hashfirst;
260 * initialization for data base routines.
264 krb5_db2_db_init(context)
265 krb5_context context;
267 char *filename = NULL;
268 krb5_db2_context *db_ctx;
269 krb5_error_code retval;
271 if (k5db2_inited(context))
274 /* Check for presence of our context, if not present, allocate one. */
275 if ((retval = k5db2_init_context(context)))
278 db_ctx = context->db_context;
281 if (!(filename = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT)))
283 db_ctx->db_lf_name = filename; /* so it gets freed by clear_context */
286 * should be opened read/write so that write locking can work with
289 if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
290 if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
297 if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
304 k5db2_clear_context(db_ctx);
309 * gracefully shut down database--must be called by ANY program that does
313 krb5_db2_db_fini(context)
314 krb5_context context;
316 krb5_error_code retval = 0;
317 krb5_db2_context *db_ctx;
319 db_ctx = (krb5_db2_context *) context->db_context;
321 if (k5db2_inited(context)) {
322 if (close(db_ctx->db_lf_file))
328 k5db2_clear_context(db_ctx);
329 free(context->db_context);
330 context->db_context = NULL;
336 krb5_db2_db_open_database(context)
337 krb5_context context;
339 if (!k5db2_inited(context))
340 return KRB5_KDB_DBNOTINITED;
345 krb5_db2_db_close_database(context)
346 krb5_context context;
348 if (!k5db2_inited(context))
349 return KRB5_KDB_DBNOTINITED;
354 * Set/Get the master key associated with the database
357 krb5_db2_db_set_mkey(context, key)
358 krb5_context context;
361 krb5_db2_context *db_ctx;
363 if (!k5db2_inited(context))
364 return(KRB5_KDB_DBNOTINITED);
366 db_ctx = context->db_context;
367 db_ctx->db_master_key = key;
372 krb5_db2_db_get_mkey(context, key)
373 krb5_context context;
376 krb5_db2_context *db_ctx;
378 if (!k5db2_inited(context))
379 return(KRB5_KDB_DBNOTINITED);
381 db_ctx = context->db_context;
382 *key = db_ctx->db_master_key;
388 * Set the "name" of the current database to some alternate value.
390 * Passing a null pointer as "name" will set back to the default.
391 * If the alternate database doesn't exist, nothing is changed.
397 krb5_db2_db_set_name(context, name)
398 krb5_context context;
402 krb5_db2_context *db_ctx;
403 krb5_error_code kret;
405 if (k5db2_inited(context))
406 return KRB5_KDB_DBINITED;
408 /* Check for presence of our context, if not present, allocate one. */
409 if ((kret = k5db2_init_context(context)))
413 name = default_db_name;
415 db_ctx = context->db_context;
416 db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0);
420 db_ctx->db_name = strdup(name);
426 * Return the last modification time of the database.
428 * Think about using fstat.
432 krb5_db2_db_get_age(context, db_name, age)
433 krb5_context context;
437 krb5_db2_context *db_ctx;
440 if (!k5db2_inited(context))
441 return(KRB5_KDB_DBNOTINITED);
442 db_ctx = (krb5_db2_context *) context->db_context;
443 if (fstat (db_ctx->db_lf_file, &st) < 0)
451 * Remove the semaphore file; indicates that database is currently
454 * This is only for use when moving the database out from underneath
455 * the server (for example, during slave updates).
458 static krb5_error_code
459 krb5_db2_db_start_update(context)
460 krb5_context context;
465 static krb5_error_code
466 krb5_db2_db_end_update(context)
467 krb5_context context;
469 krb5_error_code retval;
470 krb5_db2_context *db_ctx;
473 struct utimbuf utbuf;
475 if (!k5db2_inited(context))
476 return(KRB5_KDB_DBNOTINITED);
479 db_ctx = context->db_context;
480 now = time((time_t *) NULL);
481 if (fstat(db_ctx->db_lf_file, &st) == 0) {
482 if (st.st_mtime >= now) {
483 utbuf.actime = st.st_mtime+1;
484 utbuf.modtime = st.st_mtime+1;
485 if (utime(db_ctx->db_lf_name, &utbuf))
489 if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
496 if (fstat(db_ctx->db_lf_file, &st) == 0)
497 db_ctx->db_lf_time = st.st_mtime;
505 krb5_db2_db_lock(context, mode)
506 krb5_context context;
509 krb5_db2_context *db_ctx;
512 krb5_error_code retval;
515 if (!k5db2_inited(context))
516 return KRB5_KDB_DBNOTINITED;
518 db_ctx = (krb5_db2_context *) context->db_context;
519 if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
520 /* No need to upgrade lock, just return */
521 db_ctx->db_locks_held++;
525 if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
526 return KRB5_KDB_BADLOCKMODE;
528 if (db_ctx->db_nb_locks)
529 krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
531 krb5_lock_mode = mode;
532 retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
535 if (mode == KRB5_LOCKMODE_EXCLUSIVE)
536 return KRB5_KDB_CANTLOCK_DB;
543 if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
546 db = k5db2_dbopen(db_ctx, db_ctx->db_name,
547 mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
550 db_ctx->db_lf_time = mod_time;
558 db_ctx->db_lock_mode = mode;
559 db_ctx->db_locks_held++;
563 db_ctx->db_lock_mode = 0;
564 db_ctx->db_locks_held = 0;
565 (void) krb5_db2_db_unlock(context);
570 krb5_db2_db_unlock(context)
571 krb5_context context;
573 krb5_db2_context *db_ctx;
575 krb5_error_code retval;
577 if (!k5db2_inited(context))
578 return KRB5_KDB_DBNOTINITED;
580 db_ctx = (krb5_db2_context *) context->db_context;
581 if (!db_ctx->db_locks_held) /* lock already unlocked */
582 return KRB5_KDB_NOTLOCKED;
584 if (--(db_ctx->db_locks_held) == 0) {
588 retval = krb5_lock_file(context, db_ctx->db_lf_file,
589 KRB5_LOCKMODE_UNLOCK);
590 db_ctx->db_lock_mode = 0;
597 * Create the database, assuming it's not there.
600 krb5_db2_db_create(context, db_name, flags)
601 krb5_context context;
605 register krb5_error_code retval = 0;
608 krb5_db2_context *db_ctx;
611 if ((retval = k5db2_init_context(context)))
614 db_ctx = (krb5_db2_context *) context->db_context;
616 case KRB5_KDB_CREATE_HASH:
617 if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
620 case KRB5_KDB_CREATE_BTREE:
622 if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
626 return KRB5_KDB_BAD_CREATEFLAGS;
628 db = k5db2_dbopen(db_ctx, db_name, O_RDWR|O_CREAT|O_EXCL, 0600);
634 okname = gen_dbsuffix(db_name, KDB2_LOCK_EXT);
638 fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600);
643 free_dbsuffix(okname);
650 * Destroy the database. Zero's out all of the files, just to be sure.
652 static krb5_error_code
653 destroy_file_suffix(dbname, suffix)
666 filename = gen_dbsuffix(dbname, suffix);
669 if ((fd = open(filename, O_RDWR, 0)) < 0) {
673 /* fstat() will probably not fail unless using a remote filesystem
674 (which is inappropriate for the kerberos database) so this check
675 is mostly paranoia. */
676 if (fstat(fd, &statb) == -1) {
682 * Stroll through the file, reading in BUFSIZ chunks. If everything
683 * is zero, then we're done for that block, otherwise, zero the block.
684 * We would like to just blast through everything, but some DB
685 * implementations make holey files and writing data to the holes
686 * causes actual blocks to be allocated which is no good, since
687 * we're just about to unlink it anyways.
689 memset(zbuf, 0, BUFSIZ);
691 while (pos < statb.st_size) {
693 nb = read(fd, buf, BUFSIZ);
699 for (j=0; j<nb; j++) {
700 if (buf[j] != '\0') {
708 lseek(fd, pos, SEEK_SET);
709 nb = write(fd, zbuf, j);
718 /* ??? Is fsync really needed? I don't know of any non-networked
719 filesystem which will discard queued writes to disk if a file
720 is deleted after it is closed. --jfc */
726 if (unlink(filename)) {
735 * Since the destroy operation happens outside the init/fini bracket, we
736 * have some tomfoolery to undergo here. If we're operating under no
737 * database context, then we initialize with the default. If the caller
738 * wishes a different context (e.g. different dispatch table), it's their
739 * responsibility to call kdb5_db_set_dbops() before this call. That will
740 * set up the right dispatch table values (e.g. name extensions).
742 * Not quite valid due to ripping out of dbops...
745 krb5_db2_db_destroy(context, dbname)
746 krb5_context context;
749 krb5_error_code retval1, retval2;
750 krb5_boolean tmpcontext;
753 if (!context->db_context) {
755 if ((retval1 = k5db2_init_context(context)))
759 retval1 = retval2 = 0;
760 retval1 = destroy_file_suffix(dbname, "");
761 retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
764 k5db2_clear_context((krb5_db2_context *) context->db_context);
765 free(context->db_context);
766 context->db_context = NULL;
769 if (retval1 || retval2)
770 return (retval1 ? retval1 : retval2);
776 * "Atomically" rename the database in a way that locks out read
777 * access in the middle of the rename.
779 * Not perfect; if we crash in the middle of an update, we don't
780 * necessarily know to complete the transaction the rename, but...
782 * Since the rename operation happens outside the init/fini bracket, we
783 * have to go through the same stuff that we went through up in db_destroy.
786 krb5_db2_db_rename(context, from, to)
787 krb5_context context;
793 krb5_error_code retval;
794 krb5_db2_context *s_context, *db_ctx;
796 s_context = context->db_context;
797 context->db_context = NULL;
798 if ((retval = k5db2_init_context(context)))
800 db_ctx = (krb5_db2_context *) context->db_context;
803 * Create the database if it does not already exist; the
804 * files must exist because krb5_db2_db_lock, called below,
805 * will fail otherwise.
807 db = k5db2_dbopen(db_ctx, to, O_RDWR|O_CREAT, 0600);
815 * Set the database to the target, so that other processes sharing
816 * the target will stop their activity, and notice the new database.
818 retval = krb5_db2_db_set_name(context, to);
822 db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT);
823 if (db_ctx->db_lf_name == NULL) {
827 db_ctx->db_lf_file = open(db_ctx->db_lf_name, O_RDWR|O_CREAT, 0600);
828 if (db_ctx->db_lf_file < 0) {
833 db_ctx->db_inited = 1;
835 retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time);
839 fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
840 if (fromok == NULL) {
845 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
848 if ((retval = krb5_db2_db_start_update(context)))
851 if (rename(from, to)) {
855 if (unlink(fromok)) {
859 retval = krb5_db2_db_end_update(context);
861 free_dbsuffix(fromok);
863 if (context->db_context) {
864 if (db_ctx->db_lf_file >= 0) {
865 krb5_db2_db_unlock(context);
866 close(db_ctx->db_lf_file);
868 k5db2_clear_context((krb5_db2_context *) context->db_context);
869 free(context->db_context);
872 context->db_context = s_context;
873 (void) krb5_db2_db_unlock(context); /* unlock saved context db */
879 * look up a principal in the data base.
880 * returns number of entries found, and whether there were
881 * more than requested.
885 krb5_db2_db_get_principal(context, searchfor, entries, nentries, more)
886 krb5_context context;
887 krb5_const_principal searchfor;
888 krb5_db_entry *entries; /* filled in */
889 int *nentries; /* how much room/how many found */
890 krb5_boolean *more; /* are there more? */
892 krb5_db2_context *db_ctx;
893 krb5_error_code retval;
896 krb5_data keydata, contdata;
902 if (!k5db2_inited(context))
903 return KRB5_KDB_DBNOTINITED;
905 db_ctx = (krb5_db2_context *) context->db_context;
906 for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) {
907 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
908 if (db_ctx->db_nb_locks)
915 if (trynum == KRB5_DB2_MAX_RETRY)
916 return KRB5_KDB_DB_INUSE;
918 /* XXX deal with wildcard lookups */
919 retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
922 key.data = keydata.data;
923 key.size = keydata.length;
926 dbret = (*db->get)(db, &key, &contents, 0);
928 krb5_free_data_contents(context, &keydata);
937 contdata.data = contents.data;
938 contdata.length = contents.size;
939 retval = krb5_decode_princ_contents(context, &contdata, entries);
946 (void) krb5_db2_db_unlock(context); /* unlock read lock */
951 Free stuff returned by krb5_db2_db_get_principal.
954 krb5_db2_db_free_principal(context, entries, nentries)
955 krb5_context context;
956 krb5_db_entry *entries;
960 for (i = 0; i < nentries; i++)
961 krb5_dbe_free_contents(context, &entries[i]);
966 Stores the *"nentries" entry structures pointed to by "entries" in the
969 *"nentries" is updated upon return to reflect the number of records
970 acutally stored; the first *"nstored" records will have been stored in the
971 database (even if an error occurs).
976 krb5_db2_db_put_principal(context, entries, nentries)
977 krb5_context context;
978 krb5_db_entry *entries;
979 register int *nentries; /* number of entry structs to update */
984 krb5_data contdata, keydata;
985 krb5_error_code retval;
986 krb5_db2_context *db_ctx;
990 if (!k5db2_inited(context))
991 return KRB5_KDB_DBNOTINITED;
993 db_ctx = (krb5_db2_context *) context->db_context;
994 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
998 if ((retval = krb5_db2_db_start_update(context))) {
999 (void)krb5_db2_db_unlock(context);
1003 /* for each one, stuff temps, and do replace/append */
1004 for (i = 0; i < n; i++) {
1005 retval = krb5_encode_princ_contents(context, &contdata, entries);
1008 contents.data = contdata.data;
1009 contents.size = contdata.length;
1010 retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
1012 krb5_free_data_contents(context, &contdata);
1016 key.data = keydata.data;
1017 key.size = keydata.length;
1018 dbret = (*db->put)(db, &key, &contents, 0);
1019 retval = dbret ? errno : 0;
1020 krb5_free_data_contents(context, &keydata);
1021 krb5_free_data_contents(context, &contdata);
1024 entries++; /* bump to next struct */
1027 (void)krb5_db2_db_end_update(context);
1028 (void)krb5_db2_db_unlock(context); /* unlock database */
1034 * delete a principal from the data base.
1035 * returns number of entries removed
1039 krb5_db2_db_delete_principal(context, searchfor, nentries)
1040 krb5_context context;
1041 krb5_const_principal searchfor;
1042 int *nentries; /* how many found & deleted */
1044 krb5_error_code retval;
1045 krb5_db_entry entry;
1046 krb5_db2_context *db_ctx;
1049 krb5_data keydata, contdata;
1052 if (!k5db2_inited(context))
1053 return KRB5_KDB_DBNOTINITED;
1055 db_ctx = (krb5_db2_context *) context->db_context;
1056 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
1059 if ((retval = krb5_db2_db_start_update(context))) {
1060 (void) krb5_db2_db_unlock(context); /* unlock write lock */
1064 if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
1066 key.data = keydata.data;
1067 key.size = keydata.length;
1070 dbret = (*db->get)(db, &key, &contents, 0);
1074 retval = KRB5_KDB_NOENTRY;
1082 memset((char *)&entry, 0, sizeof(entry));
1083 contdata.data = contents.data;
1084 contdata.length = contents.size;
1085 retval = krb5_decode_princ_contents(context, &contdata, &entry);
1090 /* Clear encrypted key contents */
1091 for (i = 0; i < entry.n_key_data; i++) {
1092 if (entry.key_data[i].key_data_length[0]) {
1093 memset((char *)entry.key_data[i].key_data_contents[0], 0,
1094 (unsigned) entry.key_data[i].key_data_length[0]);
1098 retval = krb5_encode_princ_contents(context, &contdata, &entry);
1099 krb5_dbe_free_contents(context, &entry);
1103 contents.data = contdata.data;
1104 contents.size = contdata.length;
1105 dbret = (*db->put)(db, &key, &contents, 0);
1106 retval = dbret ? errno : 0;
1107 krb5_free_data_contents(context, &contdata);
1110 dbret = (*db->del)(db, &key, 0);
1111 retval = dbret ? errno : 0;
1113 krb5_free_data_contents(context, &keydata);
1116 (void) krb5_db2_db_end_update(context);
1117 (void) krb5_db2_db_unlock(context); /* unlock write lock */
1122 krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive)
1123 krb5_context context;
1124 krb5_error_code (*func) (krb5_pointer, krb5_db_entry *);
1125 krb5_pointer func_arg;
1126 int backwards, recursive;
1128 krb5_db2_context *db_ctx;
1132 krb5_db_entry entries;
1133 krb5_error_code retval;
1138 if (!k5db2_inited(context))
1139 return KRB5_KDB_DBNOTINITED;
1141 db_ctx = (krb5_db2_context *) context->db_context;
1142 retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
1148 if (recursive && db->type != DB_BTREE) {
1149 (void)krb5_db2_db_unlock(context);
1150 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1154 dbret = (*db->seq)(db, &key, &contents,
1155 backwards ? R_LAST : R_FIRST);
1158 dbret = bt_rseq(db, &key, &contents, &cookie,
1159 backwards ? R_LAST : R_FIRST);
1161 (void)krb5_db2_db_unlock(context);
1162 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1165 while (dbret == 0) {
1166 contdata.data = contents.data;
1167 contdata.length = contents.size;
1168 retval = krb5_decode_princ_contents(context, &contdata, &entries);
1171 retval = (*func)(func_arg, &entries);
1172 krb5_dbe_free_contents(context, &entries);
1176 dbret = (*db->seq)(db, &key, &contents,
1177 backwards ? R_PREV : R_NEXT);
1180 dbret = bt_rseq(db, &key, &contents, &cookie,
1181 backwards ? R_PREV : R_NEXT);
1183 (void)krb5_db2_db_unlock(context);
1184 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1196 (void) krb5_db2_db_unlock(context);
1201 krb5_db2_db_iterate(context, func, func_arg)
1202 krb5_context context;
1203 krb5_error_code (*func) (krb5_pointer, krb5_db_entry *);
1204 krb5_pointer func_arg;
1206 return krb5_db2_db_iterate_ext(context, func, func_arg, 0, 0);
1210 krb5_db2_db_set_lockmode(context, mode)
1211 krb5_context context;
1215 krb5_db2_context *db_ctx;
1218 if ((db_ctx = (krb5_db2_context *) context->db_context)) {
1219 old = db_ctx->db_nb_locks;
1220 db_ctx->db_nb_locks = mode;
1226 * Context serialization operations.
1228 * Ick, this is really gross. --- tlyu
1232 * kdb5_context_size() - Determine size required to serialize.
1234 static krb5_error_code
1235 kdb5_context_size(kcontext, arg, sizep)
1236 krb5_context kcontext;
1240 krb5_error_code kret;
1242 krb5_db2_context *dbctx;
1245 * The database context requires at minimum:
1246 * krb5_int32 for KV5M_DB_CONTEXT
1247 * krb5_int32 for db_inited
1248 * krb5_int32 for database lockfile non-blocking flag
1249 * krb5_int32 for database lockfile lock count
1250 * krb5_int32 for database lockfile lock mode
1251 * krb5_int32 for length of database name.
1252 * krb5_int32 for KV5M_DB_CONTEXT
1255 if ((dbctx = (krb5_db2_context *) arg)) {
1256 required = (sizeof(krb5_int32) * 7);
1257 if (dbctx->db_inited && dbctx->db_name)
1258 required += strlen(dbctx->db_name);
1266 * kdb5_context_externalize() - Externalize the database context.
1268 static krb5_error_code
1269 kdb5_context_externalize(kcontext, arg, buffer, lenremain)
1270 krb5_context kcontext;
1272 krb5_octet **buffer;
1275 krb5_error_code kret;
1276 krb5_db2_context *dbctx;
1283 remain = *lenremain;
1285 if ((dbctx = (krb5_db2_context *) arg)) {
1287 if (!kdb5_context_size(kcontext, arg, &required) &&
1288 (required <= remain)) {
1289 /* Write magic number */
1290 (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
1292 /* Write inited flag */
1293 (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_inited,
1296 /* Write blocking lock lockmode */
1297 (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_nb_locks,
1300 /* Write lock count */
1301 (void) krb5_ser_pack_int32((krb5_int32)
1302 (dbctx->db_inited) ?
1303 dbctx->db_locks_held : 0,
1306 /* Write lock mode */
1307 (void) krb5_ser_pack_int32((krb5_int32)
1308 (dbctx->db_inited) ?
1309 dbctx->db_lock_mode : 0,
1312 /* Write length of database name */
1313 (void) krb5_ser_pack_int32((dbctx->db_inited && dbctx->db_name) ?
1314 (krb5_int32) strlen(dbctx->db_name) : 0,
1316 if (dbctx->db_inited && dbctx->db_name)
1317 (void) krb5_ser_pack_bytes((krb5_octet *) dbctx->db_name,
1318 strlen(dbctx->db_name),
1322 (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
1325 *lenremain = remain;
1332 * kdb5_context_internalize() - Internalize the database context.
1334 static krb5_error_code
1335 kdb5_context_internalize(kcontext, argp, buffer, lenremain)
1336 krb5_context kcontext;
1338 krb5_octet **buffer;
1341 krb5_error_code kret;
1342 krb5_context tmpctx;
1343 krb5_db2_context *dbctx;
1348 krb5_int32 nb_lockmode;
1349 krb5_int32 lockcount;
1350 krb5_int32 lockmode;
1351 krb5_int32 dbnamelen;
1352 krb5_boolean nb_lock;
1356 remain = *lenremain;
1358 dbctx = (krb5_db2_context *) NULL;
1359 /* Read our magic number */
1360 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
1362 if (ibuf == KV5M_DB_CONTEXT) {
1365 if (!(kret = krb5_ser_unpack_int32(&iflag, &bp, &remain)) &&
1366 !(kret = krb5_ser_unpack_int32(&nb_lockmode, &bp, &remain)) &&
1367 !(kret = krb5_ser_unpack_int32(&lockcount, &bp, &remain)) &&
1368 !(kret = krb5_ser_unpack_int32(&lockmode, &bp, &remain)) &&
1369 !(kret = krb5_ser_unpack_int32(&dbnamelen, &bp, &remain)) &&
1370 !(kret = krb5_init_context(&tmpctx))) {
1372 dbname = (char *) NULL;
1374 (dbname = (char *) malloc((size_t) (dbnamelen+1)))) {
1375 kret = krb5_ser_unpack_bytes((krb5_octet *) dbname,
1379 dbname[dbnamelen] = '\0';
1382 (!dbname || !(kret = krb5_db_set_name(tmpctx, dbname))) &&
1383 !(kret = krb5_db_init(tmpctx))) {
1384 dbctx = (krb5_db2_context *) tmpctx->db_context;
1385 (void) krb5_db2_db_set_lockmode(tmpctx, 0);
1387 kret = krb5_db_lock(tmpctx, lockmode);
1388 if (!kret && lockmode)
1389 dbctx->db_locks_held = lockcount;
1390 nb_lock = nb_lockmode & 0xff;
1391 (void) krb5_db2_db_set_lockmode(tmpctx, nb_lock);
1397 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
1398 if (kret || (ibuf != KV5M_DB_CONTEXT))
1403 krb5_db_fini(tmpctx);
1406 tmpctx->db_context = NULL;
1407 krb5_free_context(tmpctx);
1412 *lenremain = remain;
1413 *argp = (krb5_pointer) dbctx;
1418 /* Dispatch entry */
1419 static const krb5_ser_entry kdb5_context_ser_entry = {
1420 KV5M_DB_CONTEXT, /* Type */
1421 kdb5_context_size, /* Sizer routine */
1422 kdb5_context_externalize, /* Externalize routine */
1423 kdb5_context_internalize /* Externalize routine */
1427 * Register serializer.
1430 krb5_ser_db_context_init(kcontext)
1431 krb5_context kcontext;
1433 return(krb5_register_serializer(kcontext, &kdb5_context_ser_entry));