summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTom Yu <tlyu@mit.edu>1997-07-25 19:34:42 +0000
committerTom Yu <tlyu@mit.edu>1997-07-25 19:34:42 +0000
commitb09cbdac52640cab3b3f0916c18c49f46d938a86 (patch)
tree9022976458207d71efa7fc462784c841ea54b3ab /src
parent7faa30416aeea498e83f1e4f97449a0efa525436 (diff)
downloadkrb5-b09cbdac52640cab3b3f0916c18c49f46d938a86.tar.gz
krb5-b09cbdac52640cab3b3f0916c18c49f46d938a86.tar.xz
krb5-b09cbdac52640cab3b3f0916c18c49f46d938a86.zip
* t_kdb.c: Reflect changes in the API, mostly db_create
* Makefile.in: Bump version due to major reworking. * kdb_db2.h: * kdb_db2.c: Add Berkely DB backend. * keytab.c: Add support for new kdb API; delete dead arguments. * kdb_xdr.c: Remove dependencies on dbm; encode things to krb5_datas rather than datums. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10130 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r--src/lib/kdb/ChangeLog14
-rw-r--r--src/lib/kdb/Makefile.in6
-rw-r--r--src/lib/kdb/kdb_db2.c1360
-rw-r--r--src/lib/kdb/kdb_db2.h121
-rw-r--r--src/lib/kdb/kdb_xdr.c51
-rw-r--r--src/lib/kdb/keytab.c33
-rw-r--r--src/lib/kdb/t_kdb.c20
7 files changed, 1545 insertions, 60 deletions
diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog
index fa3a680930..05497b130e 100644
--- a/src/lib/kdb/ChangeLog
+++ b/src/lib/kdb/ChangeLog
@@ -1,3 +1,17 @@
+Fri Jul 25 15:29:03 1997 Tom Yu <tlyu@mit.edu>
+
+ * t_kdb.c: Reflect changes in the API, mostly db_create.
+
+ * Makefile.in: Bump version due to major reworking.
+
+ * kdb_db2.h:
+ * kdb_db2.c: Add Berkely DB backend.
+
+ * keytab.c: Add support for new kdb API; delete dead arguments.
+
+ * kdb_xdr.c: Remove dependencies on dbm; encode things to
+ krb5_datas rather than datums.
+
Mon Mar 24 12:19:03 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
* t_kdb.c (do_testing): Clean up error handling for krb5_init_context.
diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in
index b842f95242..370aa428e1 100644
--- a/src/lib/kdb/Makefile.in
+++ b/src/lib/kdb/Makefile.in
@@ -5,7 +5,7 @@ PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
LIB=kdb5
-LIBMAJOR=1
+LIBMAJOR=2
LIBMINOR=0
RELDIR=kdb
# Depends on libcrypto and libkrb5
@@ -24,7 +24,7 @@ SRCS= \
$(srcdir)/encrypt_key.c \
$(srcdir)/decrypt_key.c \
$(srcdir)/kdb_cpw.c \
- $(srcdir)/kdb_dbm.c \
+ $(srcdir)/kdb_db2.c \
$(srcdir)/kdb_xdr.c \
$(srcdir)/verify_mky.c \
$(srcdir)/fetch_mkey.c \
@@ -37,7 +37,7 @@ STLIBOBJS= \
encrypt_key.o \
decrypt_key.o \
kdb_cpw.o \
- kdb_dbm.o \
+ kdb_db2.o \
kdb_xdr.o \
verify_mky.o \
fetch_mkey.o \
diff --git a/src/lib/kdb/kdb_db2.c b/src/lib/kdb/kdb_db2.c
new file mode 100644
index 0000000000..703c11df47
--- /dev/null
+++ b/src/lib/kdb/kdb_db2.c
@@ -0,0 +1,1360 @@
+/*
+ * lib/kdb/kdb_db2.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "k5-int.h"
+#include <db.h>
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+
+#define OLD_COMPAT_VERSION_1
+
+#ifdef OLD_COMPAT_VERSION_1
+#include "kdb_compat.h"
+#endif
+
+#include "kdb_db2.h"
+
+static char *gen_dbsuffix
+ PROTOTYPE((char *, char * ));
+static krb5_error_code krb5_db2_db_start_update
+ PROTOTYPE((krb5_context));
+static krb5_error_code krb5_db2_db_end_update
+ PROTOTYPE((krb5_context));
+static krb5_error_code krb5_db2_db_set_hashfirst
+ PROTOTYPE((krb5_context, int));
+
+static char default_db_name[] = DEFAULT_KDB_FILE;
+
+/*
+ * Locking:
+ *
+ * There are two distinct locking protocols used. One is designed to
+ * lock against processes (the admin_server, for one) which make
+ * incremental changes to the database; the other is designed to lock
+ * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
+ * entire database in one fell swoop.
+ *
+ * The first locking protocol is implemented using flock() in the
+ * krb_dbl_lock() and krb_dbl_unlock routines.
+ *
+ * The second locking protocol is necessary because DBM "files" are
+ * actually implemented as two separate files, and it is impossible to
+ * atomically rename two files simultaneously. It assumes that the
+ * database is replaced only very infrequently in comparison to the time
+ * needed to do a database read operation.
+ *
+ * A third file is used as a "version" semaphore; the modification
+ * time of this file is the "version number" of the database.
+ * At the start of a read operation, the reader checks the version
+ * number; at the end of the read operation, it checks again. If the
+ * version number changed, or if the semaphore was nonexistant at
+ * either time, the reader sleeps for a second to let things
+ * stabilize, and then tries again; if it does not succeed after
+ * KRB5_DBM_MAX_RETRY attempts, it gives up.
+ *
+ * On update, the semaphore file is deleted (if it exists) before any
+ * update takes place; at the end of the update, it is replaced, with
+ * a version number strictly greater than the version number which
+ * existed at the start of the update.
+ *
+ * If the system crashes in the middle of an update, the semaphore
+ * file is not automatically created on reboot; this is a feature, not
+ * a bug, since the database may be inconsistant. Note that the
+ * absence of a semaphore file does not prevent another _update_ from
+ * taking place later. Database replacements take place automatically
+ * only on slave servers; a crash in the middle of an update will be
+ * fixed by the next slave propagation. A crash in the middle of an
+ * update on the master would be somewhat more serious, but this would
+ * likely be noticed by an administrator, who could fix the problem and
+ * retry the operation.
+ */
+
+#define free_dbsuffix(name) free(name)
+
+/*
+ * Routines to deal with context.
+ */
+#define k5db2_inited(c) (c && c->db_context && \
+ ((krb5_db2_context *) c->db_context)->db_inited)
+
+/*
+ * Restore the default context.
+ */
+static void
+k5db2_clear_context(dbctx)
+ krb5_db2_context *dbctx;
+{
+ /*
+ * Free any dynamically allocated memory. File descriptors and locks
+ * are the caller's problem.
+ */
+ if (dbctx->db_lf_name)
+ free(dbctx->db_lf_name);
+ if (dbctx->db_name && (dbctx->db_name != default_db_name))
+ free(dbctx->db_name);
+ /*
+ * Clear the structure and reset the defaults.
+ */
+ memset((char *) dbctx, 0, sizeof(krb5_db2_context));
+ dbctx->db_name = default_db_name;
+ dbctx->db_nb_locks = FALSE;
+}
+
+static krb5_error_code
+k5db2_init_context(context)
+ krb5_context context;
+{
+ krb5_db2_context *db_ctx;
+
+ if (context->db_context == NULL) {
+ db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
+ if (db_ctx == NULL)
+ return ENOMEM;
+ else {
+ memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
+ k5db2_clear_context((krb5_db2_context *)db_ctx);
+ context->db_context = (void *) db_ctx;
+ }
+ }
+ return(0);
+}
+
+/*
+ * Utility routine: generate name of database file.
+ */
+
+static char *
+gen_dbsuffix(db_name, sfx)
+ char *db_name;
+ char *sfx;
+{
+ char *dbsuffix;
+
+ if (sfx == NULL)
+ return((char *) NULL);
+
+ dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1);
+ if (!dbsuffix)
+ return(0);
+ (void) strcpy(dbsuffix, db_name);
+ (void) strcat(dbsuffix, sfx);
+ return dbsuffix;
+}
+
+static DB *
+k5db2_dbopen(dbc, fname, flags, mode)
+ krb5_db2_context *dbc;
+ char *fname;
+ int flags;
+ int mode;
+{
+ DB *db;
+ BTREEINFO bti;
+ HASHINFO hashi;
+
+ bti.flags = 0;
+ bti.cachesize = 0;
+ bti.psize = 1024; /* ??? */
+ bti.lorder = 0;
+ bti.minkeypage = 0;
+ bti.compare = NULL;
+ bti.prefix = NULL;
+
+ hashi.bsize = 4096;
+ hashi.cachesize = 0;
+ hashi.ffactor = 40;
+ hashi.hash = NULL;
+ hashi.lorder = 0;
+ hashi.nelem = 1;
+
+ db = dbopen(fname, flags, mode,
+ dbc->hashfirst ? DB_HASH : DB_BTREE,
+ dbc->hashfirst ? (void *) &hashi : (void *) &bti);
+ if (db != NULL)
+ return db;
+ switch (errno) {
+#ifdef EFTYPE
+ case EFTYPE:
+#endif
+ case EINVAL:
+ db = dbopen(fname, flags, mode,
+ dbc->hashfirst ? DB_BTREE : DB_HASH,
+ dbc->hashfirst ? (void *) &bti : (void *) &hashi);
+ if (db != NULL)
+ dbc->hashfirst = !dbc->hashfirst;
+ default:
+ return db;
+ }
+}
+
+static krb5_error_code
+krb5_db2_db_set_hashfirst(context, hashfirst)
+ krb5_context context;
+ int hashfirst;
+{
+ krb5_db2_context *dbc;
+
+ if (k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+ dbc = (krb5_db2_context *) context;
+ dbc->hashfirst = hashfirst;
+ return 0;
+}
+
+/*
+ * initialization for data base routines.
+ */
+
+krb5_error_code
+krb5_db2_db_init(context)
+ krb5_context context;
+{
+ char *filename = NULL;
+ krb5_db2_context *db_ctx;
+ krb5_error_code retval;
+
+ if (k5db2_inited(context))
+ return 0;
+
+ /* Check for presence of our context, if not present, allocate one. */
+ if ((retval = k5db2_init_context(context)))
+ return(retval);
+
+ db_ctx = context->db_context;
+ db_ctx->db = NULL;
+
+ if (!(filename = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT)))
+ return ENOMEM;
+ db_ctx->db_lf_name = filename; /* so it gets freed by clear_context */
+
+ /*
+ * should be opened read/write so that write locking can work with
+ * POSIX systems
+ */
+ if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
+ if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
+ retval = errno;
+ goto err_out;
+ }
+ }
+ db_ctx->db_inited++;
+
+ if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
+ goto err_out;
+
+ return 0;
+
+err_out:
+ db_ctx->db = NULL;
+ k5db2_clear_context(db_ctx);
+ return (retval);
+}
+
+/*
+ * gracefully shut down database--must be called by ANY program that does
+ * a krb5_db2_db_init
+ */
+krb5_error_code
+krb5_db2_db_fini(context)
+ krb5_context context;
+{
+ krb5_error_code retval = 0;
+ krb5_db2_context *db_ctx;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+
+ if (k5db2_inited(context)) {
+ if (close(db_ctx->db_lf_file))
+ retval = errno;
+ else
+ retval = 0;
+ }
+ if (db_ctx) {
+ k5db2_clear_context(db_ctx);
+ free(context->db_context);
+ context->db_context = NULL;
+ }
+ return retval;
+}
+
+krb5_error_code
+krb5_db2_db_open_database(context)
+ krb5_context context;
+{
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+ return 0;
+}
+
+krb5_error_code
+krb5_db2_db_close_database(context)
+ krb5_context context;
+{
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+ return 0;
+}
+
+/*
+ * Set/Get the master key associated with the database
+ */
+krb5_error_code
+krb5_db2_db_set_mkey(context, eblock)
+ krb5_context context;
+ krb5_encrypt_block *eblock;
+{
+ krb5_db2_context *db_ctx;
+
+ if (!k5db2_inited(context))
+ return(KRB5_KDB_DBNOTINITED);
+
+ db_ctx = context->db_context;
+ db_ctx->db_master_key = eblock;
+ return 0;
+}
+
+krb5_error_code
+krb5_db2_db_get_mkey(context, eblock)
+ krb5_context context;
+ krb5_encrypt_block **eblock;
+{
+ krb5_db2_context *db_ctx;
+
+ if (!k5db2_inited(context))
+ return(KRB5_KDB_DBNOTINITED);
+
+ db_ctx = context->db_context;
+ *eblock = db_ctx->db_master_key;
+
+ return 0;
+}
+
+/*
+ * Set the "name" of the current database to some alternate value.
+ *
+ * Passing a null pointer as "name" will set back to the default.
+ * If the alternate database doesn't exist, nothing is changed.
+ *
+ * XXX rethink this
+ */
+
+krb5_error_code
+krb5_db2_db_set_name(context, name)
+ krb5_context context;
+ char *name;
+{
+ DB *db;
+ krb5_db2_context *db_ctx;
+ krb5_error_code kret;
+
+ if (k5db2_inited(context))
+ return KRB5_KDB_DBINITED;
+
+ /* Check for presence of our context, if not present, allocate one. */
+ if ((kret = k5db2_init_context(context)))
+ return(kret);
+
+ if (name == NULL)
+ name = default_db_name;
+
+ db_ctx = context->db_context;
+ db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0);
+ if (db == NULL)
+ return errno;
+
+ db_ctx->db_name = strdup(name);
+ (*db->close)(db);
+ return 0;
+}
+
+/*
+ * Return the last modification time of the database.
+ *
+ * Think about using fstat.
+ */
+
+krb5_error_code
+krb5_db2_db_get_age(context, db_name, age)
+ krb5_context context;
+ char *db_name;
+ time_t *age;
+{
+ krb5_db2_context *db_ctx;
+ struct stat st;
+
+ if (!k5db2_inited(context))
+ return(KRB5_KDB_DBNOTINITED);
+ db_ctx = (krb5_db2_context *) context->db_context;
+ if (fstat (db_ctx->db_lf_file, &st) < 0)
+ *age = -1;
+ else
+ *age = st.st_mtime;
+ return 0;
+}
+
+/*
+ * Remove the semaphore file; indicates that database is currently
+ * under renovation.
+ *
+ * This is only for use when moving the database out from underneath
+ * the server (for example, during slave updates).
+ */
+
+static krb5_error_code
+krb5_db2_db_start_update(context)
+ krb5_context context;
+{
+ return 0;
+}
+
+static krb5_error_code
+krb5_db2_db_end_update(context)
+ krb5_context context;
+{
+ krb5_error_code retval;
+ krb5_db2_context *db_ctx;
+ struct stat st;
+ time_t now;
+ struct utimbuf utbuf;
+
+ if (!k5db2_inited(context))
+ return(KRB5_KDB_DBNOTINITED);
+
+ retval = 0;
+ db_ctx = context->db_context;
+ now = time((time_t *) NULL);
+ if (fstat(db_ctx->db_lf_file, &st) == 0) {
+ if (st.st_mtime >= now) {
+ utbuf.actime = st.st_mtime+1;
+ utbuf.modtime = st.st_mtime+1;
+ if (utime(db_ctx->db_lf_name, &utbuf))
+ retval = errno;
+ }
+ else {
+ if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
+ retval = errno;
+ }
+ }
+ else
+ retval = errno;
+ if (!retval) {
+ if (fstat(db_ctx->db_lf_file, &st) == 0)
+ db_ctx->db_lf_time = st.st_mtime;
+ else
+ retval = errno;
+ }
+ return(retval);
+}
+
+krb5_error_code
+krb5_db2_db_lock(context, mode)
+ krb5_context context;
+ int mode;
+{
+ krb5_db2_context *db_ctx;
+ int krb5_lock_mode;
+ DB *db;
+ krb5_error_code retval;
+ time_t mod_time;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
+ /* No need to upgrade lock, just return */
+ db_ctx->db_locks_held++;
+ return(0);
+ }
+
+ if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
+ return KRB5_KDB_BADLOCKMODE;
+
+ if (db_ctx->db_nb_locks)
+ krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
+ else
+ krb5_lock_mode = mode;
+ retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
+ switch (retval) {
+ case EBADF:
+ if (mode == KRB5_LOCKMODE_EXCLUSIVE)
+ return KRB5_KDB_CANTLOCK_DB;
+ default:
+ return retval;
+ case 0:
+ break;
+ }
+
+ if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
+ goto lock_error;
+
+ db = k5db2_dbopen(db_ctx, db_ctx->db_name,
+ mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
+ 0600);
+ if (db) {
+ db_ctx->db_lf_time = mod_time;
+ db_ctx->db = db;
+ } else {
+ retval = errno;
+ db_ctx->db = NULL;
+ goto lock_error;
+ }
+
+ db_ctx->db_lock_mode = mode;
+ db_ctx->db_locks_held++;
+ return 0;
+
+lock_error:;
+ db_ctx->db_lock_mode = 0;
+ db_ctx->db_locks_held = 0;
+ (void) krb5_db2_db_unlock(context);
+ return retval;
+}
+
+krb5_error_code
+krb5_db2_db_unlock(context)
+ krb5_context context;
+{
+ krb5_db2_context *db_ctx;
+ DB *db;
+ krb5_error_code retval;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ if (!db_ctx->db_locks_held) /* lock already unlocked */
+ return KRB5_KDB_NOTLOCKED;
+ db = db_ctx->db;
+ if (--(db_ctx->db_locks_held) == 0) {
+ (*db->close)(db);
+ db_ctx->db = NULL;
+
+ retval = krb5_lock_file(context, db_ctx->db_lf_file,
+ KRB5_LOCKMODE_UNLOCK);
+ db_ctx->db_lock_mode = 0;
+ return(retval);
+ }
+ return 0;
+}
+
+/*
+ * Create the database, assuming it's not there.
+ */
+krb5_error_code
+krb5_db2_db_create(context, db_name, flags)
+ krb5_context context;
+ char *db_name;
+ krb5_int32 flags;
+{
+ register krb5_error_code retval = 0;
+ char *okname;
+ int fd;
+ krb5_db2_context *db_ctx;
+ DB *db;
+
+ if ((retval = k5db2_init_context(context)))
+ return(retval);
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ switch (flags) {
+ case KRB5_KDB_CREATE_HASH:
+ if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
+ return retval;
+ break;
+ case KRB5_KDB_CREATE_BTREE:
+ case 0:
+ if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
+ return retval;
+ break;
+ default:
+ return KRB5_KDB_BAD_CREATEFLAGS;
+ }
+ db = k5db2_dbopen(db_ctx, db_name, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (db == NULL)
+ retval = errno;
+ else
+ (*db->close)(db);
+ if (retval == 0) {
+ okname = gen_dbsuffix(db_name, KDB2_LOCK_EXT);
+ if (!okname)
+ retval = ENOMEM;
+ else {
+ fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600);
+ if (fd < 0)
+ retval = errno;
+ else
+ close(fd);
+ free_dbsuffix(okname);
+ }
+ }
+ return retval;
+}
+
+/*
+ * Destroy the database. Zero's out all of the files, just to be sure.
+ */
+krb5_error_code
+destroy_file_suffix(dbname, suffix)
+ char *dbname;
+ char *suffix;
+{
+ char *filename;
+ struct stat statb;
+ int nb,fd,i,j;
+ char buf[BUFSIZ];
+ char zbuf[BUFSIZ];
+ int dowrite;
+
+ filename = gen_dbsuffix(dbname, suffix);
+ if (filename == 0)
+ return ENOMEM;
+ if ((fd = open(filename, O_RDWR, 0)) < 0) {
+ free(filename);
+ return errno;
+ }
+ /* fstat() will probably not fail unless using a remote filesystem
+ (which is inappropriate for the kerberos database) so this check
+ is mostly paranoia. */
+ if (fstat(fd, &statb) == -1) {
+ int retval = errno;
+ free(filename);
+ return retval;
+ }
+ /*
+ * Stroll through the file, reading in BUFSIZ chunks. If everything
+ * is zero, then we're done for that block, otherwise, zero the block.
+ * We would like to just blast through everything, but some DB
+ * implementations make holey files and writing data to the holes
+ * causes actual blocks to be allocated which is no good, since
+ * we're just about to unlink it anyways.
+ */
+ memset(zbuf, 0, BUFSIZ);
+ i = 0;
+ while (i < statb.st_size) {
+ dowrite = 0;
+ nb = read(fd, buf, BUFSIZ);
+ if (nb < 0) {
+ int retval = errno;
+ free(filename);
+ return retval;
+ }
+ for (j=0; j<nb; j++) {
+ if (buf[j] != '\0') {
+ dowrite = 1;
+ break;
+ }
+ }
+ if (dowrite) {
+ lseek(fd, i, SEEK_SET);
+ nb = write(fd, zbuf, nb);
+ if (nb < 0) {
+ int retval = errno;
+ free(filename);
+ return retval;
+ }
+ }
+ i += nb;
+ }
+ /* ??? Is fsync really needed? I don't know of any non-networked
+ filesystem which will discard queued writes to disk if a file
+ is deleted after it is closed. --jfc */
+#ifndef NOFSYNC
+ fsync(fd);
+#endif
+ close(fd);
+
+ if (unlink(filename)) {
+ free(filename);
+ return(errno);
+ }
+ free(filename);
+ return(0);
+}
+
+/*
+ * Since the destroy operation happens outside the init/fini bracket, we
+ * have some tomfoolery to undergo here. If we're operating under no
+ * database context, then we initialize with the default. If the caller
+ * wishes a different context (e.g. different dispatch table), it's their
+ * responsibility to call kdb5_db_set_dbops() before this call. That will
+ * set up the right dispatch table values (e.g. name extensions).
+ *
+ * Not quite valid due to ripping out of dbops...
+ */
+krb5_error_code
+krb5_db2_db_destroy(context, dbname)
+ krb5_context context;
+ char *dbname;
+{
+ krb5_error_code retval1, retval2;
+ krb5_boolean tmpcontext;
+
+ tmpcontext = 0;
+ if (!context->db_context) {
+ tmpcontext = 1;
+ if ((retval1 = k5db2_init_context(context)))
+ return(retval1);
+ }
+
+ retval1 = retval2 = 0;
+ retval1 = destroy_file_suffix(dbname, "");
+ retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
+
+ if (tmpcontext) {
+ k5db2_clear_context((krb5_db2_context *) context->db_context);
+ free(context->db_context);
+ context->db_context = NULL;
+ }
+
+ if (retval1 || retval2)
+ return (retval1 ? retval1 : retval2);
+ else
+ return 0;
+}
+
+/*
+ * "Atomically" rename the database in a way that locks out read
+ * access in the middle of the rename.
+ *
+ * Not perfect; if we crash in the middle of an update, we don't
+ * necessarily know to complete the transaction the rename, but...
+ *
+ * Since the rename operation happens outside the init/fini bracket, we
+ * have to go through the same stuff that we went through up in db_destroy.
+ */
+krb5_error_code
+krb5_db2_db_rename(context, from, to)
+ krb5_context context;
+ char *from;
+ char *to;
+{
+ DB *db;
+ char *fromok;
+ krb5_error_code retval;
+ krb5_db2_context *s_context, *db_ctx;
+
+ s_context = context->db_context;
+ context->db_context = NULL;
+ if ((retval = k5db2_init_context(context)))
+ return retval;
+ db_ctx = (krb5_db2_context *) context->db_context;
+
+ /*
+ * Create the database if it does not already exist; the
+ * files must exist because krb5_db2_db_lock, called below,
+ * will fail otherwise.
+ */
+ db = k5db2_dbopen(db_ctx, to, O_RDWR|O_CREAT, 0600);
+ if (db == NULL) {
+ retval = errno;
+ goto errout;
+ }
+ else
+ (*db->close)(db);
+ /*
+ * Set the database to the target, so that other processes sharing
+ * the target will stop their activity, and notice the new database.
+ */
+ retval = krb5_db2_db_set_name(context, to);
+ if (retval)
+ goto errout;
+
+ db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT);
+ if (db_ctx->db_lf_name == NULL) {
+ retval = ENOMEM;
+ goto errout;
+ }
+ db_ctx->db_lf_file = open(db_ctx->db_lf_name, O_RDWR|O_CREAT, 0600);
+ if (db_ctx->db_lf_file < 0) {
+ retval = errno;
+ goto errout;
+ }
+
+ db_ctx->db_inited = 1;
+
+ retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time);
+ if (retval)
+ goto errout;
+
+ fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
+ if (fromok == NULL) {
+ retval = ENOMEM;
+ goto errout;
+ }
+
+ if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ goto errfromok;
+
+ if ((retval = krb5_db2_db_start_update(context)))
+ goto errfromok;
+
+ if (rename(from, to)) {
+ retval = errno;
+ goto errfromok;
+ }
+ if (unlink(fromok)) {
+ retval = errno;
+ goto errfromok;
+ }
+ retval = krb5_db2_db_end_update(context);
+errfromok:
+ free_dbsuffix(fromok);
+errout:
+ if (context->db_context) {
+ if (db_ctx->db_lf_file >= 0) {
+ krb5_db2_db_unlock(context);
+ close(db_ctx->db_lf_file);
+ }
+ k5db2_clear_context((krb5_db2_context *) context->db_context);
+ free(context->db_context);
+ }
+
+ context->db_context = s_context;
+ (void) krb5_db2_db_unlock(context); /* unlock saved context db */
+
+ return retval;
+}
+
+/*
+ * look up a principal in the data base.
+ * returns number of entries found, and whether there were
+ * more than requested.
+ */
+
+krb5_error_code
+krb5_db2_db_get_principal(context, searchfor, entries, nentries, more)
+ krb5_context context;
+ krb5_principal searchfor;
+ krb5_db_entry *entries; /* filled in */
+ int *nentries; /* how much room/how many found */
+ krb5_boolean *more; /* are there more? */
+{
+ krb5_db2_context *db_ctx;
+ krb5_error_code retval;
+ DB *db;
+ DBT key, contents;
+ krb5_data keydata, contdata;
+ int try, dbret;
+
+ *more = FALSE;
+ *nentries = 0;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ for (try = 0; try < KRB5_DB2_MAX_RETRY; try++) {
+ if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
+ if (db_ctx->db_nb_locks)
+ return(retval);
+ sleep(1);
+ continue;
+ }
+ break;
+ }
+ if (try == KRB5_DB2_MAX_RETRY)
+ return KRB5_KDB_DB_INUSE;
+
+ /* XXX deal with wildcard lookups */
+ retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
+ if (retval)
+ goto cleanup;
+ key.data = keydata.data;
+ key.size = keydata.length;
+
+ db = db_ctx->db;
+ dbret = (*db->get)(db, &key, &contents, 0);
+ retval = errno;
+ krb5_free_data_contents(context, &keydata);
+ switch (dbret) {
+ case 1:
+ retval = 0;
+ case -1:
+ default:
+ *nentries = 0;
+ goto cleanup;
+ case 0:
+ contdata.data = contents.data;
+ contdata.length = contents.size;
+ retval = krb5_decode_princ_contents(context, &contdata, entries);
+ if (!retval)
+ *nentries = 1;
+ break;
+ }
+
+cleanup:
+ (void) krb5_db2_db_unlock(context); /* unlock read lock */
+ return retval;
+}
+
+/*
+ Free stuff returned by krb5_db2_db_get_principal.
+ */
+void
+krb5_db2_db_free_principal(context, entries, nentries)
+ krb5_context context;
+ krb5_db_entry *entries;
+ int nentries;
+{
+ register int i;
+ for (i = 0; i < nentries; i++)
+ krb5_dbe_free_contents(context, &entries[i]);
+ return;
+}
+
+/*
+ Stores the *"nentries" entry structures pointed to by "entries" in the
+ database.
+
+ *"nentries" is updated upon return to reflect the number of records
+ acutally stored; the first *"nstored" records will have been stored in the
+ database (even if an error occurs).
+
+ */
+
+krb5_error_code
+krb5_db2_db_put_principal(context, entries, nentries)
+ krb5_context context;
+ krb5_db_entry *entries;
+ register int *nentries; /* number of entry structs to update */
+{
+ int i, n, dbret;
+ DB *db;
+ DBT key, contents;
+ krb5_data contdata, keydata;
+ krb5_error_code retval;
+ krb5_db2_context *db_ctx;
+
+ n = *nentries;
+ *nentries = 0;
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ return retval;
+
+ db = db_ctx->db;
+ if ((retval = krb5_db2_db_start_update(context))) {
+ (void)krb5_db2_db_unlock(context);
+ return retval;
+ }
+
+ /* for each one, stuff temps, and do replace/append */
+ for (i = 0; i < n; i++) {
+ retval = krb5_encode_princ_contents(context, &contdata, entries);
+ if (retval)
+ break;
+ contents.data = contdata.data;
+ contents.size = contdata.length;
+ retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
+ if (retval) {
+ krb5_free_data_contents(context, &contdata);
+ break;
+ }
+
+ key.data = keydata.data;
+ key.size = keydata.length;
+ dbret = (*db->put)(db, &key, &contents, 0);
+ retval = dbret ? errno : 0;
+ krb5_free_data_contents(context, &keydata);
+ krb5_free_data_contents(context, &contdata);
+ if (retval)
+ break;
+ entries++; /* bump to next struct */
+ }
+
+ (void)krb5_db2_db_end_update(context);
+ (void)krb5_db2_db_unlock(context); /* unlock database */
+ *nentries = i;
+ return(retval);
+}
+
+/*
+ * delete a principal from the data base.
+ * returns number of entries removed
+ */
+
+krb5_error_code
+krb5_db2_db_delete_principal(context, searchfor, nentries)
+ krb5_context context;
+ krb5_principal searchfor;
+ int *nentries; /* how many found & deleted */
+{
+ krb5_error_code retval;
+ krb5_db_entry entry;
+ krb5_db2_context *db_ctx;
+ DB *db;
+ DBT key, contents;
+ krb5_data keydata, contdata;
+ int i, dbret;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ return(retval);
+
+ if ((retval = krb5_db2_db_start_update(context))) {
+ (void) krb5_db2_db_unlock(context); /* unlock write lock */
+ return(retval);
+ }
+
+ if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
+ goto cleanup;
+ key.data = keydata.data;
+ key.size = keydata.length;
+
+ db = db_ctx->db;
+ dbret = (*db->get)(db, &key, &contents, 0);
+ retval = errno;
+ switch (dbret) {
+ case 1:
+ retval = KRB5_KDB_NOENTRY;
+ case -1:
+ default:
+ *nentries = 0;
+ goto cleankey;
+ case 0:
+ }
+ memset((char *)&entry, 0, sizeof(entry));
+ contdata.data = contents.data;
+ contdata.length = contents.size;
+ retval = krb5_decode_princ_contents(context, &contdata, &entry);
+ if (retval)
+ goto cleankey;
+ *nentries = 1;
+
+ /* Clear encrypted key contents */
+ for (i = 0; i < entry.n_key_data; i++) {
+ if (entry.key_data[i].key_data_length[0]) {
+ memset((char *)entry.key_data[i].key_data_contents[0], 0,
+ entry.key_data[i].key_data_length[0]);
+ }
+ }
+
+ retval = krb5_encode_princ_contents(context, &contdata, &entry);
+ krb5_dbe_free_contents(context, &entry);
+ if (retval)
+ goto cleankey;
+
+ contents.data = contdata.data;
+ contents.size = contdata.length;
+ dbret = (*db->put)(db, &key, &contents, 0);
+ retval = dbret ? errno : 0;
+ krb5_free_data_contents(context, &contdata);
+ if (retval)
+ goto cleankey;
+ dbret = (*db->del)(db, &key, 0);
+ retval = dbret ? errno : 0;
+cleankey:
+ krb5_free_data_contents(context, &keydata);
+
+cleanup:
+ (void) krb5_db2_db_end_update(context);
+ (void) krb5_db2_db_unlock(context); /* unlock write lock */
+ return retval;
+}
+
+krb5_error_code
+krb5_db2_db_iterate (context, func, func_arg)
+ krb5_context context;
+ krb5_error_code (*func) PROTOTYPE((krb5_pointer, krb5_db_entry *));
+ krb5_pointer func_arg;
+{
+ krb5_db2_context *db_ctx;
+ DB *db;
+ DBT key, contents;
+ krb5_data contdata;
+ krb5_db_entry entries;
+ krb5_error_code retval;
+ int dbret;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ db_ctx = (krb5_db2_context *) context->db_context;
+ retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
+ if (retval)
+ return retval;
+
+ db = db_ctx->db;
+ dbret = (*db->seq)(db, &key, &contents, R_FIRST);
+ while (dbret == 0) {
+ contdata.data = contents.data;
+ contdata.length = contents.size;
+ retval = krb5_decode_princ_contents(context, &contdata, &entries);
+ if (retval)
+ break;
+ retval = (*func)(func_arg, &entries);
+ krb5_dbe_free_contents(context, &entries);
+ if (retval)
+ break;
+ dbret = (*db->seq)(db, &key, &contents, R_NEXT);
+ }
+ switch (dbret) {
+ case 1:
+ case 0:
+ break;
+ case -1:
+ default:
+ retval = errno;
+ }
+ (void) krb5_db2_db_unlock(context);
+ return retval;
+}
+
+krb5_boolean
+krb5_db2_db_set_lockmode(context, mode)
+ krb5_context context;
+ krb5_boolean mode;
+{
+ krb5_boolean old;
+ krb5_db2_context *db_ctx;
+
+ old = mode;
+ if ((db_ctx = (krb5_db2_context *) context->db_context)) {
+ old = db_ctx->db_nb_locks;
+ db_ctx->db_nb_locks = mode;
+ }
+ return old;
+}
+
+/*
+ * Context serialization operations.
+ *
+ * Ick, this is really gross. --- tlyu
+ */
+
+/*
+ * kdb5_context_size() - Determine size required to serialize.
+ */
+static krb5_error_code
+kdb5_context_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ size_t required;
+ krb5_db2_context *dbctx;
+
+ /*
+ * The database context requires at minimum:
+ * krb5_int32 for KV5M_DB_CONTEXT
+ * krb5_int32 for db_inited
+ * krb5_int32 for database lockfile non-blocking flag
+ * krb5_int32 for database lockfile lock count
+ * krb5_int32 for database lockfile lock mode
+ * krb5_int32 for length of database name.
+ * krb5_int32 for KV5M_DB_CONTEXT
+ */
+ kret = EINVAL;
+ if ((dbctx = (krb5_db2_context *) arg)) {
+ required = (sizeof(krb5_int32) * 7);
+#ifdef notdef
+ if (dbctx->db_inited && dbctx->db_dispatch && dbctx->db_name)
+ required += strlen(dbctx->db_name);
+#endif
+ kret = 0;
+ *sizep += required;
+ }
+ return(kret);
+}
+
+/*
+ * kdb5_context_externalize() - Externalize the database context.
+ */
+static krb5_error_code
+kdb5_context_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_db2_context *dbctx;
+ size_t required;
+ krb5_octet *bp;
+ size_t remain;
+
+ required = 0;
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ if ((dbctx = (krb5_db2_context *) arg)) {
+ kret = ENOMEM;
+ if (!kdb5_context_size(kcontext, arg, &required) &&
+ (required <= remain)) {
+ /* Write magic number */
+ (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
+
+ /* Write inited flag */
+ (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_inited,
+ &bp, &remain);
+
+ /* Write blocking lock lockmode */
+ (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_nb_locks,
+ &bp, &remain);
+
+ /* Write lock count */
+ (void) krb5_ser_pack_int32((krb5_int32)
+ (dbctx->db_inited) ?
+ dbctx->db_locks_held : 0,
+ &bp, &remain);
+
+ /* Write lock mode */
+ (void) krb5_ser_pack_int32((krb5_int32)
+ (dbctx->db_inited) ?
+ dbctx->db_lock_mode : 0,
+ &bp, &remain);
+
+ /* Write length of database name */
+ (void) krb5_ser_pack_int32((dbctx->db_inited && dbctx->db_name) ?
+ (krb5_int32) strlen(dbctx->db_name) : 0,
+ &bp, &remain);
+ if (dbctx->db_inited && dbctx->db_name)
+ (void) krb5_ser_pack_bytes((krb5_octet *) dbctx->db_name,
+ strlen(dbctx->db_name),
+ &bp, &remain);
+
+ /* Write trailer */
+ (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
+ kret = 0;
+ *buffer = bp;
+ *lenremain = remain;
+ }
+ }
+ return(kret);
+}
+
+/*
+ * kdb5_context_internalize() - Internalize the database context.
+ */
+static krb5_error_code
+kdb5_context_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_context tmpctx;
+ krb5_db2_context *dbctx;
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+ krb5_int32 iflag;
+ krb5_int32 nb_lockmode;
+ krb5_int32 lockcount;
+ krb5_int32 lockmode;
+ krb5_int32 dbnamelen;
+ char *dbname;
+
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ dbctx = (krb5_db2_context *) NULL;
+ /* Read our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ ibuf = 0;
+ if (ibuf == KV5M_DB_CONTEXT) {
+ kret = ENOMEM;
+
+ if (!(kret = krb5_ser_unpack_int32(&iflag, &bp, &remain)) &&
+ !(kret = krb5_ser_unpack_int32(&nb_lockmode, &bp, &remain)) &&
+ !(kret = krb5_ser_unpack_int32(&lockcount, &bp, &remain)) &&
+ !(kret = krb5_ser_unpack_int32(&lockmode, &bp, &remain)) &&
+ !(kret = krb5_ser_unpack_int32(&dbnamelen, &bp, &remain)) &&
+ !(kret = krb5_init_context(&tmpctx))) {
+ if (iflag) {
+ dbname = (char *) NULL;
+ if (dbnamelen &&
+ (dbname = (char *) malloc((size_t) (dbnamelen+1)))) {
+ kret = krb5_ser_unpack_bytes((krb5_octet *) dbname,
+ (size_t) dbnamelen,
+ &bp, &remain);
+ if (!kret)
+ dbname[dbnamelen] = '\0';
+ }
+ if (!kret &&
+ (!dbname || !(kret = krb5_db_set_name(tmpctx, dbname))) &&
+ !(kret = krb5_db_init(tmpctx))) {
+ dbctx = (krb5_db2_context *) tmpctx->db_context;
+ (void) krb5_db2_db_set_lockmode(tmpctx, 0);
+ if (lockmode)
+ kret = krb5_db_lock(tmpctx, lockmode);
+ if (!kret && lockmode)
+ dbctx->db_locks_held = lockcount;
+ (void) krb5_db2_db_set_lockmode(tmpctx, nb_lockmode);
+ }
+ if (dbname)
+ krb5_xfree(dbname);
+ }
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ if (kret || (ibuf != KV5M_DB_CONTEXT))
+ kret = EINVAL;
+
+ if (kret) {
+ if (dbctx)
+ krb5_db_fini(tmpctx);
+ }
+ else
+ tmpctx->db_context = NULL;
+ krb5_free_context(tmpctx);
+ }
+ }
+ if (!kret) {
+ *buffer = bp;
+ *lenremain = remain;
+ *argp = (krb5_pointer) dbctx;
+ }
+ return(kret);
+}
+
+/* Dispatch entry */
+static const krb5_ser_entry kdb5_context_ser_entry = {
+ KV5M_DB_CONTEXT, /* Type */
+ kdb5_context_size, /* Sizer routine */
+ kdb5_context_externalize, /* Externalize routine */
+ kdb5_context_internalize /* Externalize routine */
+};
+
+/*
+ * Register serializer.
+ */
+krb5_error_code
+krb5_ser_db_context_init(kcontext)
+ krb5_context kcontext;
+{
+ return(krb5_register_serializer(kcontext, &kdb5_context_ser_entry));
+}
diff --git a/src/lib/kdb/kdb_db2.h b/src/lib/kdb/kdb_db2.h
new file mode 100644
index 0000000000..2c0221986c
--- /dev/null
+++ b/src/lib/kdb/kdb_db2.h
@@ -0,0 +1,121 @@
+/*
+ * lib/kdb/kdb_db2.h
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * KDC Database backend definitions for Berkely DB.
+ */
+#ifndef KRB5_KDB_DB2_H
+
+/* renaming kludge */
+#define krb5_db2_db_set_name krb5_db_set_name
+#define krb5_db2_db_set_nonblocking krb5_db_set_nonblocking
+#define krb5_db2_db_init krb5_db_init
+#define krb5_db2_db_fini krb5_db_fini
+#define krb5_db2_db_get_age krb5_db_get_age
+#define krb5_db2_db_create krb5_db_create
+#define krb5_db2_db_destroy kdb5_db_destroy
+#define krb5_db2_db_rename krb5_db_rename
+#define krb5_db2_db_get_principal krb5_db_get_principal
+#define krb5_db2_db_free_principal krb5_db_free_principal
+#define krb5_db2_db_put_principal krb5_db_put_principal
+#define krb5_db2_db_delete_principal krb5_db_delete_principal
+#define krb5_db2_db_iterate krb5_db_iterate
+#define krb5_db2_db_lock krb5_db_lock
+#define krb5_db2_db_unlock krb5_db_unlock
+#define krb5_db2_db_set_lockmode krb5_db_set_lockmode
+#define krb5_db2_db_close_database krb5_db_close_database
+#define krb5_db2_db_open_database krb5_db_open_database
+#define krb5_db2_db_set_mkey krb5_db_set_mkey
+#define krb5_db2_db_get_mkey krb5_db_get_mkey
+
+typedef struct _krb5_db2_context {
+ krb5_boolean db_inited; /* Context initialized */
+ char * db_name; /* Name of database */
+ DB * db; /* DB handle */
+ krb5_boolean hashfirst; /* Try hash database type first */
+ char * db_lf_name; /* Name of lock file */
+ int db_lf_file; /* File descriptor of lock file */
+ time_t db_lf_time; /* Time last updated */
+ int db_locks_held; /* Number of times locked */
+ int db_lock_mode; /* Last lock mode, e.g. greatest*/
+ krb5_boolean db_nb_locks; /* [Non]Blocking lock modes */
+ krb5_encrypt_block *db_master_key; /* Master key of database */
+} krb5_db2_context;
+
+#define KRB5_DB2_MAX_RETRY 5
+
+#define KDB2_LOCK_EXT ".ok"
+
+krb5_error_code krb5_db2_db_set_name
+ KRB5_PROTOTYPE((krb5_context,
+ char * ));
+krb5_error_code krb5_db2_db_init
+ KRB5_PROTOTYPE((krb5_context));
+krb5_error_code krb5_db2_db_fini
+ KRB5_PROTOTYPE((krb5_context));
+krb5_error_code krb5_db2_db_get_age
+ KRB5_PROTOTYPE((krb5_context,
+ char *,
+ time_t * ));
+krb5_error_code krb5_db2_db_create
+ KRB5_PROTOTYPE((krb5_context,
+ char *,
+ krb5_int32));
+krb5_error_code krb5_db2_db_destroy
+ KRB5_PROTOTYPE((krb5_context,
+ char * ));
+krb5_error_code krb5_db2_db_rename
+ KRB5_PROTOTYPE((krb5_context,
+ char *,
+ char * ));
+krb5_error_code krb5_db2_db_get_principal
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_db_entry *,
+ int *,
+ krb5_boolean * ));
+void krb5_db2_db_free_principal
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_db_entry *,
+ int ));
+krb5_error_code krb5_db2_db_put_principal
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_db_entry *,
+ int * ));
+krb5_error_code krb5_db2_db_iterate
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_error_code (*) KRB5_PROTOTYPE((krb5_pointer,
+ krb5_db_entry *)),
+ krb5_pointer ));
+krb5_error_code krb5_db2_db_set_nonblocking
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_boolean,
+ krb5_boolean * ));
+krb5_boolean krb5_db2_db_set_lockmode
+ KRB5_PROTOTYPE((krb5_context,
+ krb5_boolean ));
+krb5_error_code krb5_db2_db_open_database
+ KRB5_PROTOTYPE((krb5_context));
+krb5_error_code krb5_db2_db_close_database
+ KRB5_PROTOTYPE((krb5_context));
+
+#endif /* KRB5_KDB_DB2_H */
diff --git a/src/lib/kdb/kdb_xdr.c b/src/lib/kdb/kdb_xdr.c
index 044ce4c7fe..03a359636a 100644
--- a/src/lib/kdb/kdb_xdr.c
+++ b/src/lib/kdb/kdb_xdr.c
@@ -243,9 +243,9 @@ krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ)
}
krb5_error_code
-krb5_encode_princ_dbmkey(context, key, principal)
+krb5_encode_princ_dbkey(context, key, principal)
krb5_context context;
- datum *key;
+ krb5_data *key;
krb5_principal principal;
{
char *princ_name;
@@ -253,27 +253,24 @@ krb5_encode_princ_dbmkey(context, key, principal)
if (!(retval = krb5_unparse_name(context, principal, &princ_name))) {
/* need to store the NULL for decoding */
- key->dsize = strlen(princ_name)+1;
- key->dptr = princ_name;
+ key->length = strlen(princ_name)+1;
+ key->data = princ_name;
}
return(retval);
}
void
-krb5_free_princ_dbmkey(context, key)
+krb5_free_princ_dbkey(context, key)
krb5_context context;
- datum *key;
+ krb5_data *key;
{
- (void) free(key->dptr);
- key->dsize = 0;
- key->dptr = 0;
- return;
+ (void) krb5_free_data_contents(context, key);
}
krb5_error_code
krb5_encode_princ_contents(context, content, entry)
krb5_context context;
- datum * content;
+ krb5_data * content;
krb5_db_entry * entry;
{
int unparse_princ_size, i, j;
@@ -301,20 +298,20 @@ krb5_encode_princ_contents(context, content, entry)
* then (4 [type + length] + tl_data_length) bytes per tl_data
* then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data
*/
- content->dsize = entry->len + entry->e_length;
+ content->length = entry->len + entry->e_length;
if ((retval = krb5_unparse_name(context, entry->princ, &unparse_princ)))
return(retval);
unparse_princ_size = strlen(unparse_princ) + 1;
- content->dsize += unparse_princ_size;
- content->dsize += 2;
+ content->length += unparse_princ_size;
+ content->length += 2;
i = 0;
/* tl_data is a linked list */
for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
- content->dsize += tl_data->tl_data_length;
- content->dsize += 4; /* type, length */
+ content->length += tl_data->tl_data_length;
+ content->length += 4; /* type, length */
i++;
}
@@ -325,14 +322,14 @@ krb5_encode_princ_contents(context, content, entry)
/* key_data is an array */
for (i = 0; i < entry->n_key_data; i++) {
- content->dsize += 4; /* Version, KVNO */
+ content->length += 4; /* Version, KVNO */
for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
- content->dsize += entry->key_data[i].key_data_length[j];
- content->dsize += 4; /* type + length */
+ content->length += entry->key_data[i].key_data_length[j];
+ content->length += 4; /* type + length */
}
}
- if ((content->dptr = malloc(content->dsize)) == NULL) {
+ if ((content->data = malloc(content->length)) == NULL) {
retval = ENOMEM;
goto epc_error;
}
@@ -341,7 +338,7 @@ krb5_encode_princ_contents(context, content, entry)
* Now we go through entry again, this time copying data
* These first entries are always saved regaurdless of version
*/
- nextloc = content->dptr;
+ nextloc = content->data;
/* Base Length */
krb5_kdb_encode_int16(entry->len, nextloc);
@@ -450,18 +447,16 @@ epc_error:;
void
krb5_free_princ_contents(context, contents)
krb5_context context;
- datum *contents;
+ krb5_data *contents;
{
- free(contents->dptr);
- contents->dsize = 0;
- contents->dptr = 0;
+ krb5_free_data_contents(context, contents);
return;
}
krb5_error_code
krb5_decode_princ_contents(context, content, entry)
krb5_context context;
- datum * content;
+ krb5_data * content;
krb5_db_entry * entry;
{
int sizeleft, i;
@@ -484,8 +479,8 @@ krb5_decode_princ_contents(context, content, entry)
*/
/* First do the easy stuff */
- nextloc = content->dptr;
- sizeleft = content->dsize;
+ nextloc = content->data;
+ sizeleft = content->length;
if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0)
return KRB5_KDB_TRUNCATED_RECORD;
diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c
index 82ed08e33c..c114946ea0 100644
--- a/src/lib/kdb/keytab.c
+++ b/src/lib/kdb/keytab.c
@@ -23,7 +23,7 @@
*/
#include "k5-int.h"
-#include "kdb_dbc.h"
+#include "kdb_kt.h"
krb5_error_code krb5_ktkdb_close KRB5_PROTOTYPE((krb5_context, krb5_keytab));
@@ -50,23 +50,12 @@ typedef struct krb5_ktkdb_data {
} krb5_ktkdb_data;
krb5_error_code
-krb5_ktkdb_resolve(context, kdb, id)
+krb5_ktkdb_resolve(context, id)
krb5_context context;
- krb5_db_context * kdb;
krb5_keytab * id;
{
- krb5_db_context * data;
-
if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
return(ENOMEM);
-
- if ((data = (krb5_db_context *)malloc(sizeof(krb5_db_context))) == NULL) {
- krb5_xfree(*id);
- return(ENOMEM);
- }
-
- memcpy(data, kdb, sizeof(krb5_db_context));
- (*id)->data = (krb5_pointer)data;
(*id)->ops = &krb5_kt_kdb_ops;
(*id)->magic = KV5M_KEYTAB;
return(0);
@@ -85,8 +74,7 @@ krb5_ktkdb_close(context, kt)
* This routine should undo anything done by krb5_ktkdb_resolve().
*/
- krb5_xfree(kt->data);
- kt->ops = 0;
+ kt->ops = NULL;
krb5_xfree(kt);
return 0;
@@ -109,25 +97,24 @@ krb5_ktkdb_get_entry(context, id, principal, kvno, enctype, entry)
int n = 0;
/* Open database */
- /* krb5_dbm_db_init(context); */
- if ((kerror = krb5_dbm_db_open_database(context)))
+ /* krb5_db_init(context); */
+ if ((kerror = krb5_db_open_database(context)))
return(kerror);
/* get_principal */
- kerror = krb5_dbm_db_get_principal(context, principal, &
+ kerror = krb5_db_get_principal(context, principal, &
db_entry, &n, &more);
if (kerror) {
- krb5_dbm_db_close_database(context);
+ krb5_db_close_database(context);
return(kerror);
}
if (n != 1) {
- krb5_dbm_db_close_database(context);
+ krb5_db_close_database(context);
return KRB5_KT_NOTFOUND;
}
/* match key */
- /* WTF??? 2nd arg to dbm_db_get_mkey appears to be unused! -tlyu */
- kerror = krb5_dbm_db_get_mkey(context, id->ops, &master_key);
+ kerror = krb5_db_get_mkey(context, &master_key);
if (kerror)
goto error;
@@ -148,6 +135,6 @@ krb5_ktkdb_get_entry(context, id, principal, kvno, enctype, entry)
/* Close database */
error:
krb5_dbe_free_contents(context, &db_entry);
- krb5_dbm_db_close_database(context);
+ krb5_db_close_database(context);
return(kerror);
}
diff --git a/src/lib/kdb/t_kdb.c b/src/lib/kdb/t_kdb.c
index 799df31a1f..3502edac4e 100644
--- a/src/lib/kdb/t_kdb.c
+++ b/src/lib/kdb/t_kdb.c
@@ -445,7 +445,7 @@ delete_principal(kcontext, principal)
static int
do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
- ptest)
+ ptest, hash)
char *db;
int passes;
int verbose;
@@ -455,6 +455,7 @@ do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
int save_db;
int dontclean;
int ptest;
+ int hash;
{
krb5_error_code kret;
krb5_context kcontext;
@@ -475,6 +476,7 @@ do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
char *pname;
float elapsed;
krb5_keyblock stat_kb;
+ krb5_int32 crflags;
mkey_name = "master/key";
realm = master_princ_data.realm.data;
@@ -485,6 +487,7 @@ do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
db_created = 0;
linkage = "";
oparg = "";
+ crflags = hash ? KRB5_KDB_CREATE_HASH : KRB5_KDB_CREATE_BTREE;
/* Set up some initial context */
op = "initializing krb5";
@@ -542,7 +545,7 @@ do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
/* Create database */
op = "creating database";
- if ((kret = krb5_db_create(kcontext, db)))
+ if ((kret = krb5_db_create(kcontext, db, crflags)))
goto goodbye;
db_created = 1;
@@ -956,7 +959,7 @@ do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean,
(void) krb5_db_fini(kcontext);
if (db_created) {
if (!kret && !save_db) {
- kdb5_db_destroy(kcontext, db);
+ krb5_db_destroy(kcontext, db);
krb5_db_fini(kcontext);
} else {
if (kret && verbose)
@@ -987,7 +990,7 @@ main(argc, argv)
extern char *optarg;
int do_time, do_random, num_passes, check_cont, verbose, error;
- int save_db, dont_clean, do_ptest;
+ int save_db, dont_clean, do_ptest, hash;
char *db_name;
programname = argv[0];
@@ -1006,9 +1009,10 @@ main(argc, argv)
dont_clean = 0;
error = 0;
do_ptest = 0;
+ hash = 0;
/* Parse argument list */
- while ((option = getopt(argc, argv, "cd:n:prstvD")) != EOF) {
+ while ((option = getopt(argc, argv, "cd:n:prstvDh")) != EOF) {
switch (option) {
case 'c':
check_cont = 1;
@@ -1041,6 +1045,9 @@ main(argc, argv)
case 'D':
dont_clean = 1;
break;
+ case 'h':
+ hash = 1;
+ break;
default:
error++;
break;
@@ -1058,7 +1065,8 @@ main(argc, argv)
check_cont,
save_db,
dont_clean,
- do_ptest);
+ do_ptest,
+ hash);
return(error);
}