aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/kdb/db2/kdb_db2.c
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2005-12-17 10:28:39 +0000
committerKen Raeburn <raeburn@mit.edu>2005-12-17 10:28:39 +0000
commit965c2230c85dd09be5f3b4afed5a4bea39d41cf6 (patch)
treefa928a753e849d0bad4b2eb68b4fa1aeaa6b7eae /src/plugins/kdb/db2/kdb_db2.c
parent57da39d39e5afe9592de4cd7bb3de362e7443ca3 (diff)
downloadkrb5-965c2230c85dd09be5f3b4afed5a4bea39d41cf6.zip
krb5-965c2230c85dd09be5f3b4afed5a4bea39d41cf6.tar.gz
krb5-965c2230c85dd09be5f3b4afed5a4bea39d41cf6.tar.bz2
Rename "modules" to "plugins", and fix up makefile variables etc
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17565 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/plugins/kdb/db2/kdb_db2.c')
-rw-r--r--src/plugins/kdb/db2/kdb_db2.c1561
1 files changed, 1561 insertions, 0 deletions
diff --git a/src/plugins/kdb/db2/kdb_db2.c b/src/plugins/kdb/db2/kdb_db2.c
new file mode 100644
index 0000000..f3950ee
--- /dev/null
+++ b/src/plugins/kdb/db2/kdb_db2.c
@@ -0,0 +1,1561 @@
+/*
+ * 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. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * 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.
+ *
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "k5-int.h"
+#include <db.h>
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+#include "kdb5.h"
+#include "kdb_db2.h"
+#include "kdb_xdr.h"
+#include "policy_db.h"
+
+#define KDB_DB2_DATABASE_NAME "database_name"
+
+#define OLD_COMPAT_VERSION_1
+
+#ifdef OLD_COMPAT_VERSION_1
+#include "kdb_compat.h"
+#endif
+
+#include "kdb_db2.h"
+
+static char *gen_dbsuffix(char *, char *);
+
+static krb5_error_code krb5_db2_db_start_update(krb5_context);
+static krb5_error_code krb5_db2_db_end_update(krb5_context);
+
+krb5_error_code krb5_db2_db_set_name(krb5_context, char *);
+
+krb5_error_code krb5_db2_db_lock(krb5_context, int);
+
+static krb5_error_code krb5_db2_db_set_hashfirst(krb5_context, int);
+
+static char default_db_name[] = DEFAULT_KDB_FILE;
+krb5_set_err_func_t krb5_db2_dal_err_funcp = NULL;
+
+/*
+ * 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 \
+ && ((kdb5_dal_handle*)c->db_context)->db_context \
+ && ((krb5_db2_context *) ((kdb5_dal_handle*)c->db_context)->db_context)->db_inited)
+
+static krb5_error_code
+krb5_db2_get_db_opt(char *input, char **opt, char **val)
+{
+ char *pos = strchr(input, '=');
+ if (pos == NULL) {
+ *opt = NULL;
+ *val = strdup(input);
+ if (*val == NULL) {
+ return ENOMEM;
+ }
+ } else {
+ *opt = malloc((pos - input) + 1);
+ *val = strdup(pos + 1);
+ if (!*opt || !*val) {
+ return ENOMEM;
+ }
+ memcpy(*opt, input, pos - input);
+ (*opt)[pos - input] = '\0';
+ }
+ return (0);
+
+}
+
+/*
+ * Restore the default context.
+ */
+static void
+k5db2_clear_context(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(krb5_context context)
+{
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+
+ if (dal_handle->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);
+ dal_handle->db_context = (void *) db_ctx;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Utility routine: generate name of database file.
+ */
+
+static char *
+gen_dbsuffix(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(krb5_db2_context *dbc, char *fname, int flags, int mode)
+{
+ DB *db;
+ BTREEINFO bti;
+ HASHINFO hashi;
+
+ bti.flags = 0;
+ bti.cachesize = 0;
+ bti.psize = 4096;
+ 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(krb5_context context, int hashfirst)
+{
+ krb5_db2_context *dbc;
+ kdb5_dal_handle *dal_handle;
+
+ if (k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+ dbc->hashfirst = hashfirst;
+ return 0;
+}
+
+/*
+ * initialization for data base routines.
+ */
+
+krb5_error_code
+krb5_db2_db_init(krb5_context context)
+{
+ char *filename = NULL;
+ krb5_db2_context *db_ctx;
+ krb5_error_code retval;
+ kdb5_dal_handle *dal_handle;
+ char policy_db_name[1024], policy_lock_name[1024];
+
+ 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);
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = dal_handle->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;
+
+ sprintf(policy_db_name, "%s.kadm5", db_ctx->db_name);
+ sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+ if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
+ policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
+ {
+ 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(krb5_context context)
+{
+ krb5_error_code retval = 0;
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ if (dal_handle == NULL) {
+ return 0;
+ }
+
+ db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+ if (k5db2_inited(context)) {
+ if (close(db_ctx->db_lf_file))
+ retval = errno;
+ else
+ retval = 0;
+ }
+ if (db_ctx) {
+ if (db_ctx->policy_db) {
+ retval =
+ osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
+ if (retval)
+ return retval;
+ }
+
+ k5db2_clear_context(db_ctx);
+ /* free(dal_handle->db_context); */
+ dal_handle->db_context = NULL;
+ }
+ return retval;
+}
+
+/*
+ * Set/Get the master key associated with the database
+ */
+krb5_error_code
+krb5_db2_db_set_mkey(krb5_context context, krb5_keyblock *key)
+{
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ if (!k5db2_inited(context))
+ return (KRB5_KDB_DBNOTINITED);
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = dal_handle->db_context;
+ db_ctx->db_master_key = key;
+ return 0;
+}
+
+krb5_error_code
+krb5_db2_db_get_mkey(krb5_context context, krb5_keyblock **key)
+{
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ if (!k5db2_inited(context))
+ return (KRB5_KDB_DBNOTINITED);
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = dal_handle->db_context;
+ *key = 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(krb5_context context, char *name)
+{
+ DB *db;
+ krb5_db2_context *db_ctx;
+ krb5_error_code kret;
+ kdb5_dal_handle *dal_handle;
+
+ 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;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = dal_handle->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(krb5_context context, char *db_name, time_t *age)
+{
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+ struct stat st;
+
+ if (!k5db2_inited(context))
+ return (KRB5_KDB_DBNOTINITED);
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->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(krb5_context context)
+{
+ return 0;
+}
+
+static krb5_error_code
+krb5_db2_db_end_update(krb5_context context)
+{
+ krb5_error_code retval;
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+ struct stat st;
+ time_t now;
+ struct utimbuf utbuf;
+
+ if (!k5db2_inited(context))
+ return (KRB5_KDB_DBNOTINITED);
+
+ retval = 0;
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = dal_handle->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);
+}
+
+#define MAX_LOCK_TRIES 5
+
+krb5_error_code
+krb5_db2_db_lock(krb5_context context, int in_mode)
+{
+ krb5_db2_context *db_ctx;
+ int krb5_lock_mode;
+ DB *db;
+ krb5_error_code retval;
+ time_t mod_time;
+ kdb5_dal_handle *dal_handle;
+ int mode, gotlock, tries;
+
+ switch (in_mode) {
+ case KRB5_DB_LOCKMODE_PERMANENT:
+ mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
+ break;
+ case KRB5_DB_LOCKMODE_EXCLUSIVE:
+ mode = KRB5_LOCKMODE_EXCLUSIVE;
+ break;
+
+ case KRB5_DB_LOCKMODE_SHARED:
+ mode = KRB5_LOCKMODE_SHARED;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->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++;
+ goto policy_lock;
+ }
+
+ if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
+ return KRB5_KDB_BADLOCKMODE;
+
+ krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
+ for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
+ retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
+ if (retval == 0) {
+ gotlock++;
+ break;
+ } else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
+ /* tried to exclusive-lock something we don't have */
+ /* write access to */
+ return KRB5_KDB_CANTLOCK_DB;
+ sleep(1);
+ }
+ if (retval == EACCES)
+ return KRB5_KDB_CANTLOCK_DB;
+ else if (retval == EAGAIN || retval == EWOULDBLOCK)
+ return OSA_ADB_CANTLOCK_DB;
+ else if (retval != 0)
+ return retval;
+
+ 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++;
+
+ policy_lock:
+ if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) {
+ krb5_db2_db_unlock(context);
+ }
+ return retval;
+
+ lock_error:;
+ db_ctx->db_lock_mode = 0;
+ db_ctx->db_locks_held = 0;
+ krb5_db2_db_unlock(context);
+ return retval;
+}
+
+krb5_error_code
+krb5_db2_db_unlock(krb5_context context)
+{
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+ DB *db;
+ krb5_error_code retval;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+ if ((retval = osa_adb_release_lock(db_ctx->policy_db))) {
+ return retval;
+ }
+
+ 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(krb5_context context, char *db_name, krb5_int32 flags)
+{
+ register krb5_error_code retval = 0;
+ kdb5_dal_handle *dal_handle;
+ char *okname;
+ int fd;
+ krb5_db2_context *db_ctx;
+ DB *db;
+ char policy_db_name[1024], policy_lock_name[1024];
+
+ if ((retval = k5db2_init_context(context)))
+ return (retval);
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->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);
+ }
+ }
+
+ sprintf(policy_db_name, "%s.kadm5", db_name);
+ sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+ retval = osa_adb_create_db(policy_db_name,
+ policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
+
+ return retval;
+}
+
+/*
+ * Destroy the database. Zero's out all of the files, just to be sure.
+ */
+static krb5_error_code
+destroy_file_suffix(char *dbname, char *suffix)
+{
+ char *filename;
+ struct stat statb;
+ int nb, fd;
+ unsigned int j;
+ off_t pos;
+ 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);
+ pos = 0;
+ while (pos < 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;
+ }
+ }
+ /* For signedness */
+ j = nb;
+ if (dowrite) {
+ lseek(fd, pos, SEEK_SET);
+ nb = write(fd, zbuf, j);
+ if (nb < 0) {
+ int retval = errno;
+ free(filename);
+ return retval;
+ }
+ }
+ pos += 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(krb5_context context, char *dbname)
+{
+ krb5_error_code retval1, retval2;
+ krb5_boolean tmpcontext;
+ char policy_db_name[1024], policy_lock_name[1024];
+
+ tmpcontext = 0;
+ if (!context->db_context
+ || !((kdb5_dal_handle *) context->db_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 *) ((kdb5_dal_handle *) context->
+ db_context)->db_context);
+ free(((kdb5_dal_handle *) context->db_context)->db_context);
+ ((kdb5_dal_handle *) context->db_context)->db_context = NULL;
+ }
+
+ if (retval1 || retval2)
+ return (retval1 ? retval1 : retval2);
+
+ sprintf(policy_db_name, "%s.kadm5", dbname);
+ sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+ retval1 = osa_adb_destroy_db(policy_db_name,
+ policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
+
+ return retval1;
+}
+
+/*
+ * 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(krb5_context context,
+ krb5_const_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 trynum, dbret;
+ kdb5_dal_handle *dal_handle;
+
+ *more = FALSE;
+ *nentries = 0;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+ for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) {
+ if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
+ if (db_ctx->db_nb_locks)
+ return (retval);
+ sleep(1);
+ continue;
+ }
+ break;
+ }
+ if (trynum == 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.
+ */
+krb5_error_code
+krb5_db2_db_free_principal(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 0;
+}
+
+/*
+ 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(krb5_context context,
+ krb5_db_entry *entries,
+ int *nentries, /* number of entry structs to update */
+ char **db_args)
+{
+ int i, n, dbret;
+ DB *db;
+ DBT key, contents;
+ krb5_data contdata, keydata;
+ krb5_error_code retval;
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ if (db_args) {
+ /* DB2 does not support db_args DB arguments for principal */
+ char buf[KRB5_MAX_ERR_STR];
+ sprintf(buf, "Unsupported argument \"%s\" for db2", db_args[0]);
+ krb5_db2_dal_err_funcp(context, krb5_err_have_str, EINVAL, buf);
+ return EINVAL;
+ }
+
+ n = *nentries;
+ *nentries = 0;
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->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(krb5_context context,
+ krb5_const_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;
+ kdb5_dal_handle *dal_handle;
+
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->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,
+ (unsigned) 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_ext(krb5_context context,
+ krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
+ krb5_pointer func_arg,
+ int backwards, int recursive)
+{
+ krb5_db2_context *db_ctx;
+ DB *db;
+ DBT key, contents;
+ krb5_data contdata;
+ krb5_db_entry entries;
+ krb5_error_code retval;
+ kdb5_dal_handle *dal_handle;
+ int dbret;
+ void *cookie;
+
+ cookie = NULL;
+ if (!k5db2_inited(context))
+ return KRB5_KDB_DBNOTINITED;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ db_ctx = (krb5_db2_context *) dal_handle->db_context;
+ retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
+
+ if (retval)
+ return retval;
+
+ db = db_ctx->db;
+ if (recursive && db->type != DB_BTREE) {
+ (void) krb5_db2_db_unlock(context);
+ return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
+ }
+
+ if (!recursive) {
+ dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST);
+ } else {
+#ifdef HAVE_BT_RSEQ
+ dbret = bt_rseq(db, &key, &contents, &cookie,
+ backwards ? R_LAST : R_FIRST);
+#else
+ (void) krb5_db2_db_unlock(context);
+ return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
+#endif
+ }
+ 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;
+ if (!recursive) {
+ dbret = (*db->seq) (db, &key, &contents,
+ backwards ? R_PREV : R_NEXT);
+ } else {
+#ifdef HAVE_BT_RSEQ
+ dbret = bt_rseq(db, &key, &contents, &cookie,
+ backwards ? R_PREV : R_NEXT);
+#else
+ (void) krb5_db2_db_unlock(context);
+ return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
+#endif
+ }
+ }
+ switch (dbret) {
+ case 1:
+ case 0:
+ break;
+ case -1:
+ default:
+ retval = errno;
+ }
+ (void) krb5_db2_db_unlock(context);
+ return retval;
+}
+
+krb5_error_code
+krb5_db2_db_iterate(krb5_context context,
+ char *match_expr,
+ krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
+ krb5_pointer func_arg)
+{
+ return krb5_db2_db_iterate_ext(context, func, func_arg, 0, 0);
+}
+
+krb5_boolean
+krb5_db2_db_set_lockmode(krb5_context context, krb5_boolean mode)
+{
+ krb5_boolean old;
+ krb5_db2_context *db_ctx;
+ kdb5_dal_handle *dal_handle;
+
+ dal_handle = (kdb5_dal_handle *) context->db_context;
+ old = mode;
+ if (dal_handle && (db_ctx = (krb5_db2_context *) dal_handle->db_context)) {
+ old = db_ctx->db_nb_locks;
+ db_ctx->db_nb_locks = mode;
+ }
+ return old;
+}
+
+/*
+ * DAL API functions
+ */
+krb5_error_code
+krb5_db2_lib_init(krb5_set_err_func_t set_err)
+{
+ krb5_db2_dal_err_funcp = set_err;
+ return 0;
+}
+
+krb5_error_code
+krb5_db2_lib_cleanup()
+{
+ /* right now, no cleanup required */
+ return 0;
+}
+
+krb5_error_code
+krb5_db2_open(krb5_context kcontext,
+ char *conf_section, char **db_args, int mode)
+{
+ krb5_error_code status = 0;
+ char **t_ptr = db_args;
+ char db_name_set = 0;
+
+ if (k5db2_inited(kcontext))
+ return 0;
+
+ while (t_ptr && *t_ptr) {
+ char *opt = NULL, *val = NULL;
+
+ krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+ if (opt && !strcmp(opt, "dbname")) {
+ status = krb5_db2_db_set_name(kcontext, val);
+ if (status) {
+ free(opt);
+ free(val);
+ goto clean_n_exit;
+ }
+ db_name_set = 1;
+ }
+ /* ignore hash argument. Might have been passed from create */
+ else if (!opt || strcmp(opt, "hash")) {
+ char buf[KRB5_MAX_ERR_STR];
+ sprintf(buf, "Unsupported argument \"%s\" for db2",
+ opt ? opt : val);
+ krb5_db2_dal_err_funcp(kcontext, krb5_err_have_str, EINVAL, buf);
+ free(opt);
+ free(val);
+ return EINVAL;
+ }
+
+ free(opt);
+ free(val);
+ t_ptr++;
+ }
+
+ if (!db_name_set) {
+ char *value = NULL;
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME, /* under given conf section */
+ NULL, &value);
+
+ if (value == NULL) {
+ /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME, /* under given realm */
+ default_db_name, &value);
+ if (status) {
+ goto clean_n_exit;
+ }
+ }
+
+ status = krb5_db2_db_set_name(kcontext, value);
+ profile_release_string(value);
+ if (status) {
+ goto clean_n_exit;
+ }
+
+ }
+
+ status = krb5_db2_db_init(kcontext);
+
+ clean_n_exit:
+ return status;
+}
+
+krb5_error_code
+krb5_db2_create(krb5_context kcontext, char *conf_section, char **db_args)
+{
+ krb5_error_code status = 0;
+ char **t_ptr = db_args;
+ char db_name_set = 0;
+ krb5_int32 flags = KRB5_KDB_CREATE_BTREE;
+ char *db_name = NULL;
+
+ if (k5db2_inited(kcontext))
+ return 0;
+
+ while (t_ptr && *t_ptr) {
+ char *opt = NULL, *val = NULL;
+
+ krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+ if (opt && !strcmp(opt, "dbname")) {
+ db_name = strdup(val);
+ status = krb5_db2_db_set_name(kcontext, val);
+ if (!status) {
+ status = EEXIST;
+ free(opt);
+ free(val);
+ goto clean_n_exit;
+ }
+ db_name_set = 1;
+ }
+ /* ignore hash argument. Might have been passed from create */
+ else if (opt && !strcmp(opt, "hash")) {
+ flags = KRB5_KDB_CREATE_HASH;
+ } else {
+ char buf[KRB5_MAX_ERR_STR];
+ sprintf(buf, "Unsupported argument \"%s\" for db2",
+ opt ? opt : val);
+ krb5_db2_dal_err_funcp(kcontext, krb5_err_have_str, EINVAL, buf);
+ free(opt);
+ free(val);
+ return EINVAL;
+ }
+
+ free(opt);
+ free(val);
+ t_ptr++;
+ }
+
+ if (!db_name_set) {
+ char *value = NULL;
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
+ KDB_MODULE_SECTION, conf_section,
+ /* under given conf section */
+ KDB_DB2_DATABASE_NAME, NULL, &value);
+
+ if (value == NULL) {
+ /* Special case for db2. We might actually be looking at
+ * old type config file where database is specified as
+ * part of realm. */
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
+ KDB_REALM_SECTION,
+ KRB5_DB_GET_REALM(kcontext),
+ /* under given realm */
+ KDB_DB2_DATABASE_NAME,
+ default_db_name, &value);
+ if (status) {
+ goto clean_n_exit;
+ }
+ }
+
+ db_name = strdup(value);
+ status = krb5_db2_db_set_name(kcontext, value);
+ profile_release_string(value);
+ if (!status) {
+ status = EEXIST;
+ goto clean_n_exit;
+ }
+
+ }
+
+ status = krb5_db2_db_create(kcontext, db_name, flags);
+ if (status)
+ goto clean_n_exit;
+ /* db2 has a problem of needing to close and open the database again. This removes that need */
+ status = krb5_db2_db_fini(kcontext);
+ if (status)
+ goto clean_n_exit;
+
+ status = krb5_db2_open(kcontext, conf_section, db_args, KRB5_KDB_OPEN_RW);
+
+ clean_n_exit:
+ if (db_name)
+ free(db_name);
+ return status;
+}
+
+krb5_error_code
+krb5_db2_destroy(krb5_context kcontext, char *conf_section, char **db_args)
+{
+ krb5_error_code status = 0;
+ char **t_ptr = db_args;
+ char db_name_set = 0;
+ char *db_name = NULL;
+
+ while (t_ptr && *t_ptr) {
+ char *opt = NULL, *val = NULL;
+
+ krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+ if (opt && !strcmp(opt, "dbname")) {
+ db_name = strdup(val);
+ status = krb5_db2_db_set_name(kcontext, val);
+ if (status) {
+ free(opt);
+ free(val);
+ goto clean_n_exit;
+ }
+ db_name_set = 1;
+ }
+ /* ignore hash argument. Might have been passed from create */
+ else if (!opt || strcmp(opt, "hash")) {
+ free(opt);
+ free(val);
+ return EINVAL;
+ }
+
+ free(opt);
+ free(val);
+ t_ptr++;
+ }
+
+ if (!db_name_set) {
+ char *value = NULL;
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME, /* under given conf section */
+ NULL, &value);
+
+ if (value == NULL) {
+ /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
+ status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME, /* under given realm */
+ default_db_name, &value);
+ if (status) {
+ goto clean_n_exit;
+ }
+ }
+
+ db_name = strdup(value);
+ status = krb5_db2_db_set_name(kcontext, value);
+ profile_release_string(value);
+ if (status) {
+ goto clean_n_exit;
+ }
+
+ }
+
+ status = krb5_db2_db_destroy(kcontext, db_name);
+
+ clean_n_exit:
+ if (db_name)
+ free(db_name);
+ return status;
+}
+
+krb5_error_code
+krb5_db2_set_master_key_ext(krb5_context kcontext,
+ char *pwd, krb5_keyblock * key)
+{
+ return krb5_db2_db_set_mkey(kcontext, key);
+}
+
+krb5_error_code
+krb5_db2_db_set_option(krb5_context kcontext, int option, void *value)
+{
+ krb5_error_code status = 0;
+ krb5_boolean oldval;
+
+ switch (option) {
+ case KRB5_KDB_OPT_SET_DB_NAME:
+ status = krb5_db2_db_set_name(kcontext, (char *) value);
+ break;
+
+ case KRB5_KDB_OPT_SET_LOCK_MODE:
+ oldval = krb5_db2_db_set_lockmode(kcontext, *((krb5_boolean *) value));
+ *((krb5_boolean *) value) = oldval;
+ break;
+
+ default:
+ status = -1; /* TBD */
+ break;
+ }
+
+ return status;
+}
+
+void *
+krb5_db2_alloc(krb5_context kcontext, void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+void
+krb5_db2_free(krb5_context kcontext, void *ptr)
+{
+ free(ptr);
+}
+
+/* policy functions */
+krb5_error_code
+krb5_db2_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *dbc;
+
+ dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+
+ return osa_adb_create_policy(dbc->policy_db, policy);
+}
+
+krb5_error_code
+krb5_db2_get_policy(krb5_context kcontext,
+ char *name, osa_policy_ent_t * policy, int *cnt)
+{
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *dbc;
+
+ dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+
+ return osa_adb_get_policy(dbc->policy_db, name, policy, cnt);
+}
+
+krb5_error_code
+krb5_db2_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *dbc;
+
+ dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+
+ return osa_adb_put_policy(dbc->policy_db, policy);
+}
+
+krb5_error_code
+krb5_db2_iter_policy(krb5_context kcontext,
+ char *match_entry,
+ osa_adb_iter_policy_func func, void *data)
+{
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *dbc;
+
+ dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+
+ return osa_adb_iter_policy(dbc->policy_db, func, data);
+}
+
+krb5_error_code
+krb5_db2_delete_policy(krb5_context kcontext, char *policy)
+{
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *dbc;
+
+ dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+ dbc = (krb5_db2_context *) dal_handle->db_context;
+
+ return osa_adb_destroy_policy(dbc->policy_db, policy);
+}
+
+void
+krb5_db2_free_policy(krb5_context kcontext, osa_policy_ent_t entry)
+{
+ osa_free_policy_ent(entry);
+}