From: Mark Eichin Date: Thu, 27 Apr 1995 17:31:56 +0000 (+0000) Subject: V4 kdb library X-Git-Tag: krb5-1.0-beta5~208 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=41d4b980944bf6da87c0cae2e2b4859c7f31976e;p=krb5.git V4 kdb library git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5544 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/kdb4/.Sanitize b/src/lib/kdb4/.Sanitize new file mode 100644 index 000000000..e7c93b5f6 --- /dev/null +++ b/src/lib/kdb4/.Sanitize @@ -0,0 +1,41 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +.cvsignore +ChangeLog +Makefile.in +configure.in +krb_cache.c +krb_dbl.c +krb_dbm.c +krb_kdb_utils.c +krb_lib.c +print_princ.c + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/src/lib/kdb4/.cvsignore b/src/lib/kdb4/.cvsignore new file mode 100644 index 000000000..e8c05a6b1 --- /dev/null +++ b/src/lib/kdb4/.cvsignore @@ -0,0 +1 @@ +configure diff --git a/src/lib/kdb4/ChangeLog b/src/lib/kdb4/ChangeLog new file mode 100644 index 000000000..a9cd53496 --- /dev/null +++ b/src/lib/kdb4/ChangeLog @@ -0,0 +1,68 @@ +Fri Jan 13 18:24:26 1995 Ian Lance Taylor + + * krb_kdb_utils.c (kdb_verify_master_key): Don't say ``BEWARE!'', + since it's not clear what to be wary of. + +Tue Jan 10 01:16:22 1995 Mark Eichin + + * krb_dbm.c: add macro for dbm_delete under dbm. + (kerb_db_del_principal): dbm_delete the key, and handle database + locking correctly. + * krb_lib.c (kerb_del_principal): get the principal, to sanity + check, and then delete it. + +Wed Jan 4 17:44:26 1995 Ian Lance Taylor + + * krb_kdb_utils.c (kdb_get_master_key_from): Add verify argument, + and pass it to read_password routine. + (kdb_get_master_key): Add verify argument, and pass it to + kdb_get_master_key_from. + +Thu Nov 3 16:33:34 1994 Ian Lance Taylor + + * krb_dbm.c (kerb_db_rename): Initialize local variable ok. + +Tue Nov 1 16:29:32 1994 Ian Lance Taylor + + * krb_lib.c: Don't bother to declare strncpy or ctime. Declare + getenv only if it is needed. + (kerb_put_principal): Pass the address of a local time_t variable + to localtime, rather than principal->mod_date which has type + unsigned long. + * krb_cache.c: Don't declare strncpy. + * print_princ.c: Don't declare strncpy or ctime. + +Mon Oct 31 19:40:43 1994 Ian Lance Taylor + + * Makefile.in (CODE): Remove Imakefile. + +Thu Jul 21 17:40:14 1994 Mark Eichin (eichin@cygnus.com) + + * krb_kdb_utils.c (kdb_get_master_key_from): new function. + Modification of kdb_get_master_key (which is now only called by + things that force a prompt anyway, but is kept for compatibility.) + Takes an extra argument, optional filename to get the key from. + +Tue Jul 5 11:21:18 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * print_princ.c (krb_print_principal): Arg to localtime() should + be time_t*. + * krb_lib.c (kerb_put_principal): Arg to time() should be time_t*. + + * krb_kdb_utils.c: Include string.h. + +Tue Jun 21 00:19:04 1994 John Gilmore (gnu@cygnus.com) + + * krb_kdb_utils.c: Lint. + +Fri May 20 01:31:04 1994 John Gilmore (gnu@cygnus.com) + + * Makefile.in: Don't keep backup files of libraries. Use LIBEXT. + +Fri May 13 02:01:36 1994 John Gilmore (gnu@cygnus.com) + + * krb_dbm.c: Move to where it can control #if NDBM. + +Mon May 9 00:14:50 1994 John Gilmore (gnu@cygnus.com) + + * krb_lib.c: Lint. diff --git a/src/lib/kdb4/Makefile.in b/src/lib/kdb4/Makefile.in new file mode 100644 index 000000000..02e499221 --- /dev/null +++ b/src/lib/kdb4/Makefile.in @@ -0,0 +1,39 @@ +CFLAGS = $(CCOPTS) $(DEFS) $(DEFINES) +DEFINES=-I$(srcdir)/../../include/kerberosIV + +LIBNAME=libkdb4.$(LIBEXT) + +BUILDTOP=$(C)$(S)$(U)$(U) +SRCS = \ + $(srcdir)/krb_dbm.c \ + $(srcdir)/krb_lib.c \ + $(srcdir)/krb_cache.c \ + $(srcdir)/print_princ.c \ + $(srcdir)/krb_kdb_utils.c + +OBJS = \ + krb_dbm.$(OBJEXT) \ + krb_lib.$(OBJEXT) \ + krb_cache.$(OBJEXT) \ + print_princ.$(OBJEXT) \ + krb_kdb_utils.$(OBJEXT) + +CODE= ${SRCS} Makefile.in + +all:: $(LIBNAME) + +$(LIBNAME): $(OBJS) + $(RM) $@ + $(ARCHIVE) $@ $(OBJS) + $(RANLIB) $@ + +clean:: + $(RM) $(LIBNAME) + $(RM) $(OBJS) + +install:: + $(INSTALL_DATA) $(LIBNAME) $(DESTDIR)$(KRB5_LIBDIR)/$(LIBNAME) + $(CHMOD) 644 $(DESTDIR)$(KRB5_LIBDIR)/$(LIBNAME) + $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/$(LIBNAME) + $(CHMOD) 444 $(DESTDIR)$(KRB5_LIBDIR)/$(LIBNAME) +## diff --git a/src/lib/kdb4/configure.in b/src/lib/kdb4/configure.in new file mode 100644 index 000000000..0f69f3b44 --- /dev/null +++ b/src/lib/kdb4/configure.in @@ -0,0 +1,18 @@ +AC_INIT(configure.in) +WITH_CCOPTS +WITH_KRB5ROOT +CONFIG_RULES +AC_SET_BUILDTOP +WITH_NETLIB +AC_PROG_ARCHIVE +AC_PROG_ARCHIVE_ADD +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_HEADER_CHECK(ndbm.h,AC_DEFINE(NDBM)) +AC_CONST +CHECK_FCNTL +AC_HEADER_CHECK(unistd.h,AC_DEFINE(HAS_UNISTD_H)) +ET_RULES +SubdirLibraryRule([$(OBJS)]) +KRB_INCLUDE +V5_AC_OUTPUT_MAKEFILE diff --git a/src/lib/kdb4/krb_cache.c b/src/lib/kdb4/krb_cache.c new file mode 100644 index 000000000..756573a1e --- /dev/null +++ b/src/lib/kdb4/krb_cache.c @@ -0,0 +1,181 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * This is where a cache would be implemented, if it were necessary. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +extern int debug; +extern long kerb_debug; +#endif +static init = 0; + +/* + * initialization routine for cache + */ + +int +kerb_cache_init() +{ + init = 1; + return (0); +} + +/* + * look up a principal in the cache returns number of principals found + */ + +int +kerb_cache_get_principal(serv, inst, principal, max) + char *serv; /* could have wild card */ + char *inst; /* could have wild card */ + Principal *principal; + unsigned int max; /* max number of name structs to return */ + +{ + int found = 0; + + if (!init) + kerb_cache_init(); +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, "cache_get_principal for %s %s max = %d\n", + serv, inst, max); +#endif /* DEBUG */ + +#ifdef DEBUG + if (kerb_debug & 2) { + if (found) { + fprintf(stderr, "cache get %s %s found %s %s sid = %d\n", + serv, inst, principal->name, principal->instance); + } else { + fprintf(stderr, "cache %s %s not found\n", serv, + inst); + } + } +#endif + return (found); +} + +/* + * insert/replace a principal in the cache returns number of principals + * inserted + */ + +int +kerb_cache_put_principal(principal, max) + Principal *principal; + unsigned int max; /* max number of principal structs to + * insert */ + +{ + u_long i; + int count = 0; + + if (!init) + kerb_cache_init(); + +#ifdef DEBUG + if (kerb_debug & 2) { + fprintf(stderr, "kerb_cache_put_principal max = %d", + max); + } +#endif + + for (i = 0; i < max; i++) { +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, "\n %s %s", + principal->name, principal->instance); +#endif + /* DO IT */ + count++; + principal++; + } + return count; +} + +/* + * look up a dba in the cache returns number of dbas found + */ + +int +kerb_cache_get_dba(serv, inst, dba, max) + char *serv; /* could have wild card */ + char *inst; /* could have wild card */ + Dba *dba; + unsigned int max; /* max number of name structs to return */ + +{ + int found = 0; + + if (!init) + kerb_cache_init(); + +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, "cache_get_dba for %s %s max = %d\n", + serv, inst, max); +#endif + +#ifdef DEBUG + if (kerb_debug & 2) { + if (found) { + fprintf(stderr, "cache get %s %s found %s %s sid = %d\n", + serv, inst, dba->name, dba->instance); + } else { + fprintf(stderr, "cache %s %s not found\n", serv, inst); + } + } +#endif + return (found); +} + +/* + * insert/replace a dba in the cache returns number of dbas inserted + */ + +int +kerb_cache_put_dba(dba, max) + Dba *dba; + unsigned int max; /* max number of dba structs to insert */ + +{ + u_long i; + int count = 0; + + if (!init) + kerb_cache_init(); +#ifdef DEBUG + if (kerb_debug & 2) { + fprintf(stderr, "kerb_cache_put_dba max = %d", max); + } +#endif + for (i = 0; i < max; i++) { +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, "\n %s %s", + dba->name, dba->instance); +#endif + /* DO IT */ + count++; + dba++; + } + return count; +} + diff --git a/src/lib/kdb4/krb_dbl.c b/src/lib/kdb4/krb_dbl.c new file mode 100644 index 000000000..777629845 --- /dev/null +++ b/src/lib/kdb4/krb_dbl.c @@ -0,0 +1 @@ +This file is now obsolete. diff --git a/src/lib/kdb4/krb_dbm.c b/src/lib/kdb4/krb_dbm.c new file mode 100644 index 000000000..c67c020ba --- /dev/null +++ b/src/lib/kdb4/krb_dbm.c @@ -0,0 +1,829 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* before krb_db.h */ +#include +#include + +#ifdef NDBM +#include +#else /*NDBM*/ +#include +#endif /*NDBM*/ + +#ifdef POSIX +#include +#endif + +#define KERB_DB_MAX_RETRY 5 + +#ifdef DEBUG +extern int debug; +extern long kerb_debug; +extern char *progname; +#endif +extern char *malloc(); +extern int errno; + +static init = 0; +static char default_db_name[] = DBM_FILE; +static char *current_db_name = default_db_name; +static void encode_princ_key(), decode_princ_key(); +static void encode_princ_contents(), decode_princ_contents(); +static void kerb_dbl_fini(); +static int kerb_dbl_lock(); +static void kerb_dbl_unlock(); + +static struct timeval timestamp;/* current time of request */ +static int non_blocking = 0; + +/* + * This module contains all of the code which directly interfaces to + * the underlying representation of the Kerberos database; this + * implementation uses a DBM or NDBM indexed "file" (actually + * implemented as two separate files) to store the relations, plus a + * third file as a semaphore to allow the database to be replaced out + * from underneath the KDC server. + */ + +/* + * 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 (kdb_util, kpropd) 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 + * KERB_DB_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. + */ + +/* Macros to convert ndbm names to dbm names. + * Note that dbm_nextkey() cannot be simply converted using a macro, since + * it is invoked giving the database, and nextkey() needs the previous key. + * + * Instead, all routines call "dbm_next" instead. + */ + +#ifndef NDBM +typedef char DBM; + +#define dbm_open(file, flags, mode) ((dbminit(file) == 0)?"":((char *)0)) +#define dbm_fetch(db, key) fetch(key) +#define dbm_delete(db, key) delete(key) +#define dbm_store(db, key, content, flag) store(key, content) +#define dbm_firstkey(db) firstkey() +#define dbm_next(db,key) nextkey(key) +#define dbm_close(db) dbmclose() +#else +#define dbm_next(db,key) dbm_nextkey(db) +#endif + +/* + * Utility routine: generate name of database file. + */ + +static char *gen_dbsuffix(db_name, sfx) + char *db_name; + char *sfx; +{ + char *dbsuffix; + + if (sfx == NULL) + sfx = ".ok"; + + dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1); + strcpy(dbsuffix, db_name); + strcat(dbsuffix, sfx); + return dbsuffix; +} + +/* + * initialization for data base routines. + */ + +int kerb_db_init() +{ + init = 1; + return (0); +} + +/* + * gracefully shut down database--must be called by ANY program that does + * a kerb_db_init + */ + +kerb_db_fini() +{ +} + +/* + * 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. + */ + +int kerb_db_set_name(name) + char *name; +{ + DBM *db; + + if (name == NULL) + name = default_db_name; + db = dbm_open(name, 0, 0); + if (db == NULL) + return errno; + dbm_close(db); + kerb_dbl_fini(); + current_db_name = name; + return 0; +} + +/* + * Return the last modification time of the database. + */ + +long kerb_get_db_age() +{ + struct stat st; + char *okname; + long age; + + okname = gen_dbsuffix(current_db_name, ".ok"); + + if (stat (okname, &st) < 0) + age = 0; + else + age = st.st_mtime; + + free (okname); + return age; +} + +/* + * 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 long kerb_start_update(db_name) + char *db_name; +{ + char *okname = gen_dbsuffix(db_name, ".ok"); + long age = kerb_get_db_age(); + + if (unlink(okname) < 0 + && errno != ENOENT) { + age = -1; + } + free (okname); + return age; +} + +static long kerb_end_update(db_name, age) + char *db_name; + long age; +{ + int fd; + int retval = 0; + char *new_okname = gen_dbsuffix(db_name, ".ok#"); + char *okname = gen_dbsuffix(db_name, ".ok"); + + fd = open (new_okname, O_CREAT|O_RDWR|O_TRUNC, 0600); + if (fd < 0) + retval = errno; + else { + struct stat st; + struct timeval tv[2]; + /* make sure that semaphore is "after" previous value. */ + if (fstat (fd, &st) == 0 + && st.st_mtime <= age) { + tv[0].tv_sec = st.st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = age; + tv[1].tv_usec = 0; + /* set times.. */ + utimes (new_okname, tv); +#ifndef NO_FSYNC + fsync(fd); +#endif + } + close(fd); + if (rename (new_okname, okname) < 0) + retval = errno; + } + + free (new_okname); + free (okname); + + return retval; +} + +static long kerb_start_read() +{ + return kerb_get_db_age(); +} + +static long kerb_end_read(age) + u_long age; +{ + if (kerb_get_db_age() != age || age == -1) { + return -1; + } + return 0; +} + +/* + * Create the database, assuming it's not there. + */ + +int kerb_db_create(db_name) + char *db_name; +{ + char *okname = gen_dbsuffix(db_name, ".ok"); + int fd; + register int ret = 0; +#ifdef NDBM + DBM *db; + + db = dbm_open(db_name, O_RDWR|O_CREAT|O_EXCL, 0600); + if (db == NULL) + ret = errno; + else + dbm_close(db); +#else + char *dirname = gen_dbsuffix(db_name, ".dir"); + char *pagname = gen_dbsuffix(db_name, ".pag"); + + fd = open(dirname, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd < 0) + ret = errno; + else { + close(fd); + fd = open (pagname, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd < 0) + ret = errno; + else + close(fd); + } + if (dbminit(db_name) < 0) + ret = errno; +#endif + if (ret == 0) { + fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600); + if (fd < 0) + ret = errno; + close(fd); + } + return ret; +} + +/* + * "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... + */ + +int kerb_db_rename(from, to) + char *from; + char *to; +{ + char *fromdir = gen_dbsuffix (from, ".dir"); + char *todir = gen_dbsuffix (to, ".dir"); + char *frompag = gen_dbsuffix (from , ".pag"); + char *topag = gen_dbsuffix (to, ".pag"); + char *fromok = gen_dbsuffix(from, ".ok"); + long trans = kerb_start_update(to); + int ok = 0; + + if ((rename (fromdir, todir) == 0) + && (rename (frompag, topag) == 0)) { + (void) unlink (fromok); + ok = 1; + } + + free (fromok); + free (fromdir); + free (todir); + free (frompag); + free (topag); + if (ok) + return kerb_end_update(to, trans); + else + return -1; +} + +/* + * look up a principal in the data base returns number of principals + * found, and whether there were more than requested. + */ + +int kerb_db_get_principal(name, inst, principal, max, more) + char *name; /* could have wild card */ + char *inst; /* could have wild card */ + Principal *principal; + unsigned int max; /* max number of name structs to return */ + int *more; /* where there more than 'max' tuples? */ + +{ + int found = 0, code; + extern int errorproc(); + int wildp, wildi; + datum key, contents; + char testname[ANAME_SZ], testinst[INST_SZ]; + u_long trans; + int try; + DBM *db; + + if (!init) + kerb_db_init(); /* initialize database routines */ + + for (try = 0; try < KERB_DB_MAX_RETRY; try++) { + trans = kerb_start_read(); + + if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0) + return -1; + + db = dbm_open(current_db_name, O_RDONLY, 0600); + + *more = 0; + +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, + "%s: db_get_principal for %s %s max = %d", + progname, name, inst, max); +#endif + + wildp = !strcmp(name, "*"); + wildi = !strcmp(inst, "*"); + + if (!wildi && !wildp) { /* nothing's wild */ + encode_princ_key(&key, name, inst); + contents = dbm_fetch(db, key); + if (contents.dptr == NULL) { + found = 0; + goto done; + } + decode_princ_contents(&contents, principal); +#ifdef DEBUG + if (kerb_debug & 1) { + fprintf(stderr, "\t found %s %s p_n length %d t_n length %d\n", + principal->name, principal->instance, + strlen(principal->name), + strlen(principal->instance)); + } +#endif + found = 1; + goto done; + } + /* process wild cards by looping through entire database */ + + for (key = dbm_firstkey(db); key.dptr != NULL; + key = dbm_next(db, key)) { + decode_princ_key(&key, testname, testinst); + if ((wildp || !strcmp(testname, name)) && + (wildi || !strcmp(testinst, inst))) { /* have a match */ + if (found >= max) { + *more = 1; + goto done; + } else { + found++; + contents = dbm_fetch(db, key); + decode_princ_contents(&contents, principal); +#ifdef DEBUG + if (kerb_debug & 1) { + fprintf(stderr, + "\tfound %s %s p_n length %d t_n length %d\n", + principal->name, principal->instance, + strlen(principal->name), + strlen(principal->instance)); + } +#endif + principal++; /* point to next */ + } + } + } + + done: + kerb_dbl_unlock(); /* unlock read lock */ + dbm_close(db); + if (kerb_end_read(trans) == 0) + break; + found = -1; + if (!non_blocking) + sleep(1); + } + return (found); +} + +/* + * delete a principal from the data base returns number of principals + * found, and whether there were more than requested. + */ + +int kerb_db_del_principal(principal, n) + Principal *principal; + int n; +{ + int found = 0, code; + DBM *db; + u_long trans; + int try; + datum key; + + if (!init) + kerb_db_init(); /* initialize database routines */ + + for (try = 0; try < KERB_DB_MAX_RETRY; try++) { + trans = kerb_start_read(); + + if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0) + return -1; + + db = dbm_open(current_db_name, O_RDWR, 0600); + + encode_princ_key(&key, principal->name, principal->instance); + if (!dbm_delete(db, key)) { + found = 1; + } else { + krb_log("kerb_db_del_principal failed on %s %s <%s>", + principal->name, principal->instance, key.dptr); + } + + kerb_dbl_unlock(); /* unlock read lock */ + dbm_close(db); + if (kerb_end_read(trans) == 0) + break; + if (found) break; + found = -1; + if (!non_blocking) + sleep(1); + } + return (found); +} + +/* + * Update a name in the data base. Returns number of names + * successfully updated. + */ + +int kerb_db_put_principal(principal, max) + Principal *principal; + unsigned int max; /* number of principal structs to + * update */ + +{ + int found = 0, code; + u_long i; + extern int errorproc(); + datum key, contents; + DBM *db; + + gettimeofday(×tamp, NULL); + + if (!init) + kerb_db_init(); + + if ((code = kerb_dbl_lock(KERB_DBL_EXCLUSIVE)) != 0) + return -1; + + db = dbm_open(current_db_name, O_RDWR, 0600); + +#ifdef DEBUG + if (kerb_debug & 2) + fprintf(stderr, "%s: kerb_db_put_principal max = %d", + progname, max); +#endif + + /* for each one, stuff temps, and do replace/append */ + for (i = 0; i < max; i++) { + encode_princ_contents(&contents, principal); + encode_princ_key(&key, principal->name, principal->instance); + dbm_store(db, key, contents, DBM_REPLACE); +#ifdef DEBUG + if (kerb_debug & 1) { + fprintf(stderr, "\n put %s %s\n", + principal->name, principal->instance); + } +#endif + found++; + principal++; /* bump to next struct */ + } + + dbm_close(db); + kerb_dbl_unlock(); /* unlock database */ + return (found); +} + +static void +encode_princ_key(key, name, instance) + datum *key; + char *name, *instance; +{ + static char keystring[ANAME_SZ + INST_SZ]; + + memset(keystring, 0, ANAME_SZ + INST_SZ); + strncpy(keystring, name, ANAME_SZ); + strncpy(&keystring[ANAME_SZ], instance, INST_SZ); + key->dptr = keystring; + key->dsize = ANAME_SZ + INST_SZ; +} + +static void +decode_princ_key(key, name, instance) + datum *key; + char *name, *instance; +{ + strncpy(name, key->dptr, ANAME_SZ); + strncpy(instance, key->dptr + ANAME_SZ, INST_SZ); + name[ANAME_SZ - 1] = '\0'; + instance[INST_SZ - 1] = '\0'; +} + +static void +encode_princ_contents(contents, principal) + datum *contents; + Principal *principal; +{ + contents->dsize = sizeof(*principal); + contents->dptr = (char *) principal; +} + +static void +decode_princ_contents(contents, principal) + datum *contents; + Principal *principal; +{ + memcpy((char *) principal, contents->dptr, sizeof(*principal)); +} + +kerb_db_get_stat(s) + DB_stat *s; +{ + gettimeofday(×tamp, NULL); + + + s->cpu = 0; + s->elapsed = 0; + s->dio = 0; + s->pfault = 0; + s->t_stamp = timestamp.tv_sec; + s->n_retrieve = 0; + s->n_replace = 0; + s->n_append = 0; + s->n_get_stat = 0; + s->n_put_stat = 0; + /* update local copy too */ +} + +kerb_db_put_stat(s) + DB_stat *s; +{ +} + +delta_stat(a, b, c) + DB_stat *a, *b, *c; +{ + /* c = a - b then b = a for the next time */ + + c->cpu = a->cpu - b->cpu; + c->elapsed = a->elapsed - b->elapsed; + c->dio = a->dio - b->dio; + c->pfault = a->pfault - b->pfault; + c->t_stamp = a->t_stamp - b->t_stamp; + c->n_retrieve = a->n_retrieve - b->n_retrieve; + c->n_replace = a->n_replace - b->n_replace; + c->n_append = a->n_append - b->n_append; + c->n_get_stat = a->n_get_stat - b->n_get_stat; + c->n_put_stat = a->n_put_stat - b->n_put_stat; + + memcpy(b, a, sizeof(DB_stat)); + return; +} + +/* + * look up a dba in the data base returns number of dbas found , and + * whether there were more than requested. + */ + +int kerb_db_get_dba(dba_name, dba_inst, dba, max, more) + char *dba_name; /* could have wild card */ + char *dba_inst; /* could have wild card */ + Dba *dba; + unsigned int max; /* max number of name structs to return */ + int *more; /* where there more than 'max' tuples? */ + +{ + *more = 0; + return (0); +} + +int kerb_db_iterate (func, arg) + int (*func)(); + char *arg; /* void *, really */ +{ + datum key, contents; + Principal *principal; + int code; + DBM *db; + + kerb_db_init(); /* initialize and open the database */ + if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0) + return code; + + db = dbm_open(current_db_name, O_RDONLY, 0600); + + for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_next(db, key)) { + contents = dbm_fetch (db, key); + /* XXX may not be properly aligned */ + principal = (Principal *) contents.dptr; + if ((code = (*func)(arg, principal)) != 0) + return code; + } + dbm_close(db); + kerb_dbl_unlock(); + return 0; +} + +static int dblfd = -1; +static int mylock = 0; +static int inited = 0; + +static int kerb_dbl_init() +{ + if (!inited) { + char *filename = gen_dbsuffix (current_db_name, ".ok"); + if ((dblfd = open(filename, O_RDWR)) < 0) { + fprintf(stderr, "kerb_dbl_init: couldn't open %s\n", filename); + fflush(stderr); + perror("open"); + exit(1); + } + free(filename); + inited++; + } + return (0); +} + +static void kerb_dbl_fini() +{ + close(dblfd); + dblfd = -1; + inited = 0; + mylock = 0; +} + +static int kerb_dbl_lock(mode) + int mode; +{ +#ifdef POSIX + struct flock f; + int rv; +#else + int flock_mode; +#endif + + if (!inited) + kerb_dbl_init(); + if (mylock) { /* Detect lock call when lock already + * locked */ + fprintf(stderr, "Kerberos locking error (mylock)\n"); + fflush(stderr); + exit(1); + } +#ifdef POSIX + memset(&f, 0, sizeof(f)); +#endif + + switch (mode) { + case KERB_DBL_EXCLUSIVE: +#ifdef POSIX + f.l_type = F_WRLCK; +#else + flock_mode = LOCK_EX; +#endif + break; + + case KERB_DBL_SHARED: +#ifdef POSIX + f.l_type = F_RDLCK; +#else + flock_mode = LOCK_SH; +#endif + break; + + default: + fprintf(stderr, "invalid lock mode %d\n", mode); + abort(); + } + +#ifdef POSIX + if (non_blocking) + rv = fcntl (dblfd, F_SETLK, &f); + else + rv = fcntl (dblfd, F_SETLKW, &f); + if (rv == -1) + return errno; +#else + if (non_blocking) + flock_mode |= LOCK_NB; + if (flock(dblfd, flock_mode) < 0) + return errno; +#endif + + mylock++; + return 0; +} + +static void kerb_dbl_unlock() +{ +#ifdef POSIX + struct flock f; +#endif + + if (!mylock) { /* lock already unlocked */ + fprintf(stderr, "Kerberos database lock not locked when unlocking.\n"); + fflush(stderr); + exit(1); + } +#ifdef POSIX + memset(&f, 0, sizeof (f)); + f.l_type = F_UNLCK; + if (fcntl(dblfd, F_SETLK, &f) < 0) { + fprintf(stderr, "Kerberos database lock error. (unlocking)\n"); + fflush(stderr); + perror("fcntl"); + exit(1); + } +#else + if (flock(dblfd, LOCK_UN) < 0) { + fprintf(stderr, "Kerberos database lock error. (unlocking)\n"); + fflush(stderr); + perror("flock"); + exit(1); + } +#endif + mylock = 0; +} + +int kerb_db_set_lockmode(mode) + int mode; +{ + int old = non_blocking; + non_blocking = mode; + return old; +} diff --git a/src/lib/kdb4/krb_kdb_utils.c b/src/lib/kdb4/krb_kdb_utils.c new file mode 100644 index 000000000..9421b30c6 --- /dev/null +++ b/src/lib/kdb4/krb_kdb_utils.c @@ -0,0 +1,154 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * Utility routines for Kerberos programs which directly access + * the database. This code was duplicated in too many places + * before I gathered it here. + * + * Jon Rochlis, MIT Telecom, March 1988 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NEED_SYS_FCNTL_H +/* just for O_* for sco */ +#include +#endif + +long kdb_get_master_key_from(prompt, master_key, master_key_sched, verify, + kfilename) + int prompt; + C_Block master_key; + Key_schedule master_key_sched; + int verify; + char *kfilename; +{ + int kfile; + + if (prompt) { +#ifdef NOENCRYPTION + placebo_read_password(master_key, + "Kerberos master key: ", verify); +#else + des_read_password(master_key, + "Kerberos master key: ", verify); +#endif + printf ("\n"); + } + else { + kfile = open(kfilename?kfilename:MKEYFILE, O_RDONLY, 0600); + if (kfile < 0) { + /* oh, for com_err_ */ + return (-1); + } + if (read(kfile, (char *) master_key, 8) != 8) { + return (-1); + } + close(kfile); + } + +#ifndef NOENCRYPTION + key_sched(master_key, master_key_sched); +#endif + return (0); +} + +long kdb_get_master_key(prompt, master_key, master_key_sched, verify) + int prompt; + C_Block master_key; + Key_schedule master_key_sched; + int verify; +{ + return kdb_get_master_key_from(prompt, master_key, master_key_sched, + verify, NULL); +} + +/* The caller is reasponsible for cleaning up the master key and sched, + even if we can't verify the master key */ + +/* Returns master key version if successful, otherwise -1 */ + +long kdb_verify_master_key (master_key, master_key_sched, out) + C_Block master_key; + Key_schedule master_key_sched; + FILE *out; /* setting this to non-null be do output */ +{ + C_Block key_from_db; + Principal principal_data[1]; + int n, more = 0; + long master_key_version; + + /* lookup the master key version */ + n = kerb_get_principal(KERB_M_NAME, KERB_M_INST, principal_data, + 1 /* only one please */, &more); + if ((n != 1) || more) { + if (out != (FILE *) NULL) + fprintf(out, + "verify_master_key: %s, %d found.\n", + "Kerberos error on master key version lookup", + n); + return (-1); + } + + master_key_version = (long) principal_data[0].key_version; + + /* set up the master key */ + if (out != (FILE *) NULL) /* should we punt this? */ + fprintf(out, "Current Kerberos master key version is %d.\n", + principal_data[0].kdc_key_ver); + + /* + * now use the master key to decrypt the key in the db, had better + * be the same! + */ + memcpy(key_from_db, &principal_data[0].key_low, sizeof(KRB4_32)); + memcpy(((KRB4_32 *) key_from_db) + 1, &principal_data[0].key_high, sizeof(KRB4_32)); + kdb_encrypt_key (key_from_db, key_from_db, + master_key, master_key_sched, DECRYPT); + + /* the decrypted database key had better equal the master key */ + n = memcmp((char *) master_key, (char *) key_from_db, + sizeof(master_key)); + /* this used to zero the master key here! */ + memset(key_from_db, 0, sizeof(key_from_db)); + memset(principal_data, 0, sizeof (principal_data)); + + if (n && (out != (FILE *) NULL)) { + fprintf(out, "\n\07\07verify_master_key: Invalid master key; "); + fprintf(out, "does not match database.\n"); + return (-1); + } + if (out != (FILE *) NULL) { + fprintf(out, "\nMaster key entered.\n"); + fflush(out); + } + + return (master_key_version); +} + +/* The old algorithm used the key schedule as the initial vector which + was byte order depedent ... */ + +kdb_encrypt_key (in, out, master_key, master_key_sched, e_d_flag) + C_Block in, out, master_key; + Key_schedule master_key_sched; + int e_d_flag; +{ + +#ifdef NOENCRYPTION + memcpy(out, in, sizeof(C_Block)); +#else + pcbc_encrypt((C_Block *)in, (C_Block *)out, (long) sizeof(C_Block), + master_key_sched, (C_Block *)master_key, e_d_flag); +#endif +} diff --git a/src/lib/kdb4/krb_lib.c b/src/lib/kdb4/krb_lib.c new file mode 100644 index 000000000..3203af789 --- /dev/null +++ b/src/lib/kdb4/krb_lib.c @@ -0,0 +1,269 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + */ + +#include +#include +#include +#include +#include +#ifdef NEED_TIME_H +#include +#else +#include +#endif +#ifdef NEED_SYS_TIME_H +/* for timeval */ +#include +#endif +#include +#include +#include +#include +#include + +#ifdef DEBUG +extern int debug; +extern char *progname; +long kerb_debug; +#endif + +static init = 0; + +/* + * initialization routine for data base + */ + +int +kerb_init() +{ +#ifdef DEBUG + if (!init) { + extern char *getenv (); + char *dbg = getenv("KERB_DBG"); + if (dbg) + sscanf(dbg, "%d", &kerb_debug); + init = 1; + } +#endif + kerb_db_init(); + +#ifdef CACHE + kerb_cache_init(); +#endif + + /* successful init, return 0, else errcode */ + return (0); +} + +/* + * finalization routine for database -- NOTE: MUST be called by any + * program using kerb_init. ALSO will have to be modified to finalize + * caches, if they're ever really implemented. + */ + +int +kerb_fini() +{ + kerb_db_fini(); + return 0; +} + +/* + * look up a principal in the cache or data base returns number of + * principals found + */ + +int +kerb_get_principal(name, inst, principal, max, more) + char *name; /* could have wild card */ + char *inst; /* could have wild card */ + Principal *principal; + unsigned int max; /* max number of name structs to return */ + int *more; /* more tuples than room for */ + +{ + int found = 0; +#ifdef CACHE + static int wild = 0; +#endif + if (!init) + kerb_init(); + +#ifdef DEBUG + if (kerb_debug & 1) + fprintf(stderr, "\n%s: kerb_get_principal for %s %s max = %d\n", + progname, name, inst, max); +#endif + + /* + * if this is a request including a wild card, have to go to db + * since the cache may not be exhaustive. + */ + + /* clear the principal area */ + memset((char *) principal, 0, max * sizeof(Principal)); + +#ifdef CACHE + /* + * so check to see if the name contains a wildcard "*" or "?", not + * preceeded by a backslash. + */ + wild = 0; + if (strchr(name, '*') || strchr(name, '?') || + strchr(inst, '*') || strchr(inst, '?')) + wild = 1; + + if (!wild) { + /* try the cache first */ + found = kerb_cache_get_principal(name, inst, principal, max, more); + if (found) + return (found); + } +#endif + /* If we didn't try cache, or it wasn't there, try db */ + found = kerb_db_get_principal(name, inst, principal, max, more); + /* try to insert principal(s) into cache if it was found */ +#ifdef CACHE + if (found) { + kerb_cache_put_principal(principal, found); + } +#endif + return (found); +} + +/* + * delete a principal from the data base returns number of + * principals deleted + */ + +int +kerb_del_principal(name, inst, principal, max, more) + char *name; /* could have wild card */ + char *inst; /* could have wild card */ + Principal *principal; + unsigned int max; /* max number of name structs to return */ + int *more; /* more tuples than room for */ + +{ + int found; + + if (!init) + kerb_init(); + + found = kerb_get_principal(name, inst, principal, max, more); + + if (found) { + found = kerb_db_del_principal(principal, found); + } + + return (found); +} + +/* principals */ +int kerb_put_principal(principal, n) + Principal *principal; + unsigned int n; /* number of principal structs to write */ +{ + struct tm *tp, *localtime(); + time_t mod_date; + + /* set mod date */ + principal->mod_date = mod_date = time((time_t *)0); + /* and mod date string */ + + tp = localtime(&mod_date); + (void) sprintf(principal->mod_date_txt, "%4d-%2d-%2d", + tp->tm_year > 1900 ? tp->tm_year : tp->tm_year + 1900, + tp->tm_mon + 1, tp->tm_mday); /* January is 0, not 1 */ +#ifdef DEBUG + if (kerb_debug & 1) { + int i; + fprintf(stderr, "\nkerb_put_principal..."); + for (i = 0; i < n; i++) { + krb_print_principal(&principal[i]); + } + } +#endif + /* write database */ + if (kerb_db_put_principal(principal, n) < 0) { +#ifdef DEBUG + if (kerb_debug & 1) + fprintf(stderr, "\n%s: kerb_db_put_principal err", progname); + /* watch out for cache */ +#endif + return -1; + } +#ifdef CACHE + /* write cache */ + if (!kerb_cache_put_principal(principal, n)) { +#ifdef DEBUG + if (kerb_debug & 1) + fprintf(stderr, "\n%s: kerb_cache_put_principal err", progname); +#endif + return -1; + } +#endif + return 0; +} + +int +kerb_get_dba(name, inst, dba, max, more) + char *name; /* could have wild card */ + char *inst; /* could have wild card */ + Dba *dba; + unsigned int max; /* max number of name structs to return */ + int *more; /* more tuples than room for */ + +{ + int found = 0; +#ifdef CACHE + static int wild = 0; +#endif + if (!init) + kerb_init(); + +#ifdef DEBUG + if (kerb_debug & 1) + fprintf(stderr, "\n%s: kerb_get_dba for %s %s max = %d\n", + progname, name, inst, max); +#endif + /* + * if this is a request including a wild card, have to go to db + * since the cache may not be exhaustive. + */ + + /* clear the dba area */ + memset((char *) dba, 0, max * sizeof(Dba)); + +#ifdef CACHE + /* + * so check to see if the name contains a wildcard "*" or "?", not + * preceeded by a backslash. + */ + + wild = 0; + if (strchr(name, '*') || strchr(name, '?') || + strchr(inst, '*') || strchr(inst, '?')) + wild = 1; + + if (!wild) { + /* try the cache first */ + found = kerb_cache_get_dba(name, inst, dba, max, more); + if (found) + return (found); + } +#endif + /* If we didn't try cache, or it wasn't there, try db */ + found = kerb_db_get_dba(name, inst, dba, max, more); +#ifdef CACHE + /* try to insert dba(s) into cache if it was found */ + if (found) { + kerb_cache_put_dba(dba, found); + } +#endif + return (found); +} diff --git a/src/lib/kdb4/print_princ.c b/src/lib/kdb4/print_princ.c new file mode 100644 index 000000000..9c47ddf96 --- /dev/null +++ b/src/lib/kdb4/print_princ.c @@ -0,0 +1,46 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + */ + +#include +#include +#include +#ifdef NEED_TIME_H +#include +#endif +#include +#include +#include +#include + +extern int debug; +extern struct tm *localtime(); +struct tm *time_p; + +long kerb_debug; + +krb_print_principal(a_n) + Principal *a_n; +{ + /* run-time database does not contain string versions */ + time_t exp_date = a_n->exp_date; + time_p = localtime(&exp_date); + + fprintf(stderr, + "\n%s %s expires %4d-%2d-%2d %2d:%2d, max_life %d*5 = %d min attr 0x%02x", + a_n->name, a_n->instance, + time_p->tm_year > 1900 ? time_p->tm_year : time_p->tm_year + 1900, + time_p->tm_mon + 1, time_p->tm_mday, + time_p->tm_hour, time_p->tm_min, + a_n->max_life, 5 * a_n->max_life, a_n->attributes); + + fprintf(stderr, + "\n\tkey_ver %d k_low 0x%08x k_high 0x%08x akv %d exists %d\n", + a_n->key_version, a_n->key_low, a_n->key_high, + a_n->kdc_key_ver, a_n->old); + + fflush(stderr); +}