summaryrefslogtreecommitdiffstats
path: root/src/lib/kdb/kdb_db2
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2005-06-21 01:36:03 +0000
committerKen Raeburn <raeburn@mit.edu>2005-06-21 01:36:03 +0000
commitf72c3ffaca4600d4e75282857ce4dda11106d5e7 (patch)
tree89df6e717f00e1687994fc089fd6df9ff8a5c21c /src/lib/kdb/kdb_db2
parentf4aaa29ac68e3dd5a2ae326cd54918c7250558e9 (diff)
downloadkrb5-f72c3ffaca4600d4e75282857ce4dda11106d5e7.tar.gz
krb5-f72c3ffaca4600d4e75282857ce4dda11106d5e7.tar.xz
krb5-f72c3ffaca4600d4e75282857ce4dda11106d5e7.zip
Novell Database Abstraction Layer merge.
Will probably break things. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17258 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/kdb/kdb_db2')
-rw-r--r--src/lib/kdb/kdb_db2/ChangeLog17
-rw-r--r--src/lib/kdb/kdb_db2/Makefile.in150
-rw-r--r--src/lib/kdb/kdb_db2/adb_openclose.c412
-rw-r--r--src/lib/kdb/kdb_db2/adb_policy.c389
-rw-r--r--src/lib/kdb/kdb_db2/configure.in22
-rw-r--r--src/lib/kdb/kdb_db2/db2_exp.c64
-rw-r--r--src/lib/kdb/kdb_db2/kdb_compat.h81
-rw-r--r--src/lib/kdb/kdb_db2/kdb_db2.c2000
-rw-r--r--src/lib/kdb/kdb_db2/kdb_db2.h216
-rw-r--r--src/lib/kdb/kdb_db2/kdb_xdr.c816
-rw-r--r--src/lib/kdb/kdb_db2/kdb_xdr.h32
-rw-r--r--src/lib/kdb/kdb_db2/libkdb_db2.exports1
-rw-r--r--src/lib/kdb/kdb_db2/pol_xdr.c88
-rw-r--r--src/lib/kdb/kdb_db2/policy_db.h87
14 files changed, 4375 insertions, 0 deletions
diff --git a/src/lib/kdb/kdb_db2/ChangeLog b/src/lib/kdb/kdb_db2/ChangeLog
new file mode 100644
index 000000000..6ebc2a0e8
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/ChangeLog
@@ -0,0 +1,17 @@
+2005-06-20 Ken Raeburn <raeburn@mit.edu>
+
+ Novell merge.
+ * Makefile.in:
+ * adb_openclose.c:
+ * adb_policy.c:
+ * configure.in:
+ * db2_exp.c:
+ * kdb_compat.h:
+ * kdb_db2.c:
+ * kdb_db2.h:
+ * kdb_xdr.c:
+ * kdb_xdr.h:
+ * libkdb_db2.exports:
+ * pol_xdr.c:
+ * policy_db.h:
+
diff --git a/src/lib/kdb/kdb_db2/Makefile.in b/src/lib/kdb/kdb_db2/Makefile.in
new file mode 100644
index 000000000..ebd39f0c7
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/Makefile.in
@@ -0,0 +1,150 @@
+thisconfigdir=.
+myfulldir=lib/kdb/kdb_db2
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LOCALINCLUDES = -I..
+
+LIBBASE=kdb_db2
+LIB=$(LIBBASE)
+LIBMAJOR=4
+LIBMINOR=0
+RELDIR=kdb/kdb_db2
+SO_EXT=.so
+# Depends on libk5crypto and libkrb5
+
+SHLIB_EXPDEPS = \
+ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+ $(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto $(KDB5_DB_LIB) $(LIBS)
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+DBDIR = $(BUILDTOP)/util/db2
+DBOBJLISTS = $(DBOBJLISTS-@DB_VERSION@)
+DBOBJLISTS-sys =
+DBOBJLISTS-k5 = $(DBDIR)/hash/OBJS.ST $(DBDIR)/btree/OBJS.ST \
+ $(DBDIR)/db/OBJS.ST $(DBDIR)/mpool/OBJS.ST $(DBDIR)/recno/OBJS.ST \
+ $(DBDIR)/clib/OBJS.ST
+
+all:: lib$(LIB)$(SO_EXT)
+
+SRCS= \
+ $(srcdir)/kdb_xdr.c \
+ $(srcdir)/adb_openclose.c \
+ $(srcdir)/adb_policy.c \
+ $(srcdir)/kdb_db2.c \
+ $(srcdir)/pol_xdr.c \
+ $(srcdir)/db2_exp.c
+
+STOBJLISTS=OBJS.ST $(DBOBJLISTS)
+STLIBOBJS= \
+ kdb_xdr.o \
+ adb_openclose.o \
+ adb_policy.o \
+ kdb_db2.o \
+ pol_xdr.o \
+ db2_exp.o
+
+all-unix:: all-liblinks
+install-unix:: install-libs
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+lib$(LIB)$(SO_EXT): db2_exp.o # lib$(LIB)$(STLIBEXT)
+ $(CC) -shared -o $@ -L$(TOPLIBD) $^ -lgssrpc -ldb $(SHLIB_EXPLIBS)
+
+clean::
+ $(RM) lib$(LIB)$(SO_EXT) db2_exp.o
+
+
+t_kdb: t_kdb.o $(OBJS) $(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o t_kdb t_kdb.o $(OBJS) $(KDB5_LIBS) $(KRB5_BASE_LIBS)
+
+check:: t_kdb
+ $(RM) test_db
+ $(KRB5_CONFIG_SETUP) $(KRB5_RUN_ENV) ./t_kdb -tcv
+ $(KRB5_CONFIG_SETUP) $(KRB5_RUN_ENV) ./t_kdb -tcvr
+
+clean::
+ $(RM) t_kdb t_kdb.o
+
+
+adb_openclose.c adb_policy.c : ../adb_err.h
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(OBJEXT): kdb_xdr.c \
+ $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-thread.h \
+ $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+ $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+ kdb_xdr.h
+adb_openclose.so adb_openclose.po $(OUTPRE)adb_openclose.$(OBJEXT): \
+ adb_openclose.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-thread.h \
+ $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+ $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+ policy_db.h $(SRCTOP)/include/krb5/kdb.h $(DB_DEPS) \
+ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+ $(BUILDTOP)/include/gssrpc/xdr.h ../adb_err.h
+adb_policy.so adb_policy.po $(OUTPRE)adb_policy.$(OBJEXT): \
+ adb_policy.c policy_db.h $(SRCTOP)/include/k5-int.h \
+ $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/k5-platform.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+ $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+ $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/krb5/kdb.h \
+ $(DB_DEPS) $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+ $(BUILDTOP)/include/gssrpc/xdr.h ../adb_err.h
+kdb_db2.so kdb_db2.po $(OUTPRE)kdb_db2.$(OBJEXT): kdb_db2.c \
+ $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-thread.h \
+ $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+ $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+ $(DB_DEPS) $(srcdir)/../kdb5.h $(SRCTOP)/include/k5-int.h \
+ $(srcdir)/../err_handle.h kdb_db2.h policy_db.h $(SRCTOP)/include/krb5/kdb.h \
+ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+ $(BUILDTOP)/include/gssrpc/xdr.h ../adb_err.h kdb_xdr.h \
+ kdb_compat.h
+pol_xdr.so pol_xdr.po $(OUTPRE)pol_xdr.$(OBJEXT): pol_xdr.c \
+ $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/gssrpc/rpc.h \
+ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+ $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+ $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+ $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+ $(BUILDTOP)/include/gssrpc/svc.h $(SRCTOP)/include/krb5/kdb.h \
+ policy_db.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-thread.h \
+ $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+ $(SRCTOP)/include/krb5/kdb.h $(DB_DEPS) ../adb_err.h
+db2_exp.so db2_exp.po $(OUTPRE)db2_exp.$(OBJEXT): db2_exp.c \
+ $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-thread.h \
+ $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+ $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+ $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+ $(DB_DEPS) $(srcdir)/../kdb5.h $(SRCTOP)/include/k5-int.h \
+ $(srcdir)/../err_handle.h kdb_db2.h policy_db.h $(SRCTOP)/include/krb5/kdb.h \
+ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+ $(BUILDTOP)/include/gssrpc/xdr.h ../adb_err.h kdb_xdr.h
diff --git a/src/lib/kdb/kdb_db2/adb_openclose.c b/src/lib/kdb/kdb_db2/adb_openclose.c
new file mode 100644
index 000000000..97ce1123b
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/adb_openclose.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/file.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <k5-int.h>
+#include "policy_db.h"
+#include <stdlib.h>
+#include <db.h>
+
+#define MAX_LOCK_TRIES 5
+
+struct _locklist {
+ osa_adb_lock_ent lockinfo;
+ struct _locklist *next;
+};
+
+krb5_error_code osa_adb_create_db(char *filename, char *lockfilename,
+ int magic)
+{
+ int lf;
+ DB *db;
+ BTREEINFO btinfo;
+
+ memset(&btinfo, 0, sizeof(btinfo));
+ btinfo.flags = 0;
+ btinfo.cachesize = 0;
+ btinfo.psize = 4096;
+ btinfo.lorder = 0;
+ btinfo.minkeypage = 0;
+ btinfo.compare = NULL;
+ btinfo.prefix = NULL;
+ db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
+ if (db == NULL)
+ return errno;
+ if (db->close(db) < 0)
+ return errno;
+
+ /* only create the lock file if we successfully created the db */
+ lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
+ if (lf == -1)
+ return errno;
+ (void) close(lf);
+
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_destroy_db(char *filename, char *lockfilename,
+ int magic)
+{
+ /* the admin databases do not contain security-critical data */
+ if (unlink(filename) < 0 ||
+ unlink(lockfilename) < 0)
+ return errno;
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom,
+ char *fileto, char *lockto, int magic)
+{
+ osa_adb_db_t fromdb, todb;
+ krb5_error_code ret;
+
+ /* make sure todb exists */
+ if ((ret = osa_adb_create_db(fileto, lockto, magic)) &&
+ ret != EEXIST)
+ return ret;
+
+ if ((ret = osa_adb_init_db(&fromdb, filefrom, lockfrom, magic)))
+ return ret;
+ if ((ret = osa_adb_init_db(&todb, fileto, lockto, magic))) {
+ (void) osa_adb_fini_db(fromdb, magic);
+ return ret;
+ }
+ if ((ret = osa_adb_get_lock(fromdb, KRB5_DB_LOCKMODE_PERMANENT))) {
+ (void) osa_adb_fini_db(fromdb, magic);
+ (void) osa_adb_fini_db(todb, magic);
+ return ret;
+ }
+ if ((ret = osa_adb_get_lock(todb, KRB5_DB_LOCKMODE_PERMANENT))) {
+ (void) osa_adb_fini_db(fromdb, magic);
+ (void) osa_adb_fini_db(todb, magic);
+ return ret;
+ }
+ if ((rename(filefrom, fileto) < 0)) {
+ (void) osa_adb_fini_db(fromdb, magic);
+ (void) osa_adb_fini_db(todb, magic);
+ return errno;
+ }
+ /*
+ * Do not release the lock on fromdb because it is being renamed
+ * out of existence; no one can ever use it again.
+ */
+ if ((ret = osa_adb_release_lock(todb))) {
+ (void) osa_adb_fini_db(fromdb, magic);
+ (void) osa_adb_fini_db(todb, magic);
+ return ret;
+ }
+
+ (void) osa_adb_fini_db(fromdb, magic);
+ (void) osa_adb_fini_db(todb, magic);
+ return 0;
+}
+
+krb5_error_code osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
+ char *lockfilename, int magic)
+{
+ osa_adb_db_t db;
+ static struct _locklist *locklist = NULL;
+ struct _locklist *lockp;
+ krb5_error_code code;
+
+ if (dbp == NULL || filename == NULL)
+ return EINVAL;
+
+ db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
+ if (db == NULL)
+ return ENOMEM;
+
+ memset(db, 0, sizeof(*db));
+ db->info.hash = NULL;
+ db->info.bsize = 256;
+ db->info.ffactor = 8;
+ db->info.nelem = 25000;
+ db->info.lorder = 0;
+
+ db->btinfo.flags = 0;
+ db->btinfo.cachesize = 0;
+ db->btinfo.psize = 4096;
+ db->btinfo.lorder = 0;
+ db->btinfo.minkeypage = 0;
+ db->btinfo.compare = NULL;
+ db->btinfo.prefix = NULL;
+ /*
+ * A process is allowed to open the same database multiple times
+ * and access it via different handles. If the handles use
+ * distinct lockinfo structures, things get confused: lock(A),
+ * lock(B), release(B) will result in the kernel unlocking the
+ * lock file but handle A will still think the file is locked.
+ * Therefore, all handles using the same lock file must share a
+ * single lockinfo structure.
+ *
+ * It is not sufficient to have a single lockinfo structure,
+ * however, because a single process may also wish to open
+ * multiple different databases simultaneously, with different
+ * lock files. This code used to use a single static lockinfo
+ * structure, which means that the second database opened used
+ * the first database's lock file. This was Bad.
+ *
+ * We now maintain a linked list of lockinfo structures, keyed by
+ * lockfilename. An entry is added when this function is called
+ * with a new lockfilename, and all subsequent calls with that
+ * lockfilename use the existing entry, updating the refcnt.
+ * When the database is closed with fini_db(), the refcnt is
+ * decremented, and when it is zero the lockinfo structure is
+ * freed and reset. The entry in the linked list, however, is
+ * never removed; it will just be reinitialized the next time
+ * init_db is called with the right lockfilename.
+ */
+
+ /* find or create the lockinfo structure for lockfilename */
+ lockp = locklist;
+ while (lockp) {
+ if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
+ break;
+ else
+ lockp = lockp->next;
+ }
+ if (lockp == NULL) {
+ /* doesn't exist, create it, add to list */
+ lockp = (struct _locklist *) malloc(sizeof(*lockp));
+ if (lockp == NULL) {
+ free(db);
+ return ENOMEM;
+ }
+ memset(lockp, 0, sizeof(*lockp));
+ lockp->next = locklist;
+ locklist = lockp;
+ }
+
+ /* now initialize lockp->lockinfo if necessary */
+ if (lockp->lockinfo.lockfile == NULL) {
+ if ((code = krb5_init_context(&lockp->lockinfo.context))) {
+ free(db);
+ return((krb5_error_code) code);
+ }
+
+ /*
+ * needs be open read/write so that write locking can work with
+ * POSIX systems
+ */
+ lockp->lockinfo.filename = strdup(lockfilename);
+ if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
+ /*
+ * maybe someone took away write permission so we could only
+ * get shared locks?
+ */
+ if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r"))
+ == NULL) {
+ free(db);
+ return OSA_ADB_NOLOCKFILE;
+ }
+ }
+ lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
+ }
+
+ /* lockp is set, lockinfo is initialized, update the reference count */
+ db->lock = &lockp->lockinfo;
+ db->lock->refcnt++;
+
+ db->opencnt = 0;
+ db->filename = strdup(filename);
+ db->magic = magic;
+
+ *dbp = db;
+
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_fini_db(osa_adb_db_t db, int magic)
+{
+ if (db->magic != magic)
+ return EINVAL;
+ if (db->lock->refcnt == 0) {
+ /* barry says this can't happen */
+ return OSA_ADB_FAILURE;
+ } else {
+ db->lock->refcnt--;
+ }
+
+ if (db->lock->refcnt == 0) {
+ /*
+ * Don't free db->lock->filename, it is used as a key to
+ * find the lockinfo entry in the linked list. If the
+ * lockfile doesn't exist, we must be closing the database
+ * after trashing it. This has to be allowed, so don't
+ * generate an error.
+ */
+ if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
+ (void) fclose(db->lock->lockfile);
+ db->lock->lockfile = NULL;
+ krb5_free_context(db->lock->context);
+ }
+
+ db->magic = 0;
+ free(db->filename);
+ free(db);
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_get_lock(osa_adb_db_t db, int mode)
+{
+ int tries, gotlock, perm, krb5_mode, ret = 0;
+
+ if (db->lock->lockmode >= mode) {
+ /* No need to upgrade lock, just incr refcnt and return */
+ db->lock->lockcnt++;
+ return(OSA_ADB_OK);
+ }
+
+ perm = 0;
+ switch (mode) {
+ case KRB5_DB_LOCKMODE_PERMANENT:
+ perm = 1;
+ case KRB5_DB_LOCKMODE_EXCLUSIVE:
+ krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
+ break;
+ case KRB5_DB_LOCKMODE_SHARED:
+ krb5_mode = KRB5_LOCKMODE_SHARED;
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
+ if ((ret = krb5_lock_file(db->lock->context,
+ fileno(db->lock->lockfile),
+ krb5_mode|KRB5_LOCKMODE_DONTBLOCK)) == 0) {
+ gotlock++;
+ break;
+ } else if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
+ /* tried to exclusive-lock something we don't have */
+ /* write access to */
+ return OSA_ADB_NOEXCL_PERM;
+
+ sleep(1);
+ }
+
+ /* test for all the likely "can't get lock" error codes */
+ if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
+ return OSA_ADB_CANTLOCK_DB;
+ else if (ret != 0)
+ return ret;
+
+ /*
+ * If the file no longer exists, someone acquired a permanent
+ * lock. If that process terminates its exclusive lock is lost,
+ * but if we already had the file open we can (probably) lock it
+ * even though it has been unlinked. So we need to insist that
+ * it exist.
+ */
+ if (access(db->lock->filename, F_OK) < 0) {
+ (void) krb5_lock_file(db->lock->context,
+ fileno(db->lock->lockfile),
+ KRB5_LOCKMODE_UNLOCK);
+ return OSA_ADB_NOLOCKFILE;
+ }
+
+ /* we have the shared/exclusive lock */
+
+ if (perm) {
+ if (unlink(db->lock->filename) < 0) {
+ /* somehow we can't delete the file, but we already */
+ /* have the lock, so release it and return */
+
+ ret = errno;
+ (void) krb5_lock_file(db->lock->context,
+ fileno(db->lock->lockfile),
+ KRB5_LOCKMODE_UNLOCK);
+
+ /* maybe we should return CANTLOCK_DB.. but that would */
+ /* look just like the db was already locked */
+ return ret;
+ }
+
+ /* this releases our exclusive lock.. which is okay because */
+ /* now no one else can get one either */
+ (void) fclose(db->lock->lockfile);
+ }
+
+ db->lock->lockmode = mode;
+ db->lock->lockcnt++;
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_release_lock(osa_adb_db_t db)
+{
+ int ret, fd;
+
+ if (!db->lock->lockcnt) /* lock already unlocked */
+ return OSA_ADB_NOTLOCKED;
+
+ if (--db->lock->lockcnt == 0) {
+ if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
+ /* now we need to create the file since it does not exist */
+ fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
+ 0600);
+ if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL)
+ return OSA_ADB_NOLOCKFILE;
+ } else if ((ret = krb5_lock_file(db->lock->context,
+ fileno(db->lock->lockfile),
+ KRB5_LOCKMODE_UNLOCK)))
+ return ret;
+
+ db->lock->lockmode = 0;
+ }
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
+{
+ int ret;
+
+ ret = osa_adb_get_lock(db, locktype);
+ if (ret != OSA_ADB_OK)
+ return ret;
+ if (db->opencnt)
+ goto open_ok;
+
+ db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
+ if (db->db != NULL)
+ goto open_ok;
+ switch (errno) {
+#ifdef EFTYPE
+ case EFTYPE:
+#endif
+ case EINVAL:
+ db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
+ if (db->db != NULL)
+ goto open_ok;
+ default:
+ (void) osa_adb_release_lock(db);
+ if (errno == EINVAL)
+ return OSA_ADB_BAD_DB;
+ return errno;
+ }
+open_ok:
+ db->opencnt++;
+ return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db)
+{
+ if (--db->opencnt)
+ return osa_adb_release_lock(db);
+ if(db->db != NULL && db->db->close(db->db) == -1) {
+ (void) osa_adb_release_lock(db);
+ return OSA_ADB_FAILURE;
+ }
+
+ db->db = NULL;
+
+ return(osa_adb_release_lock(db));
+}
diff --git a/src/lib/kdb/kdb_db2/adb_policy.c b/src/lib/kdb/kdb_db2/adb_policy.c
new file mode 100644
index 000000000..e338cbbd0
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/adb_policy.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/file.h>
+#include <fcntl.h>
+#include "policy_db.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define OPENLOCK(db, mode) \
+{ \
+ int olret; \
+ if (db == NULL) \
+ return EINVAL; \
+ else if (db->magic != OSA_ADB_POLICY_DB_MAGIC) \
+ return OSA_ADB_DBINIT; \
+ else if ((olret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \
+ return olret; \
+ }
+
+#define CLOSELOCK(db) \
+{ \
+ int cl_ret; \
+ if ((cl_ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \
+ return cl_ret; \
+}
+
+
+/*
+ * Function: osa_adb_create_policy
+ *
+ * Purpose: create a policy entry in the policy db.
+ *
+ * Arguments:
+ * entry (input) pointer to the entry to be added
+ * <return value> OSA_ADB_OK on success, else error code.
+ *
+ * Requires:
+ * entry have a valid name.
+ *
+ * Effects:
+ * creates the entry in the db
+ *
+ * Modifies:
+ * the policy db.
+ *
+ */
+krb5_error_code
+osa_adb_create_policy(osa_adb_policy_t db, osa_policy_ent_t entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret;
+
+ OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+
+ if(entry->name == NULL) {
+ ret = EINVAL;
+ goto error;
+ }
+ dbkey.data = entry->name;
+ dbkey.size = (strlen(entry->name) + 1);
+
+ switch(db->db->get(db->db, &dbkey, &dbdata, 0)) {
+ case 0:
+ ret = OSA_ADB_DUP;
+ goto error;
+ case 1:
+ break;
+ default:
+ ret = errno;
+ goto error;
+ }
+ xdralloc_create(&xdrs, XDR_ENCODE);
+ if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+ xdr_destroy(&xdrs);
+ ret = OSA_ADB_XDR_FAILURE;
+ goto error;
+ }
+ dbdata.data = xdralloc_getdata(&xdrs);
+ dbdata.size = xdr_getpos(&xdrs);
+ switch(db->db->put(db->db, &dbkey, &dbdata, R_NOOVERWRITE)) {
+ case 0:
+ if((db->db->sync(db->db, 0)) == -1)
+ ret = OSA_ADB_FAILURE;
+ ret = OSA_ADB_OK;
+ break;
+ case 1:
+ ret = OSA_ADB_DUP;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ xdr_destroy(&xdrs);
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+/*
+ * Function: osa_adb_destroy_policy
+ *
+ * Purpose: destroy a policy entry
+ *
+ * Arguments:
+ * db (input) database handle
+ * name (input) name of policy
+ * <return value> OSA_ADB_OK on success, or error code.
+ *
+ * Requires:
+ * db being valid.
+ * name being non-null.
+ * Effects:
+ * deletes policy from db.
+ *
+ * Modifies:
+ * policy db.
+ *
+ */
+krb5_error_code
+osa_adb_destroy_policy(osa_adb_policy_t db, char *name)
+{
+ DBT dbkey;
+ int status, ret;
+
+ OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+
+ if(name == NULL) {
+ ret = EINVAL;
+ goto error;
+ }
+ dbkey.data = name;
+ dbkey.size = (strlen(name) + 1);
+
+ status = db->db->del(db->db, &dbkey, 0);
+ switch(status) {
+ case 1:
+ ret = OSA_ADB_NOENT;
+ goto error;
+ case 0:
+ if ((db->db->sync(db->db, 0)) == -1) {
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ ret = OSA_ADB_OK;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+/*
+ * Function: osa_adb_get_policy
+ *
+ * Purpose: retrieve policy
+ *
+ * Arguments:
+ * db (input) db handle
+ * name (input) name of policy
+ * entry (output) policy entry
+ * cnt (inout) Number of entries
+ * <return value> 0 on success, error code on failure.
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+krb5_error_code
+osa_adb_get_policy(osa_adb_policy_t db, char *name,
+ osa_policy_ent_t *entry, int *cnt)
+{
+ DBT dbkey;
+ DBT dbdata;
+ XDR xdrs;
+ int ret;
+ char *aligned_data;
+
+ OPENLOCK(db, KRB5_DB_LOCKMODE_SHARED);
+
+ *cnt = 1;
+
+ if(name == NULL) {
+ ret = EINVAL;
+ goto error;
+ }
+ dbkey.data = name;
+ dbkey.size = (strlen(dbkey.data) + 1);
+ dbdata.data = NULL;
+ dbdata.size = 0;
+ switch((db->db->get(db->db, &dbkey, &dbdata, 0))) {
+ case 1:
+ ret = 0;
+ *cnt = 0;
+ goto error;
+ case 0:
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ if (!(*(entry) = (osa_policy_ent_t)malloc(sizeof(osa_policy_ent_rec)))) {
+ ret = ENOMEM;
+ goto error;
+ }
+ if (!(aligned_data = (char *) malloc(dbdata.size))) {
+ ret = ENOMEM;
+ goto error;
+ }
+ memcpy(aligned_data, dbdata.data, dbdata.size);
+ memset(*entry, 0, sizeof(osa_policy_ent_rec));
+ xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+ if (!xdr_osa_policy_ent_rec(&xdrs, *entry))
+ ret = OSA_ADB_FAILURE;
+ else ret = OSA_ADB_OK;
+ xdr_destroy(&xdrs);
+ free(aligned_data);
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+/*
+ * Function: osa_adb_put_policy
+ *
+ * Purpose: update a policy in the dababase
+ *
+ * Arguments:
+ * db (input) db handle
+ * entry (input) policy entry
+ * <return value> 0 on success error code on failure.
+ *
+ * Requires:
+ * [requires]
+ *
+ * Effects:
+ * [effects]
+ *
+ * Modifies:
+ * [modifies]
+ *
+ */
+krb5_error_code
+osa_adb_put_policy(osa_adb_policy_t db, osa_policy_ent_t entry)
+{
+ DBT dbkey;
+ DBT dbdata;
+ DBT tmpdb;
+ XDR xdrs;
+ int ret;
+
+ OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+
+ if(entry->name == NULL) {
+ ret = EINVAL;
+ goto error;
+ }
+ dbkey.data = entry->name;
+ dbkey.size = (strlen(entry->name) + 1);
+ switch(db->db->get(db->db, &dbkey, &tmpdb, 0)) {
+ case 0:
+ break;
+ case 1:
+ ret = OSA_ADB_NOENT;
+ goto error;
+ default:
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ xdralloc_create(&xdrs, XDR_ENCODE);
+ if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+ xdr_destroy(&xdrs);
+ ret = OSA_ADB_XDR_FAILURE;
+ goto error;
+ }
+ dbdata.data = xdralloc_getdata(&xdrs);
+ dbdata.size = xdr_getpos(&xdrs);
+ switch(db->db->put(db->db, &dbkey, &dbdata, 0)) {
+ case 0:
+ if((db->db->sync(db->db, 0)) == -1)
+ ret = OSA_ADB_FAILURE;
+ ret = OSA_ADB_OK;
+ break;
+ default:
+ ret = OSA_ADB_FAILURE;
+ break;
+ }
+ xdr_destroy(&xdrs);
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+/*
+ * Function: osa_adb_iter_policy
+ *
+ * Purpose: iterate over the policy database.
+ *
+ * Arguments:
+ * db (input) db handle
+ * func (input) fucntion pointer to call
+ * data opaque data type
+ * <return value> 0 on success error code on failure
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+krb5_error_code
+osa_adb_iter_policy(osa_adb_policy_t db, osa_adb_iter_policy_func func,
+ void *data)
+{
+ DBT dbkey,
+ dbdata;
+ XDR xdrs;
+ int ret;
+ osa_policy_ent_t entry;
+ char *aligned_data;
+
+ OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE); /* hmmm */
+
+ if((ret = db->db->seq(db->db, &dbkey, &dbdata, R_FIRST)) == -1) {
+ ret = errno;
+ goto error;
+ }
+
+ while (ret == 0) {
+ if (!(entry = (osa_policy_ent_t) malloc(sizeof(osa_policy_ent_rec)))) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ if(!(aligned_data = (char *) malloc(dbdata.size))) {
+ ret = ENOMEM;
+ goto error;
+ }
+ memcpy(aligned_data, dbdata.data, dbdata.size);
+
+ memset(entry, 0, sizeof(osa_policy_ent_rec));
+ xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+ if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+ xdr_destroy(&xdrs);
+ free(aligned_data);
+ ret = OSA_ADB_FAILURE;
+ goto error;
+ }
+ (*func)(data, entry);
+ xdr_destroy(&xdrs);
+ free(aligned_data);
+ osa_free_policy_ent(entry);
+ ret = db->db->seq(db->db, &dbkey, &dbdata, R_NEXT);
+ }
+ if(ret == -1)
+ ret = errno;
+ else ret = OSA_ADB_OK;
+
+error:
+ CLOSELOCK(db);
+ return ret;
+}
+
+void
+osa_free_policy_ent(osa_policy_ent_t val)
+{
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
+
+ xdr_osa_policy_ent_rec(&xdrs, val);
+
+ free(val);
+}
diff --git a/src/lib/kdb/kdb_db2/configure.in b/src/lib/kdb/kdb_db2/configure.in
new file mode 100644
index 000000000..dc002d878
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/configure.in
@@ -0,0 +1,22 @@
+AC_INIT(configure.in)
+CONFIG_RULES
+AC_CHECK_HEADERS(unistd.h)
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+
+AC_CHECK_FUNCS(srand48 srand srandom umask)
+
+dnl AIX is unusual in that it wants all symbols resolved at link time
+dnl Fortunately, it will allow us to link the kdb library now, even if
+dnl it is linked again later.
+case $krb5_cv_host in
+*-*-aix*)
+ LIBS="$LIBS -ldb"
+ ;;
+esac
+KRB5_RUN_FLAGS
+dnl The following is for check...
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/lib/kdb/kdb_db2/db2_exp.c b/src/lib/kdb/kdb_db2/db2_exp.c
new file mode 100644
index 000000000..f511487f1
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/db2_exp.c
@@ -0,0 +1,64 @@
+/**********************************************************************
+*
+* C %name: db2_exp.c %
+* Instance: idc_sec_2
+* Description:
+* %created_by: spradeep %
+* %date_created: Tue Apr 5 11:44:00 2005 %
+*
+**********************************************************************/
+#ifndef lint
+static char *_csrc = "@(#) %filespec: db2_exp.c~5 % (%full_filespec: db2_exp.c~5:csrc:idc_sec#2 %)";
+#endif
+
+#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"
+
+/*
+ * Exposed API
+ */
+
+kdb_vftabl krb5_db_vftabl_kdb_db2 = {
+ 1, /* major version number 1 */
+ 0, /* minor version number 0 */
+ 0, /* TBD. Not sure whether thread safe. For now, its not */
+ /* init_library */ krb5_db2_lib_init,
+ /* fini_library */ krb5_db2_lib_cleanup,
+ /* init_module */ krb5_db2_open,
+ /* fini_module */ krb5_db2_db_fini,
+ /* db_create */ krb5_db2_create,
+ /* db_destroy */ krb5_db2_destroy,
+ /* db_get_age */ krb5_db2_db_get_age,
+ /* db_set_option */ krb5_db2_db_set_option,
+ /* db_lock */ krb5_db2_db_lock,
+ /* db_unlock */ krb5_db2_db_unlock,
+ /* db_get_principal */ krb5_db2_db_get_principal,
+ /* db_free_principal */ krb5_db2_db_free_principal,
+ /* db_put_principal */ krb5_db2_db_put_principal,
+ /* db_delete_principal */ krb5_db2_db_delete_principal,
+ /* db_iterate */ krb5_db2_db_iterate,
+ /* db_create_policy */ krb5_db2_create_policy,
+ /* db_get_policy */ krb5_db2_get_policy,
+ /* db_put_policy */ krb5_db2_put_policy,
+ /* db_iter_policy */ krb5_db2_iter_policy,
+ /* db_delete_policy */ krb5_db2_delete_policy,
+ /* db_free_policy */ krb5_db2_free_policy,
+ /* db_supported_realms */ NULL,
+ /* db_free_supported_realms */ NULL,
+ /* errcode_2_string */ NULL,
+ /* db_alloc */ krb5_db2_alloc,
+ /* db_free */ krb5_db2_free,
+ /* set_master_key */ krb5_db2_set_master_key_ext,
+ /* get_master_key */ krb5_db2_db_get_mkey
+};
diff --git a/src/lib/kdb/kdb_db2/kdb_compat.h b/src/lib/kdb/kdb_db2/kdb_compat.h
new file mode 100644
index 000000000..540d4a249
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/kdb_compat.h
@@ -0,0 +1,81 @@
+/*
+ * lib/kdb/kdb_compat.h
+ *
+ * Copyright 1994 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.
+ *
+ *
+ * KDC Database interface definitions.
+ */
+
+
+typedef struct _old_krb5_encrypted_keyblock {
+ krb5_enctype enctype;
+ int length;
+ krb5_octet *contents;
+} old_krb5_encrypted_keyblock;
+
+typedef struct old_krb5_principal_data {
+ krb5_magic magic;
+ krb5_data realm;
+ krb5_data *data; /* An array of strings */
+ krb5_int32 length;
+ krb5_int32 type;
+} old_krb5_principal_data;
+
+typedef old_krb5_principal_data *old_krb5_principal;
+
+
+/*
+ * Note --- this structure cannot be modified without changing the
+ * database version number in libkdb.a
+ */
+typedef struct _old_krb5_db_entry {
+ old_krb5_principal principal;
+ old_krb5_encrypted_keyblock key;
+ krb5_kvno kvno;
+ krb5_deltat max_life;
+ krb5_deltat max_renewable_life;
+ krb5_kvno mkvno; /* master encryption key vno */
+
+ krb5_timestamp expiration; /* This is when the client expires */
+ krb5_timestamp pw_expiration; /* This is when its password does */
+ krb5_timestamp last_pwd_change; /* Last time of password change */
+ krb5_timestamp last_success; /* Last successful password */
+
+ krb5_timestamp last_failed; /* Last failed password attempt */
+ krb5_kvno fail_auth_count; /* # of failed password attempts */
+
+ old_krb5_principal mod_name;
+ krb5_timestamp mod_date;
+ krb5_flags attributes;
+ krb5_int32 salt_type:8,
+ salt_length:24;
+ krb5_octet *salt;
+ old_krb5_encrypted_keyblock alt_key;
+ krb5_int32 alt_salt_type:8,
+ alt_salt_length:24;
+ krb5_octet *alt_salt;
+
+ krb5_int32 expansion[8];
+} old_krb5_db_entry;
+
diff --git a/src/lib/kdb/kdb_db2/kdb_db2.c b/src/lib/kdb/kdb_db2/kdb_db2.c
new file mode 100644
index 000000000..2ac462e89
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/kdb_db2.c
@@ -0,0 +1,2000 @@
+/*
+ * 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(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;
+ 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(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 = 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(context, 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(context)
+ 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(context)
+ 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;
+}
+
+#if 0 // pradx
+
+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;
+}
+
+#endif // 0 -pradx
+
+/*
+ * Set/Get the master key associated with the database
+ */
+krb5_error_code
+krb5_db2_db_set_mkey(context, key)
+ 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(context, key)
+ 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(context, 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(context, db_name, 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(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;
+ 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);
+}
+
+krb5_error_code
+krb5_db2_db_lock(context, in_mode)
+ 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 = in_mode & ~KRB5_DB_LOCKMODE_PERMANENT; /* permanent is not available for principal db */
+
+ 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;
+
+ 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++;
+
+ 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(context)
+ 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(context, db_name, flags)
+ 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(dbname, 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(context, dbname)
+ 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;
+}
+
+#if 0 // -pradx
+
+/*
+ * "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;
+ kdb5_dal_handle *dal_handle;
+ krb5_db2_context *s_context, *db_ctx;
+
+ dal_handle = (kdb5_dal_handle*) context->db_context;
+ s_context = dal_handle->db_context;
+ dal_handle->db_context = NULL;
+ if ((retval = k5db2_init_context(context)))
+ return retval;
+ db_ctx = (krb5_db2_context *) ((kdb5_dal_handle*)context->db_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 ( ((kdb5_dal_handle*)context->db_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 *) ((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 = s_context;
+ (void) krb5_db2_db_unlock(context); /* unlock saved context db */
+
+ return retval;
+}
+
+#endif // 0 - pradx
+
+/*
+ * 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_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 try, 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 (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.
+ */
+krb5_error_code
+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 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(context, entries, nentries, db_args)
+ krb5_context context;
+ krb5_db_entry *entries;
+ register 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(context, searchfor, nentries)
+ 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(context, func, func_arg, backwards, recursive)
+ krb5_context context;
+ krb5_error_code (*func) (krb5_pointer, krb5_db_entry *);
+ krb5_pointer func_arg;
+ int backwards, 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(context, mode)
+ 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;
+}
+
+#if 0 // -pradx
+/*
+ * 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);
+ if (dbctx->db_inited && dbctx->db_name)
+ required += strlen(dbctx->db_name);
+ 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;
+ krb5_boolean nb_lock;
+ 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_db2_db_lock(tmpctx, lockmode);
+ if (!kret && lockmode)
+ dbctx->db_locks_held = lockcount;
+ nb_lock = nb_lockmode & 0xff;
+ (void) krb5_db2_db_set_lockmode(tmpctx, nb_lock);
+ }
+ 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));
+}
+
+#endif // 0 - pradx
+
+/*
+ * 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, 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 )
+ {
+ 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);
+}
+
diff --git a/src/lib/kdb/kdb_db2/kdb_db2.h b/src/lib/kdb/kdb_db2/kdb_db2.h
new file mode 100644
index 000000000..ba03ea36f
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/kdb_db2.h
@@ -0,0 +1,216 @@
+/*
+ * 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. 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.
+ *
+ *
+ * KDC Database backend definitions for Berkely DB.
+ */
+#ifndef KRB5_KDB_DB2_H
+#define KRB5_KDB_DB2_H
+
+#include "policy_db.h"
+
+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_keyblock *db_master_key; /* Master key of database */
+ osa_adb_policy_t policy_db;
+} krb5_db2_context;
+
+#define KRB5_DB2_MAX_RETRY 5
+
+#define KDB2_LOCK_EXT ".ok"
+
+krb5_error_code krb5_db2_db_set_name
+ (krb5_context,
+ char * );
+krb5_error_code krb5_db2_db_init
+ (krb5_context);
+krb5_error_code krb5_db2_db_fini
+ (krb5_context);
+krb5_error_code krb5_db2_db_get_age
+ (krb5_context,
+ char *,
+ time_t * );
+krb5_error_code krb5_db2_db_create
+ (krb5_context,
+ char *,
+ krb5_int32);
+krb5_error_code krb5_db2_db_destroy
+ (krb5_context,
+ char * );
+krb5_error_code krb5_db2_db_rename
+ (krb5_context,
+ char *,
+ char * );
+krb5_error_code krb5_db2_db_get_principal
+ (krb5_context,
+ krb5_const_principal,
+ krb5_db_entry *,
+ int *,
+ krb5_boolean * );
+krb5_error_code krb5_db2_db_free_principal
+ (krb5_context,
+ krb5_db_entry *,
+ int );
+krb5_error_code krb5_db2_db_put_principal
+ (krb5_context,
+ krb5_db_entry *,
+ int *,
+ char **db_args
+ );
+krb5_error_code krb5_db2_db_iterate_ext
+ (krb5_context,
+ krb5_error_code (*) (krb5_pointer,
+ krb5_db_entry *),
+ krb5_pointer, int, int );
+krb5_error_code krb5_db2_db_iterate
+(krb5_context,char *,
+ krb5_error_code (*) (krb5_pointer,
+ krb5_db_entry *),
+ krb5_pointer );
+krb5_error_code krb5_db2_db_set_nonblocking
+ (krb5_context,
+ krb5_boolean,
+ krb5_boolean * );
+krb5_boolean krb5_db2_db_set_lockmode
+ (krb5_context,
+ krb5_boolean );
+krb5_error_code krb5_db2_db_open_database
+ (krb5_context);
+krb5_error_code krb5_db2_db_close_database
+ (krb5_context);
+
+krb5_error_code
+krb5_db2_set_master_key_ext ( krb5_context kcontext,
+ char *pwd,
+ krb5_keyblock *key);
+
+krb5_error_code
+krb5_db2_db_set_mkey( krb5_context context,
+ krb5_keyblock *key);
+
+krb5_error_code
+krb5_db2_db_get_mkey( krb5_context context,
+ krb5_keyblock **key);
+
+krb5_error_code
+krb5_db2_db_put_principal( krb5_context context,
+ krb5_db_entry *entries,
+ register int *nentries,
+ char **db_args);
+
+krb5_error_code
+krb5_db2_db_delete_principal(krb5_context context,
+ krb5_const_principal searchfor,
+ int *nentries);
+
+krb5_error_code krb5_db2_lib_init(krb5_set_err_func_t);
+
+krb5_error_code krb5_db2_lib_cleanup(void);
+
+krb5_error_code
+krb5_db2_db_unlock(krb5_context);
+
+krb5_error_code
+krb5_db2_db_set_option ( krb5_context kcontext,
+ int option,
+ void *value );
+
+krb5_error_code
+krb5_db2_db_lock( krb5_context context,
+ int in_mode);
+
+
+krb5_error_code
+krb5_db2_open( krb5_context kcontext,
+ char *conf_section,
+ char **db_args,
+ int mode );
+
+krb5_error_code krb5_db2_create( krb5_context kcontext,
+ char *conf_section,
+ char **db_args );
+
+krb5_error_code krb5_db2_destroy( krb5_context kcontext,
+ char *conf_section,
+ char **db_args );
+
+const char * krb5_db2_err2str( krb5_context kcontext,
+ long err_code );
+
+void *
+krb5_db2_alloc( krb5_context kcontext,
+ void *ptr,
+ size_t size );
+
+void
+krb5_db2_free( krb5_context kcontext,
+ void *ptr );
+
+
+
+
+
+/* policy management functions */
+krb5_error_code
+krb5_db2_create_policy(krb5_context context, osa_policy_ent_t entry);
+
+krb5_error_code krb5_db2_get_policy ( krb5_context kcontext,
+ char *name,
+ osa_policy_ent_t *policy,
+ int *cnt);
+
+krb5_error_code krb5_db2_get_policy ( krb5_context kcontext,
+ char *name,
+ osa_policy_ent_t *policy,
+ int *cnt);
+
+krb5_error_code krb5_db2_put_policy ( krb5_context kcontext,
+ osa_policy_ent_t policy );
+
+krb5_error_code krb5_db2_iter_policy ( krb5_context kcontext,
+ char *match_entry,
+ osa_adb_iter_policy_func func,
+ void *data );
+
+krb5_error_code krb5_db2_delete_policy ( krb5_context kcontext,
+ char *policy );
+
+void krb5_db2_free_policy( krb5_context kcontext,
+ osa_policy_ent_t entry );
+
+
+
+extern krb5_set_err_func_t krb5_db2_dal_err_funcp;
+
+#endif /* KRB5_KDB_DB2_H */
diff --git a/src/lib/kdb/kdb_db2/kdb_xdr.c b/src/lib/kdb/kdb_db2/kdb_xdr.c
new file mode 100644
index 000000000..a5332ea6d
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/kdb_xdr.c
@@ -0,0 +1,816 @@
+/*
+ * lib/kdb/kdb_xdr.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+#include "k5-int.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "kdb_xdr.h"
+
+#define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n)))
+
+krb5_error_code
+krb5_dbe_create_key_data(context, entry)
+ krb5_context context;
+ krb5_db_entry * entry;
+{
+ if ((entry->key_data =
+ (krb5_key_data *) safe_realloc(entry->key_data,
+ (sizeof(krb5_key_data)*
+ (entry->n_key_data + 1)))) == NULL)
+ return(ENOMEM);
+
+
+ memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
+ entry->n_key_data++;
+
+ return 0;
+}
+
+krb5_error_code
+krb5_dbe_update_tl_data(context, entry, new_tl_data)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_tl_data * new_tl_data;
+{
+ krb5_tl_data * tl_data;
+ krb5_octet * tmp;
+
+ /* copy the new data first, so we can fail cleanly if malloc()
+ fails */
+
+ if ((tmp = (krb5_octet *) malloc(new_tl_data->tl_data_length)) == NULL)
+ return(ENOMEM);
+
+ /* Find an existing entry of the specified type and point at
+ it, or NULL if not found */
+
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next)
+ if (tl_data->tl_data_type == new_tl_data->tl_data_type)
+ break;
+
+ /* if necessary, chain a new record in the beginning and point at it */
+
+ if (!tl_data) {
+ if ((tl_data = (krb5_tl_data *) calloc(1, sizeof(krb5_tl_data)))
+ == NULL) {
+ free(tmp);
+ return(ENOMEM);
+ }
+ tl_data->tl_data_next = entry->tl_data;
+ entry->tl_data = tl_data;
+ entry->n_tl_data++;
+ }
+
+ /* fill in the record */
+
+ if (tl_data->tl_data_contents)
+ free(tl_data->tl_data_contents);
+
+ tl_data->tl_data_type = new_tl_data->tl_data_type;
+ tl_data->tl_data_length = new_tl_data->tl_data_length;
+ tl_data->tl_data_contents = tmp;
+ memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
+
+ return(0);
+}
+
+krb5_error_code
+krb5_dbe_lookup_tl_data(context, entry, ret_tl_data)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_tl_data * ret_tl_data;
+{
+ krb5_tl_data *tl_data;
+
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
+ if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
+ *ret_tl_data = *tl_data;
+ return(0);
+ }
+ }
+
+ /* if the requested record isn't found, return zero bytes.
+ if it ever means something to have a zero-length tl_data,
+ this code and its callers will have to be changed */
+
+ ret_tl_data->tl_data_length = 0;
+ ret_tl_data->tl_data_contents = NULL;
+ return(0);
+}
+
+krb5_error_code
+krb5_dbe_update_last_pwd_change(context, entry, stamp)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_timestamp stamp;
+{
+ krb5_tl_data tl_data;
+ krb5_octet buf[4]; /* this is the encoded size of an int32 */
+
+ tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+ tl_data.tl_data_length = sizeof(buf);
+ krb5_kdb_encode_int32((krb5_int32) stamp, buf);
+ tl_data.tl_data_contents = buf;
+
+ return(krb5_dbe_update_tl_data(context, entry, &tl_data));
+}
+
+krb5_error_code
+krb5_dbe_lookup_last_pwd_change(context, entry, stamp)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_timestamp * stamp;
+{
+ krb5_tl_data tl_data;
+ krb5_error_code code;
+ krb5_int32 tmp;
+
+ tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+
+ if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
+ return(code);
+
+ if (tl_data.tl_data_length != 4) {
+ *stamp = 0;
+ return(0);
+ }
+
+ krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
+
+ *stamp = (krb5_timestamp) tmp;
+
+ return(0);
+}
+
+/* it seems odd that there's no function to remove a tl_data, but if
+ I need one, I'll add one */
+
+krb5_error_code
+krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_timestamp mod_date;
+ krb5_const_principal mod_princ;
+{
+ krb5_tl_data tl_data;
+
+ krb5_error_code retval = 0;
+ krb5_octet * nextloc = 0;
+ char * unparse_mod_princ = 0;
+ unsigned int unparse_mod_princ_size;
+
+ if ((retval = krb5_unparse_name(context, mod_princ,
+ &unparse_mod_princ)))
+ return(retval);
+
+ unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
+
+ if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
+ == NULL) {
+ free(unparse_mod_princ);
+ return(ENOMEM);
+ }
+
+ tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
+ tl_data.tl_data_length = unparse_mod_princ_size + 4;
+ tl_data.tl_data_contents = nextloc;
+
+ /* Mod Date */
+ krb5_kdb_encode_int32(mod_date, nextloc);
+
+ /* Mod Princ */
+ memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size);
+
+ retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
+
+ free(unparse_mod_princ);
+ free(nextloc);
+
+ return(retval);
+}
+
+krb5_error_code
+krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ)
+ krb5_context context;
+ krb5_db_entry * entry;
+ krb5_timestamp * mod_time;
+ krb5_principal * mod_princ;
+{
+ krb5_tl_data tl_data;
+ krb5_error_code code;
+
+ tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
+
+ if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
+ return(code);
+
+ if ((tl_data.tl_data_length < 5) ||
+ (tl_data.tl_data_contents[tl_data.tl_data_length-1] != '\0'))
+ return(KRB5_KDB_TRUNCATED_RECORD);
+
+ /* Mod Date */
+ krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time);
+
+ /* Mod Princ */
+ if ((code = krb5_parse_name(context,
+ (const char *) (tl_data.tl_data_contents+4),
+ mod_princ)))
+ return(code);
+
+ return(0);
+}
+
+krb5_error_code
+krb5_encode_princ_dbkey(context, key, principal)
+ krb5_context context;
+ krb5_data *key;
+ krb5_const_principal principal;
+{
+ char *princ_name;
+ krb5_error_code retval;
+
+ if (!(retval = krb5_unparse_name(context, principal, &princ_name))) {
+ /* need to store the NULL for decoding */
+ key->length = strlen(princ_name)+1;
+ key->data = princ_name;
+ }
+ return(retval);
+}
+
+void
+krb5_free_princ_dbkey(context, key)
+ krb5_context context;
+ krb5_data *key;
+{
+ (void) krb5_free_data_contents(context, key);
+}
+
+krb5_error_code
+krb5_encode_princ_contents(context, content, entry)
+ krb5_context context;
+ krb5_data * content;
+ krb5_db_entry * entry;
+{
+ int i, j;
+ unsigned int unparse_princ_size;
+ char * unparse_princ;
+ char * nextloc;
+ krb5_tl_data * tl_data;
+ krb5_error_code retval;
+ krb5_int16 psize16;
+
+ /*
+ * Generate one lump of data from the krb5_db_entry.
+ * This data must be independent of byte order of the machine,
+ * compact and extensible.
+ */
+
+ /*
+ * First allocate enough space for all the data.
+ * Need 2 bytes for the length of the base structure
+ * then 36 [ 8 * 4 + 2 * 2] bytes for the base information
+ * [ attributes, max_life, max_renewable_life, expiration,
+ * pw_expiration, last_success, last_failed, fail_auth_count ]
+ * [ n_key_data, n_tl_data ]
+ * then XX bytes [ e_length ] for the extra data [ e_data ]
+ * then XX bytes [ 2 for length + length for string ] for the principal,
+ * 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->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->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->length += tl_data->tl_data_length;
+ content->length += 4; /* type, length */
+ i++;
+ }
+
+ if (i != entry->n_tl_data) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto epc_error;
+ }
+
+ /* key_data is an array */
+ for (i = 0; i < entry->n_key_data; i++) {
+ content->length += 4; /* Version, KVNO */
+ for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+ content->length += entry->key_data[i].key_data_length[j];
+ content->length += 4; /* type + length */
+ }
+ }
+
+ if ((content->data = malloc(content->length)) == NULL) {
+ retval = ENOMEM;
+ goto epc_error;
+ }
+
+ /*
+ * Now we go through entry again, this time copying data
+ * These first entries are always saved regardless of version
+ */
+ nextloc = content->data;
+
+ /* Base Length */
+ krb5_kdb_encode_int16(entry->len, nextloc);
+ nextloc += 2;
+
+ /* Attributes */
+ krb5_kdb_encode_int32(entry->attributes, nextloc);
+ nextloc += 4;
+
+ /* Max Life */
+ krb5_kdb_encode_int32(entry->max_life, nextloc);
+ nextloc += 4;
+
+ /* Max Renewable Life */
+ krb5_kdb_encode_int32(entry->max_renewable_life, nextloc);
+ nextloc += 4;
+
+ /* When the client expires */
+ krb5_kdb_encode_int32(entry->expiration, nextloc);
+ nextloc += 4;
+
+ /* When its passwd expires */
+ krb5_kdb_encode_int32(entry->pw_expiration, nextloc);
+ nextloc += 4;
+
+ /* Last successful passwd */
+ krb5_kdb_encode_int32(entry->last_success, nextloc);
+ nextloc += 4;
+
+ /* Last failed passwd attempt */
+ krb5_kdb_encode_int32(entry->last_failed, nextloc);
+ nextloc += 4;
+
+ /* # of failed passwd attempt */
+ krb5_kdb_encode_int32(entry->fail_auth_count, nextloc);
+ nextloc += 4;
+
+ /* # tl_data strutures */
+ krb5_kdb_encode_int16(entry->n_tl_data, nextloc);
+ nextloc += 2;
+
+ /* # key_data strutures */
+ krb5_kdb_encode_int16(entry->n_key_data, nextloc);
+ nextloc += 2;
+
+ /* Put extended fields here */
+ if (entry->len != KRB5_KDB_V1_BASE_LENGTH)
+ abort();
+
+ /* Any extra data that this version doesn't understand. */
+ if (entry->e_length) {
+ memcpy(nextloc, entry->e_data, entry->e_length);
+ nextloc += entry->e_length;
+ }
+
+ /*
+ * Now we get to the principal.
+ * To squeze a few extra bytes out it is always assumed to come
+ * after the base type.
+ */
+ psize16 = (krb5_int16) unparse_princ_size;
+ krb5_kdb_encode_int16(psize16, nextloc);
+ nextloc += 2;
+ (void) memcpy(nextloc, unparse_princ, unparse_princ_size);
+ nextloc += unparse_princ_size;
+
+ /* tl_data is a linked list, of type, legth, contents */
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
+ krb5_kdb_encode_int16(tl_data->tl_data_type, nextloc);
+ nextloc += 2;
+ krb5_kdb_encode_int16(tl_data->tl_data_length, nextloc);
+ nextloc += 2;
+
+ memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length);
+ nextloc += tl_data->tl_data_length;
+ }
+
+ /* key_data is an array */
+ for (i = 0; i < entry->n_key_data; i++) {
+ krb5_kdb_encode_int16(entry->key_data[i].key_data_ver, nextloc);
+ nextloc += 2;
+ krb5_kdb_encode_int16(entry->key_data[i].key_data_kvno, nextloc);
+ nextloc += 2;
+
+ for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+ krb5_int16 type = entry->key_data[i].key_data_type[j];
+ krb5_ui_2 length = entry->key_data[i].key_data_length[j];
+
+ krb5_kdb_encode_int16(type, nextloc);
+ nextloc += 2;
+ krb5_kdb_encode_int16(length, nextloc);
+ nextloc += 2;
+
+ if (length) {
+ memcpy(nextloc, entry->key_data[i].key_data_contents[j],length);
+ nextloc += length;
+ }
+ }
+ }
+
+epc_error:;
+ free(unparse_princ);
+ return retval;
+}
+
+void
+krb5_free_princ_contents(context, contents)
+ krb5_context context;
+ krb5_data *contents;
+{
+ krb5_free_data_contents(context, contents);
+ return;
+}
+
+krb5_error_code
+krb5_decode_princ_contents(context, content, entry)
+ krb5_context context;
+ krb5_data * content;
+ krb5_db_entry * entry;
+{
+ int sizeleft, i;
+ char * nextloc;
+ krb5_tl_data ** tl_data;
+ krb5_int16 i16;
+
+ krb5_error_code retval;
+
+ /* Zero out entry and NULL pointers */
+ memset(entry, 0, sizeof(krb5_db_entry));
+
+ /*
+ * undo the effects of encode_princ_contents.
+ *
+ * The first part is decoding the base type. If the base type is
+ * bigger than the original base type then the additional fields
+ * need to be filled in. If the base type is larger than any
+ * known base type the additional data goes in e_data.
+ */
+
+ /* First do the easy stuff */
+ nextloc = content->data;
+ sizeleft = content->length;
+ if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0)
+ return KRB5_KDB_TRUNCATED_RECORD;
+
+ /* Base Length */
+ krb5_kdb_decode_int16(nextloc, entry->len);
+ nextloc += 2;
+
+ /* Attributes */
+ krb5_kdb_decode_int32(nextloc, entry->attributes);
+ nextloc += 4;
+
+ /* Max Life */
+ krb5_kdb_decode_int32(nextloc, entry->max_life);
+ nextloc += 4;
+
+ /* Max Renewable Life */
+ krb5_kdb_decode_int32(nextloc, entry->max_renewable_life);
+ nextloc += 4;
+
+ /* When the client expires */
+ krb5_kdb_decode_int32(nextloc, entry->expiration);
+ nextloc += 4;
+
+ /* When its passwd expires */
+ krb5_kdb_decode_int32(nextloc, entry->pw_expiration);
+ nextloc += 4;
+
+ /* Last successful passwd */
+ krb5_kdb_decode_int32(nextloc, entry->last_success);
+ nextloc += 4;
+
+ /* Last failed passwd attempt */
+ krb5_kdb_decode_int32(nextloc, entry->last_failed);
+ nextloc += 4;
+
+ /* # of failed passwd attempt */
+ krb5_kdb_decode_int32(nextloc, entry->fail_auth_count);
+ nextloc += 4;
+
+ /* # tl_data strutures */
+ krb5_kdb_decode_int16(nextloc, entry->n_tl_data);
+ nextloc += 2;
+
+ if (entry->n_tl_data < 0)
+ return KRB5_KDB_TRUNCATED_RECORD;
+
+ /* # key_data strutures */
+ krb5_kdb_decode_int16(nextloc, entry->n_key_data);
+ nextloc += 2;
+
+ if (entry->n_key_data < 0)
+ return KRB5_KDB_TRUNCATED_RECORD;
+
+ /* Check for extra data */
+ if (entry->len > KRB5_KDB_V1_BASE_LENGTH) {
+ entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH;
+ if ((entry->e_data = (krb5_octet *)malloc(entry->e_length))) {
+ memcpy(entry->e_data, nextloc, entry->e_length);
+ nextloc += entry->e_length;
+ } else {
+ return ENOMEM;
+ }
+ }
+
+ /*
+ * Get the principal name for the entry
+ * (stored as a string which gets unparsed.)
+ */
+ if ((sizeleft -= 2) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+
+ i = 0;
+ krb5_kdb_decode_int16(nextloc, i16);
+ i = (int) i16;
+ nextloc += 2;
+
+ if ((retval = krb5_parse_name(context, nextloc, &(entry->princ))))
+ goto error_out;
+ if (((size_t) i != (strlen(nextloc) + 1)) || (sizeleft < i)) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ sizeleft -= i;
+ nextloc += i;
+
+ /* tl_data is a linked list */
+ tl_data = &entry->tl_data;
+ for (i = 0; i < entry->n_tl_data; i++) {
+ if ((sizeleft -= 4) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ if ((*tl_data = (krb5_tl_data *)
+ malloc(sizeof(krb5_tl_data))) == NULL) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+ (*tl_data)->tl_data_next = NULL;
+ (*tl_data)->tl_data_contents = NULL;
+ krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type);
+ nextloc += 2;
+ krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length);
+ nextloc += 2;
+
+ if ((sizeleft -= (*tl_data)->tl_data_length) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ if (((*tl_data)->tl_data_contents = (krb5_octet *)
+ malloc((*tl_data)->tl_data_length)) == NULL) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*tl_data)->tl_data_contents,nextloc,(*tl_data)->tl_data_length);
+ nextloc += (*tl_data)->tl_data_length;
+ tl_data = &((*tl_data)->tl_data_next);
+ }
+
+ /* key_data is an array */
+ if (entry->n_key_data && ((entry->key_data = (krb5_key_data *)
+ malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+ for (i = 0; i < entry->n_key_data; i++) {
+ krb5_key_data * key_data;
+ int j;
+
+ if ((sizeleft -= 4) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ key_data = entry->key_data + i;
+ memset(key_data, 0, sizeof(krb5_key_data));
+ krb5_kdb_decode_int16(nextloc, key_data->key_data_ver);
+ nextloc += 2;
+ krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno);
+ nextloc += 2;
+
+ /* key_data_ver determins number of elements and how to unparse them. */
+ if (key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) {
+ for (j = 0; j < key_data->key_data_ver; j++) {
+ if ((sizeleft -= 4) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]);
+ nextloc += 2;
+ krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]);
+ nextloc += 2;
+
+ if ((sizeleft -= key_data->key_data_length[j]) < 0) {
+ retval = KRB5_KDB_TRUNCATED_RECORD;
+ goto error_out;
+ }
+ if (key_data->key_data_length[j]) {
+ if ((key_data->key_data_contents[j] = (krb5_octet *)
+ malloc(key_data->key_data_length[j])) == NULL) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+ memcpy(key_data->key_data_contents[j], nextloc,
+ key_data->key_data_length[j]);
+ nextloc += key_data->key_data_length[j];
+ }
+ }
+ } else {
+ /* This isn't right. I'll fix it later */
+ abort();
+ }
+ }
+ return 0;
+
+error_out:;
+ krb5_dbe_free_contents(context, entry);
+ return retval;
+}
+
+void
+krb5_dbe_free_contents(context, entry)
+ krb5_context context;
+ krb5_db_entry * entry;
+{
+ krb5_tl_data * tl_data_next;
+ krb5_tl_data * tl_data;
+ int i, j;
+
+ if (entry->e_data)
+ free(entry->e_data);
+ if (entry->princ)
+ krb5_free_principal(context, entry->princ);
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
+ tl_data_next = tl_data->tl_data_next;
+ if (tl_data->tl_data_contents)
+ free(tl_data->tl_data_contents);
+ free(tl_data);
+ }
+ if (entry->key_data) {
+ for (i = 0; i < entry->n_key_data; i++) {
+ for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+ if (entry->key_data[i].key_data_length[j]) {
+ if (entry->key_data[i].key_data_contents[j]) {
+ memset(entry->key_data[i].key_data_contents[j],
+ 0,
+ (unsigned) entry->key_data[i].key_data_length[j]);
+ free (entry->key_data[i].key_data_contents[j]);
+ }
+ }
+ entry->key_data[i].key_data_contents[j] = NULL;
+ entry->key_data[i].key_data_length[j] = 0;
+ entry->key_data[i].key_data_type[j] = 0;
+ }
+ }
+ free(entry->key_data);
+ }
+ memset(entry, 0, sizeof(*entry));
+ return;
+}
+
+/*
+ * Given a particular enctype and optional salttype and kvno, find the
+ * most appropriate krb5_key_data entry of the database entry.
+ *
+ * If stype or kvno is negative, it is ignored.
+ * If kvno is 0 get the key which is maxkvno for the princ and matches
+ * the other attributes.
+ */
+krb5_error_code
+krb5_dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap)
+ krb5_context kcontext;
+ krb5_db_entry *dbentp;
+ krb5_int32 *start;
+ krb5_int32 ktype;
+ krb5_int32 stype;
+ krb5_int32 kvno;
+ krb5_key_data **kdatap;
+{
+ int i, idx;
+ int maxkvno;
+ krb5_key_data *datap;
+ krb5_error_code ret;
+
+ ret = 0;
+ if (kvno == -1 && stype == -1 && ktype == -1)
+ kvno = 0;
+
+ if (kvno == 0) {
+ /* Get the max key version */
+ for (i = 0; i < dbentp->n_key_data; i++) {
+ if (kvno < dbentp->key_data[i].key_data_kvno) {
+ kvno = dbentp->key_data[i].key_data_kvno;
+ }
+ }
+ }
+
+ maxkvno = -1;
+ datap = (krb5_key_data *) NULL;
+ for (i = *start; i < dbentp->n_key_data; i++) {
+ krb5_boolean similar;
+ krb5_int32 db_stype;
+
+ ret = 0;
+ if (dbentp->key_data[i].key_data_ver > 1) {
+ db_stype = dbentp->key_data[i].key_data_type[1];
+ } else {
+ db_stype = KRB5_KDB_SALTTYPE_NORMAL;
+ }
+
+ /*
+ * Filter out non-permitted enctypes.
+ */
+ if (!krb5_is_permitted_enctype(kcontext,
+ dbentp->key_data[i].key_data_type[0])) {
+ ret = KRB5_KDB_NO_PERMITTED_KEY;
+ continue;
+ }
+
+
+ if (ktype > 0) {
+ if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
+ dbentp->key_data[i].key_data_type[0],
+ &similar)))
+
+ return(ret);
+ }
+
+ if (((ktype <= 0) || similar) &&
+ ((db_stype == stype) || (stype < 0))) {
+ if (kvno >= 0) {
+ if (kvno == dbentp->key_data[i].key_data_kvno) {
+ datap = &dbentp->key_data[i];
+ idx = i;
+ maxkvno = kvno;
+ break;
+ }
+ } else {
+ if (dbentp->key_data[i].key_data_kvno > maxkvno) {
+ maxkvno = dbentp->key_data[i].key_data_kvno;
+ datap = &dbentp->key_data[i];
+ idx = i;
+ }
+ }
+ }
+ }
+ if (maxkvno < 0)
+ return ret ? ret : KRB5_KDB_NO_MATCHING_KEY;
+ *kdatap = datap;
+ *start = idx+1;
+ return 0;
+}
+
+krb5_error_code
+krb5_dbe_find_enctype(kcontext, dbentp, ktype, stype, kvno, kdatap)
+ krb5_context kcontext;
+ krb5_db_entry *dbentp;
+ krb5_int32 ktype;
+ krb5_int32 stype;
+ krb5_int32 kvno;
+ krb5_key_data **kdatap;
+{
+ krb5_int32 start = 0;
+
+ return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype,
+ kvno, kdatap);
+}
+
+
diff --git a/src/lib/kdb/kdb_db2/kdb_xdr.h b/src/lib/kdb/kdb_db2/kdb_xdr.h
new file mode 100644
index 000000000..2ee068fbd
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/kdb_xdr.h
@@ -0,0 +1,32 @@
+#ifndef _KDB2_XDR_H
+#define _KDB2_XDR_H
+
+krb5_error_code
+krb5_encode_princ_dbkey( krb5_context context,
+ krb5_data *key,
+ krb5_const_principal principal);
+
+krb5_error_code
+krb5_decode_princ_contents( krb5_context context,
+ krb5_data * content,
+ krb5_db_entry * entry);
+
+void
+krb5_dbe_free_contents( krb5_context context,
+ krb5_db_entry * entry);
+
+krb5_error_code
+krb5_encode_princ_contents( krb5_context context,
+ krb5_data * content,
+ krb5_db_entry * entry);
+
+
+void
+krb5_free_princ_dbkey( krb5_context context,
+ krb5_data *key);
+
+void
+krb5_free_princ_contents( krb5_context context,
+ krb5_data *contents);
+
+#endif
diff --git a/src/lib/kdb/kdb_db2/libkdb_db2.exports b/src/lib/kdb/kdb_db2/libkdb_db2.exports
new file mode 100644
index 000000000..b6902ebda
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/libkdb_db2.exports
@@ -0,0 +1 @@
+krb5_db_vftabl_kdb_db2
diff --git a/src/lib/kdb/kdb_db2/pol_xdr.c b/src/lib/kdb/kdb_db2/pol_xdr.c
new file mode 100644
index 000000000..37761080a
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/pol_xdr.c
@@ -0,0 +1,88 @@
+#include <sys/types.h>
+#include <krb5.h>
+#include <gssrpc/rpc.h>
+#include <krb5/kdb.h>
+#include "policy_db.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+bool_t xdr_nullstring(XDR *xdrs, char **objp)
+{
+ u_int size;
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (*objp == NULL)
+ size = 0;
+ else
+ size = strlen(*objp) + 1;
+ }
+ if (! xdr_u_int(xdrs, &size)) {
+ return FALSE;
+ }
+ switch (xdrs->x_op) {
+ case XDR_DECODE:
+ if (size == 0) {
+ *objp = NULL;
+ return TRUE;
+ } else if (*objp == NULL) {
+ *objp = (char *) mem_alloc(size);
+ if (*objp == NULL) {
+ errno = ENOMEM;
+ return FALSE;
+ }
+ }
+ return (xdr_opaque(xdrs, *objp, size));
+
+ case XDR_ENCODE:
+ if (size != 0)
+ return (xdr_opaque(xdrs, *objp, size));
+ return TRUE;
+
+ case XDR_FREE:
+ if (*objp != NULL)
+ mem_free(*objp, size);
+ *objp = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+bool_t
+xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp)
+{
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ objp->version = OSA_ADB_POLICY_VERSION_1;
+ /* fall through */
+ case XDR_FREE:
+ if (!xdr_int(xdrs, &objp->version))
+ return FALSE;
+ break;
+ case XDR_DECODE:
+ if (!xdr_int(xdrs, &objp->version))
+ return FALSE;
+ if (objp->version != OSA_ADB_POLICY_VERSION_1)
+ return FALSE;
+ break;
+ }
+
+ if(!xdr_nullstring(xdrs, &objp->name))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->pw_min_life))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->pw_max_life))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->pw_min_length))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->pw_min_classes))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->pw_history_num))
+ return (FALSE);
+ if (!xdr_u_int32(xdrs, &objp->policy_refcnt))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/src/lib/kdb/kdb_db2/policy_db.h b/src/lib/kdb/kdb_db2/policy_db.h
new file mode 100644
index 000000000..772b24d07
--- /dev/null
+++ b/src/lib/kdb/kdb_db2/policy_db.h
@@ -0,0 +1,87 @@
+/*
+ * Data Types for policy and principal information that
+ * exists in the respective databases.
+ *
+ * $Header$
+ *
+ * This file was originally created with rpcgen.
+ * It has been hacked up since then.
+ */
+
+#ifndef __ADB_H__
+#define __ADB_H__
+#include <sys/types.h>
+#include "k5-int.h"
+#include <krb5/kdb.h>
+#include <db.h>
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include "adb_err.h"
+#include <com_err.h>
+
+typedef long osa_adb_ret_t;
+
+#define OSA_ADB_POLICY_DB_MAGIC 0x12345A00
+
+#define OSA_ADB_POLICY_VERSION_MASK 0x12345D00
+#define OSA_ADB_POLICY_VERSION_1 0x12345D01
+
+
+
+typedef struct _osa_adb_db_lock_ent_t {
+ FILE *lockfile;
+ char *filename;
+ int refcnt, lockmode, lockcnt;
+ krb5_context context;
+} osa_adb_lock_ent, *osa_adb_lock_t;
+
+typedef struct _osa_adb_db_ent_t {
+ int magic;
+ DB *db;
+ HASHINFO info;
+ BTREEINFO btinfo;
+ char *filename;
+ osa_adb_lock_t lock;
+ int opencnt;
+} osa_adb_db_ent, *osa_adb_db_t, *osa_adb_princ_t, *osa_adb_policy_t;
+
+/*
+ * Return Code (the rest are in adb_err.h)
+ */
+
+#define OSA_ADB_OK 0
+
+/*
+ * Functions
+ */
+
+krb5_error_code osa_adb_create_db(char *filename, char *lockfile, int magic);
+krb5_error_code osa_adb_destroy_db(char *filename, char *lockfile, int magic);
+krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom,
+ char *fileto, char *lockto, int magic);
+krb5_error_code osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
+ char *lockfile, int magic);
+krb5_error_code osa_adb_fini_db(osa_adb_db_t db, int magic);
+krb5_error_code osa_adb_get_lock(osa_adb_db_t db, int mode);
+krb5_error_code osa_adb_release_lock(osa_adb_db_t db);
+krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype);
+krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db);
+krb5_error_code osa_adb_close_policy(osa_adb_policy_t db);
+krb5_error_code osa_adb_create_policy(osa_adb_policy_t db,
+ osa_policy_ent_t entry);
+krb5_error_code osa_adb_destroy_policy(osa_adb_policy_t db,
+ char * name);
+krb5_error_code osa_adb_get_policy(osa_adb_policy_t db,
+ char * name,
+ osa_policy_ent_t *entry,
+ int *cnt);
+krb5_error_code osa_adb_put_policy(osa_adb_policy_t db,
+ osa_policy_ent_t entry);
+krb5_error_code osa_adb_iter_policy(osa_adb_policy_t db,
+ osa_adb_iter_policy_func func,
+ void * data);
+void osa_free_policy_ent(osa_policy_ent_t val);
+
+bool_t xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp);
+
+#endif /* __ADB_H__ */