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