diff options
Diffstat (limited to 'src/lib/kdb')
34 files changed, 5044 insertions, 1740 deletions
diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog index 99e6b58..740cef0 100644 --- a/src/lib/kdb/ChangeLog +++ b/src/lib/kdb/ChangeLog @@ -1,3 +1,30 @@ +2005-06-20 Ken Raeburn <raeburn@mit.edu> + + Novell merge. + * Makefile.in: + * adb_err.et: + * configure.in: + * decrypt_key.c: + * encrypt_key.c: + * err_handle.c: + * err_handle.h: + * fetch_mkey.c: + * kdb5.c: + * kdb5.h: + * kdb_compat.h: + * kdb_cpw.c: + * kdb_db2.c: + * kdb_db2.h: + * kdb_default.c: + * kdb_xdr.c: + * keytab.c: + * libkrb5.exports: + * setup_mkey.c: + * store_mkey.c: + * t_kdb.c: + * t_krb5.conf: + * verify_mky.c: + 2005-06-09 Ken Raeburn <raeburn@mit.edu> * kdb_dbm.c: Unused file deleted. diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index 396ce1e..84c94c2 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -6,6 +6,8 @@ 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) +CFLAGS=@CFLAGS@ -DKDB5_USE_LIB_KDB_DB2 +LOCALINCLUDES= -I. LIBBASE=kdb5 LIBMAJOR=4 @@ -29,30 +31,29 @@ DBOBJLISTS-k5 = $(DBDIR)/hash/OBJS.ST $(DBDIR)/btree/OBJS.ST \ all:: +adb_err.$(OBJEXT): adb_err.c +adb_err.c adb_err.h: $(srcdir)/adb_err.et + SRCS= \ - $(srcdir)/keytab.c \ + $(srcdir)/kdb5.c \ $(srcdir)/encrypt_key.c \ $(srcdir)/decrypt_key.c \ + $(srcdir)/kdb_default.c \ $(srcdir)/kdb_cpw.c \ - $(srcdir)/kdb_db2.c \ - $(srcdir)/kdb_xdr.c \ - $(srcdir)/verify_mky.c \ - $(srcdir)/fetch_mkey.c \ - $(srcdir)/setup_mkey.c \ - $(srcdir)/store_mkey.c + adb_err.c \ + $(srcdir)/err_handle.c \ + $(srcdir)/keytab.c STOBJLISTS=OBJS.ST $(DBOBJLISTS) STLIBOBJS= \ - keytab.o \ + kdb5.o \ encrypt_key.o \ decrypt_key.o \ + kdb_default.o \ kdb_cpw.o \ - kdb_db2.o \ - kdb_xdr.o \ - verify_mky.o \ - fetch_mkey.o \ - setup_mkey.o \ - store_mkey.o + adb_err.o \ + err_handle.o \ + keytab.o all-unix:: all-liblinks install-unix:: install-libs @@ -78,14 +79,14 @@ clean:: # Makefile dependencies follow. This must be the last section in # the Makefile.in file # -keytab.so keytab.po $(OUTPRE)keytab.$(OBJEXT): keytab.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 \ - $(SRCTOP)/include/krb5/kdb_kt.h $(SRCTOP)/include/krb5/kdb.h +kdb5.so kdb5.po $(OUTPRE)kdb5.$(OBJEXT): kdb5.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 $(BUILDTOP)/include/krb5/osconf.h \ + kdb5.h err_handle.h ./adb_err.h encrypt_key.so encrypt_key.po $(OUTPRE)encrypt_key.$(OBJEXT): \ encrypt_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \ $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \ @@ -100,54 +101,35 @@ decrypt_key.so decrypt_key.po $(OUTPRE)decrypt_key.$(OBJEXT): \ $(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_cpw.so kdb_cpw.po $(OUTPRE)kdb_cpw.$(OBJEXT): kdb_cpw.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 \ - $(SRCTOP)/include/krb5/adm.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) kdb_compat.h kdb_db2.h -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 -verify_mky.so verify_mky.po $(OUTPRE)verify_mky.$(OBJEXT): \ - verify_mky.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 -fetch_mkey.so fetch_mkey.po $(OUTPRE)fetch_mkey.$(OBJEXT): \ - fetch_mkey.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \ +kdb_default.so kdb_default.po $(OUTPRE)kdb_default.$(OBJEXT): \ + kdb_default.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 -setup_mkey.so setup_mkey.po $(OUTPRE)setup_mkey.$(OBJEXT): \ - setup_mkey.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \ +kdb_cpw.so kdb_cpw.po $(OUTPRE)kdb_cpw.$(OBJEXT): kdb_cpw.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 -store_mkey.so store_mkey.po $(OUTPRE)store_mkey.$(OBJEXT): \ - store_mkey.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \ +adb_err.so adb_err.po $(OUTPRE)adb_err.$(OBJEXT): adb_err.c \ + $(COM_ERR_DEPS) +err_handle.so err_handle.po $(OUTPRE)err_handle.$(OBJEXT): \ + err_handle.c err_handle.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 +keytab.so keytab.po $(OUTPRE)keytab.$(OBJEXT): keytab.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 + $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \ + $(SRCTOP)/include/krb5/kdb_kt.h $(SRCTOP)/include/krb5/kdb.h diff --git a/src/lib/kdb/adb_err.et b/src/lib/kdb/adb_err.et new file mode 100644 index 0000000..3948025 --- /dev/null +++ b/src/lib/kdb/adb_err.et @@ -0,0 +1,16 @@ +error_table adb +error_code OSA_ADB_NOERR, "No Error" +error_code OSA_ADB_DUP, "Principal or policy already exists" +error_code OSA_ADB_NOENT, "Principal or policy does not exist" +error_code OSA_ADB_DBINIT, "Database not initialized" +error_code OSA_ADB_BAD_POLICY, "Invalid policy name" +error_code OSA_ADB_BAD_PRINC, "Invalid principal name" +error_code OSA_ADB_BAD_DB, "Database inconsistency detected" +error_code OSA_ADB_XDR_FAILURE, "XDR encoding error" +error_code OSA_ADB_FAILURE, "Failure!" +error_code OSA_ADB_BADLOCKMODE, "Bad lock mode" +error_code OSA_ADB_CANTLOCK_DB, "Cannot lock database" +error_code OSA_ADB_NOTLOCKED, "Database not locked" +error_code OSA_ADB_NOLOCKFILE, "KADM5 administration database lock file missing" +error_code OSA_ADB_NOEXCL_PERM, "Insufficient permission to lock file" +end diff --git a/src/lib/kdb/configure.in b/src/lib/kdb/configure.in index dc002d8..4f06b32 100644 --- a/src/lib/kdb/configure.in +++ b/src/lib/kdb/configure.in @@ -4,6 +4,7 @@ AC_CHECK_HEADERS(unistd.h) AC_TYPE_MODE_T AC_TYPE_OFF_T +AC_CHECK_HEADERS(pthread.h) AC_CHECK_FUNCS(srand48 srand srandom umask) dnl AIX is unusual in that it wants all symbols resolved at link time @@ -19,4 +20,5 @@ dnl The following is for check... KRB5_BUILD_PROGRAM KRB5_BUILD_LIBOBJS KRB5_BUILD_LIBRARY_WITH_DEPS -V5_AC_OUTPUT_MAKEFILE +AC_CONFIG_SUBDIRS(kdb_db2) +V5_AC_OUTPUT_MAKEFILE(. kdb_db2) diff --git a/src/lib/kdb/decrypt_key.c b/src/lib/kdb/decrypt_key.c index 765e6f3..53d02ff 100644 --- a/src/lib/kdb/decrypt_key.c +++ b/src/lib/kdb/decrypt_key.c @@ -62,12 +62,11 @@ */ krb5_error_code -krb5_dbekd_decrypt_key_data(context, mkey, key_data, dbkey, keysalt) - krb5_context context; - const krb5_keyblock * mkey; - const krb5_key_data * key_data; - krb5_keyblock * dbkey; - krb5_keysalt * keysalt; +krb5_dbekd_decrypt_key_data( krb5_context context, + const krb5_keyblock * mkey, + const krb5_key_data * key_data, + krb5_keyblock * dbkey, + krb5_keysalt * keysalt) { krb5_error_code retval = 0; krb5_int16 tmplen; diff --git a/src/lib/kdb/encrypt_key.c b/src/lib/kdb/encrypt_key.c index aa259f9..13686a4 100644 --- a/src/lib/kdb/encrypt_key.c +++ b/src/lib/kdb/encrypt_key.c @@ -62,13 +62,12 @@ */ krb5_error_code -krb5_dbekd_encrypt_key_data(context, mkey, dbkey, keysalt, keyver, key_data) - krb5_context context; - const krb5_keyblock * mkey; - const krb5_keyblock * dbkey; - const krb5_keysalt * keysalt; - int keyver; - krb5_key_data * key_data; +krb5_dbekd_encrypt_key_data( krb5_context context, + const krb5_keyblock * mkey, + const krb5_keyblock * dbkey, + const krb5_keysalt * keysalt, + int keyver, + krb5_key_data * key_data) { krb5_error_code retval; krb5_octet * ptr; diff --git a/src/lib/kdb/err_handle.c b/src/lib/kdb/err_handle.c new file mode 100644 index 0000000..7d54441 --- /dev/null +++ b/src/lib/kdb/err_handle.c @@ -0,0 +1,193 @@ +/********************************************************************** +* +* C %name: err_handle.c % +* Instance: idc_sec_1 +* Description: +* %created_by: spradeep % +* %date_created: Thu Apr 7 14:05:00 2005 % +* +**********************************************************************/ +#ifndef lint +static char *_csrc = "@(#) %filespec: err_handle.c~1 % (%full_filespec: err_handle.c~1:csrc:idc_sec#1 %)"; +#endif + +/* This file should be ideally be in util/et. But, for now thread + safety requirement stops me from putting there. if I do, then all + the applications have to link to pthread. */ + +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif +#include "err_handle.h" +#include <assert.h> + +#ifdef NOVELL +krb5_errcode_2_string_func old_error_2_string = NULL; +#endif + +typedef struct { + char krb5_err_str[KRB5_MAX_ERR_STR + 1]; + long err_code; + krb5_err_subsystem subsystem; + krb5_context kcontext; +} krb5_err_struct_t; + +#ifdef HAVE_PTHREAD_H +static void tsd_key_destructor(void *data) +{ + free(data); +} + +static pthread_key_t krb5_err_key; + +static void init_err_handling( void ) +{ + assert(!pthread_key_create(&krb5_err_key, tsd_key_destructor)); +#ifdef NOVELL + old_error_2_string = error_message; + error_message = krb5_get_err_string; +#endif +} + +static pthread_once_t krb5_key_create = PTHREAD_ONCE_INIT; + +krb5_error_code krb5_set_err( krb5_context kcontext, krb5_err_subsystem subsystem, long err_code, char *str ) +{ + int ret; + krb5_err_struct_t *err_struct; + pthread_once(&krb5_key_create, init_err_handling); + + err_struct = (krb5_err_struct_t*) pthread_getspecific(krb5_err_key); + if( err_struct == NULL ) + { + err_struct = calloc(sizeof(krb5_err_struct_t), 1); + if( err_struct == NULL ) + return ENOMEM; + + if((ret = pthread_setspecific(krb5_err_key, err_struct))) + { + free( err_struct ); + return ret; + } + } + + err_struct->subsystem = subsystem; + err_struct->err_code = err_code; + err_struct->kcontext = kcontext; + if( err_struct->subsystem == krb5_err_have_str ) + { + strncpy( err_struct->krb5_err_str, str, sizeof(err_struct->krb5_err_str) ); + err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0'; + } + + return 0; +} + +const char * KRB5_CALLCONV krb5_get_err_string(long err_code) +{ + krb5_err_struct_t *err_struct; + pthread_once(&krb5_key_create, init_err_handling); + + err_struct = (krb5_err_struct_t*) pthread_getspecific(krb5_err_key); + if( err_struct && (err_struct->subsystem == krb5_err_have_str) && (err_code == err_struct->err_code) ) + { + /* checking error code is for safety. + In case, the caller ignores a database error and calls other calls before doing com_err. + Though not perfect, caller should call krb5_clr_error before this*/ + err_struct->subsystem = krb5_err_unknown; + return err_struct->krb5_err_str; + } + + if( err_struct && (err_struct->subsystem == krb5_err_db) && (err_code == err_struct->err_code) ) + { + err_struct->subsystem = krb5_err_unknown; + return krb5_db_errcode2string(err_struct->kcontext, err_code); + } + + /* Error strings are not generated here. the remaining two cases are handled by the default error string convertor */ +#ifdef NOVELL + return old_error_2_string(err_code); +#else + return error_message (err_code); +#endif +} + +void krb5_clr_error() +{ + krb5_err_struct_t *err_struct; + pthread_once(&krb5_key_create, init_err_handling); + + err_struct = (krb5_err_struct_t*) pthread_getspecific(krb5_err_key); + if( err_struct ) + err_struct->subsystem = krb5_err_unknown; +} + +#else +krb5_err_struct_t krb5_err = {{0}, 0, 0, 0}; +krb5_boolean krb5_init_once = TRUE; + +static void init_err_handling( void ) +{ + if( krb5_init_once ) + { + old_error_2_string = error_message; + error_message = krb5_get_err_string; + krb5_init_once = FALSE; + } +} + +krb5_error_code krb5_set_err( krb5_context kcontext, krb5_err_subsystem subsystem, long err_code, char *str ) +{ + krb5_err_struct_t *err_struct = &krb5_err; + + init_err_handling(); /* takes care for multiple inits */ + + err_struct->subsystem = subsystem; + err_struct->err_code = err_code; + err_struct->kcontext = kcontext; + if( err_struct->subsystem == krb5_err_have_str ) + { + strncpy( err_struct->krb5_err_str, str, sizeof(err_struct->krb5_err_str) ); + err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0'; + } + + return 0; +} + +const char * KRB5_CALLCONV krb5_get_err_string(long err_code) +{ + krb5_err_struct_t *err_struct = &krb5_err; + + init_err_handling(); /* takes care for multiple inits */ + + if( (err_struct->subsystem == krb5_err_have_str) && (err_code == err_struct->err_code) ) + { + /* checking error code is for safety. + In case, the caller ignores a database error and calls other calls before doing com_err. + Though not perfect, caller should call krb5_clr_error before this*/ + err_struct->subsystem = krb5_err_unknown; + return err_struct->krb5_err_str; + } + + if( (err_struct->subsystem == krb5_err_db) && (err_code == err_struct->err_code) ) + { + err_struct->subsystem = krb5_err_unknown; + return krb5_db_errcode2string(err_struct->kcontext, err_code); + } + + /* it is not generated here. the remaining two cases are handled by the default error string convertor */ + return old_error_2_string(err_code); + +} + +void krb5_clr_error() +{ + krb5_err_struct_t *err_struct = &krb5_err; + + init_err_handling(); /* takes care for multiple inits */ + + err_struct->subsystem = krb5_err_unknown; +} + + +#endif diff --git a/src/lib/kdb/err_handle.h b/src/lib/kdb/err_handle.h new file mode 100644 index 0000000..e123afc --- /dev/null +++ b/src/lib/kdb/err_handle.h @@ -0,0 +1,32 @@ +/********************************************************************** +* +* C Header: err_handle.h +* Instance: idc_sec_1 +* Description: +* %created_by: spradeep % +* %date_created: Thu Apr 7 14:05:33 2005 % +* +**********************************************************************/ +#ifndef _idc_sec_1_err_handle_h_H +#define _idc_sec_1_err_handle_h_H +#include <k5-int.h> + +/* Everything else goes here */ + +#define KRB5_MAX_ERR_STR 1024 +typedef enum krb5_err_subsystem { krb5_err_unknown = 0, /* no error or unknown system. Has to be probed */ + krb5_err_system, /* error in system call */ + krb5_err_krblib, /* error in kerberos library call, should lookup in the error table */ + krb5_err_have_str, /* error message is available in the string */ + krb5_err_db /* error is a database error, should be handled by calling DB */ +} krb5_err_subsystem; + +typedef krb5_error_code (*krb5_set_err_func_t)( krb5_context, krb5_err_subsystem, long, char*); + +krb5_error_code krb5_set_err( krb5_context kcontext, krb5_err_subsystem subsystem, long err_code, char *str ); + +const char * KRB5_CALLCONV krb5_get_err_string(long err_code); + +void krb5_clr_error(void); + +#endif diff --git a/src/lib/kdb/fetch_mkey.c b/src/lib/kdb/fetch_mkey.c deleted file mode 100644 index 5d63b8c..0000000 --- a/src/lib/kdb/fetch_mkey.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * lib/kdb/fetch_mkey.c - * - * Copyright 1990 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. - * - * - * krb5_db_fetch_mkey(): - * Fetch a database master key from somewhere. - */ - -/* - * 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. - */ - -#include "k5-int.h" - -/* these are available to other funcs, and the pointers may be reassigned */ - -char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; -char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; - -/* - * Get the KDC database master key from somewhere, filling it into *key. - * - * key->enctype should be set to the desired key type. - * - * if fromkeyboard is TRUE, then the master key is read as a password - * from the user's terminal. In this case, - * eblock should point to a block with an appropriate string_to_key function. - * if twice is TRUE, the password is read twice for verification. - * - * mname is the name of the key sought; this can be used by the string_to_key - * function or by some other method to isolate the desired key. - * - */ - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -krb5_error_code -krb5_db_fetch_mkey(context, mname, etype, fromkeyboard, twice, keyfile, - salt, key) - krb5_context context; - krb5_principal mname; - krb5_enctype etype; - krb5_boolean fromkeyboard; - krb5_boolean twice; - char *keyfile; - krb5_data * salt; - krb5_keyblock * key; -{ - krb5_error_code retval; - char password[BUFSIZ]; - krb5_data pwd; - unsigned int size = sizeof(password); - - if (fromkeyboard) { - krb5_data scratch; - - if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, - twice ? krb5_mkey_pwd_prompt2 : 0, - password, &size))) - return(retval); - - pwd.data = password; - pwd.length = size; - if (!salt) { - retval = krb5_principal2salt(context, mname, &scratch); - if (retval) - return retval; - } - retval = krb5_c_string_to_key(context, etype, &pwd, salt?salt:&scratch, - key); - - if (!salt) - krb5_xfree(scratch.data); - memset(password, 0, sizeof(password)); /* erase it */ - return retval; - - } else { - /* from somewhere else */ - krb5_ui_2 enctype; - char defkeyfile[MAXPATHLEN+1]; - krb5_data *realm = krb5_princ_realm(context, mname); - FILE *kf; - - retval = 0; - key->magic = KV5M_KEYBLOCK; - (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB); - (void) strncat(defkeyfile, realm->data, - min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1, - realm->length)); - defkeyfile[sizeof(defkeyfile) - 1] = '\0'; - -#ifdef ANSI_STDIO - if (!(kf = fopen((keyfile) ? keyfile : defkeyfile, "rb"))) -#else - if (!(kf = fopen((keyfile) ? keyfile : defkeyfile, "r"))) -#endif - return KRB5_KDB_CANTREAD_STORED; - if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) { - retval = KRB5_KDB_CANTREAD_STORED; - goto errout; - } - if (key->enctype == ENCTYPE_UNKNOWN) - key->enctype = enctype; - else if (enctype != key->enctype) { - retval = KRB5_KDB_BADSTORED_MKEY; - goto errout; - } - if (fread((krb5_pointer) &key->length, - sizeof(key->length), 1, kf) != 1) { - retval = KRB5_KDB_CANTREAD_STORED; - goto errout; - } - if (!key->length || ((int) key->length) < 0) { - retval = KRB5_KDB_BADSTORED_MKEY; - goto errout; - } - - if (!(key->contents = (krb5_octet *)malloc(key->length))) { - retval = ENOMEM; - goto errout; - } - if (fread((krb5_pointer) key->contents, - sizeof(key->contents[0]), key->length, kf) - != key->length) { - retval = KRB5_KDB_CANTREAD_STORED; - memset(key->contents, 0, key->length); - free(key->contents); - key->contents = 0; - } else - retval = 0; - - errout: - (void) fclose(kf); - return retval; - } -} diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c new file mode 100644 index 0000000..c4afa1b --- /dev/null +++ b/src/lib/kdb/kdb5.c @@ -0,0 +1,2051 @@ +/* + * Include files + */ + +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <k5-int.h> +#include <osconf.h> +#include "kdb5.h" +#include <assert.h> + +/* currently DB2 policy related errors are exported from DAL. But other databases should set_err function to return string */ +#include "adb_err.h" + + +/* + * Type definitions + */ +#define KRB5_TL_DB_ARGS 0x7fff + +/* + * internal static variable + */ + +#ifdef HAVE_PTHREAD_H +/* static pthread_once_t db_inited = PTHREAD_ONCE_INIT; */ +static pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER; +#else +/* static int db_inited = 0; */ +#endif + + +#ifdef _KDB5_STATIC_LINK +#undef _KDB5_DYNAMIC_LINK +#else +#undef _KDB5_DYNAMIC_LINK +/* to avoid redefinition problem */ +#define _KDB5_DYNAMIC_LINK +#endif + + +static db_library lib_list; + +/* + * Helper Functions + */ +#ifdef HAVE_PTHREAD_H + +/* + * KNOWN ISSUES with locking: This code does not handle a scenario where a library is thread-safe for different DB contexts, + * but not with the same context. It locks the complete DB library. If this is not the scenario, then lock has to be moved from + * db_library to kdb5_dal_handle. For now doing a pessimistic locking. + * + * If any thread does a DB lock, all the other threads are barred from accessing DB using this context (infact library + * because of the previous defect). + * This is with the assumption that, DB's lock code will take care of excluding other processes/machines from + * using the DB. But there could be a scenario where access by some other thread using the same context might corrupt the database. + */ + +static int kdb_lock_list() +{ + return pthread_mutex_lock( &db_lock ); +} + +static int kdb_unlock_list() +{ + return pthread_mutex_unlock( &db_lock ); +} + +static int kdb_init_lib_lock( db_library lib ) +{ + krb5_error_code retval; + if( (retval= pthread_mutex_init( &lib->lib_lock, NULL ))) + { + return retval; + } + + lib->lock_holder = pthread_self(); + lib->excl = 0; + lib->recursive_cnt = 0; + + return pthread_cond_init( &lib->unlocked, NULL ); +} + +static int kdb_destroy_lib_lock ( db_library lib ) +{ + krb5_error_code retval; + if( (retval = pthread_mutex_destroy( &lib->lib_lock )) ) + { + return retval; + } + + return pthread_cond_destroy( &lib->unlocked ); +} + +static int kdb_lock_lib_lock( db_library lib, krb5_boolean exclusive ) +{ + /* since, handle locked by one thread should not allow another thread to continue */ + krb5_error_code retval = 0; + pthread_t myid = pthread_self(); + + if( (retval = pthread_mutex_lock( &lib->lib_lock )) ) + return retval; + + while( (exclusive && (lib->excl || lib->recursive_cnt)) || + (!pthread_equal(lib->lock_holder, myid) && !lib->vftabl.is_thread_safe && lib->recursive_cnt) ) + { + /* exclusive lock held or some one using lock when exclusive is requested or library not-re-entrent */ + if( (retval = pthread_cond_wait(&lib->unlocked, &lib->lib_lock)) ) + return retval; + } + + /* exclusive lock and recursive_cnt allow a thread to lock even it already holds a lock */ + if( exclusive ) + lib->excl++; + + lib->recursive_cnt++; + + lib->lock_holder = myid; + + return pthread_mutex_unlock( &lib->lib_lock ); +} + +static int kdb_unlock_lib_lock( db_library lib, krb5_boolean exclusive ) +{ + krb5_error_code retval = 0; + + if( (retval = pthread_mutex_lock( &lib->lib_lock )) ) + return retval; + + lib->recursive_cnt--; + if( exclusive ) + lib->excl--; + + if( (retval = pthread_cond_broadcast( &lib->unlocked )) ) + return retval; + + return pthread_mutex_unlock( &lib->lib_lock ); +} + +#else /* no PTHREAD */ + +/* program is not using pthread. So, threads wont be there. No need to lock */ +#define kdb_lock_list() 0 +#define kdb_unlock_list() 0 +#define kdb_init_lib_lock(a) 0 +#define kdb_destroy_lib_lock(a) 0 +#define kdb_lock_lib_lock(a, b) 0 +#define kdb_unlock_lib_lock(a, b) 0 + +#endif /* end of HAVE_PTHREAD_H */ + + +static char * kdb_get_conf_section( krb5_context kcontext ) +{ + krb5_error_code status = 0; + char *result = NULL; + char *value = NULL; + + /* profile has to be initialized. If profile is not initialized, expect nothing less than a crash */ + status = profile_get_string( kcontext->profile, KDB_REALM_SECTION, /* realms */ + kcontext->default_realm, KDB_MODULE_POINTER, /* under the realm name, database_module */ + kcontext->default_realm, /* default value is the realm name itself */ + &value ); + + if( status ) + { + /* some problem */ + result = strdup( kcontext->default_realm ); + /* let NULL be handled by the caller */ + } + else + { + result = strdup( value ); + /* free profile string */ + profile_release_string( value ); + } + + return result; +} + +static char * kdb_get_library_name( krb5_context kcontext ) +{ + krb5_error_code status = 0; + char *result = NULL; + char *value = NULL; + char *lib = NULL; + + status = profile_get_string( kcontext->profile, KDB_REALM_SECTION, /* realms */ + kcontext->default_realm, KDB_MODULE_POINTER, /* under the realm name, database_module */ + kcontext->default_realm, /* default value is the realm name itself */ + &value ); + if( status ) + { + goto clean_n_exit; + } + + /* we got the module section. Get the library name from the module */ + status = profile_get_string( kcontext->profile, KDB_MODULE_SECTION, + value, KDB_LIB_POINTER, + "kdb_db2", /* default to db2 */ + &lib ); + + if( status ) + { + goto clean_n_exit; + } + + result = strdup( lib ); + clean_n_exit: + if( value ) + { + /* free profile string */ + profile_release_string( value ); + } + + if( lib ) + { + /* free profile string */ + profile_release_string( lib ); + } + + if( status ) + { + /* any error default to db2 */ + result = strdup( "kdb_db2" ); + } + return result; +} + +static void kdb_setup_opt_functions ( db_library lib ) +{ + if ( lib->vftabl.set_master_key == NULL ) + { + lib->vftabl.set_master_key = kdb_def_set_mkey; + } + + if ( lib->vftabl.get_master_key == NULL ) + { + lib->vftabl.get_master_key = kdb_def_get_mkey; + } + + if( lib->vftabl.fetch_master_key == NULL ) + { + lib->vftabl.fetch_master_key = krb5_db_def_fetch_mkey; + } + + if( lib->vftabl.verify_master_key == NULL ) + { + lib->vftabl.verify_master_key = krb5_def_verify_master_key; + } + + if( lib->vftabl.dbe_search_enctype == NULL ) + { + lib->vftabl.dbe_search_enctype = krb5_dbe_def_search_enctype; + } + + if( lib->vftabl.db_change_pwd == NULL ) + { + lib->vftabl.db_change_pwd = krb5_dbe_def_cpw; + } + + if( lib->vftabl.store_master_key == NULL ) + { + lib->vftabl.store_master_key = krb5_def_store_mkey; + } +} + +static int kdb_db2_pol_err_loaded = 0; +#ifdef _KDB5_STATIC_LINK +#define DEF_SYMBOL(a) extern kdb_vftabl krb5_db_vftabl_ ## a +#define GET_SYMBOL(a) (krb5_db_vftabl_ ## a) +static krb5_error_code kdb_load_library( krb5_context kcontext, char *lib_name, db_library *lib ) +{ + krb5_error_code status; + void *vftabl_addr = NULL; + char buf[KRB5_MAX_ERR_STR]; + + if( !strcmp("kdb_db2", lib_name) && (kdb_db2_pol_err_loaded == 0) ) + { + initialize_adb_error_table(); + kdb_db2_pol_err_loaded = 1; + } + + *lib = calloc( (size_t)1, sizeof(**lib)); + if( *lib == NULL ) + { + status = ENOMEM; + goto clean_n_exit; + } + + status = kdb_init_lib_lock( *lib ); + if( status ) + { + goto clean_n_exit; + } + + strcpy( (*lib)->name, lib_name ); + +#if !defined(KDB5_USE_LIB_KDB_DB2) && !defined(KDB5_USE_LIB_TEST) +#error No database module defined +#endif + +#ifdef KDB5_USE_LIB_KDB_DB2 + if( strcmp( lib_name, "kdb_db2" ) == 0 ) + { + DEF_SYMBOL(kdb_db2); + vftabl_addr = (void*)& GET_SYMBOL(kdb_db2); + } + else +#endif +#ifdef KDB5_USE_LIB_TEST + if( strcmp( lib_name, "test" ) == 0 ) + { + DEF_SYMBOL(test); + vftabl_addr = (void*) &GET_SYMBOL(test); + } else +#endif + { + sprintf( buf, "Program not built to support %s database type\n", lib_name ); + status = -1; + krb5_db_set_err(kcontext, krb5_err_have_str, status, buf); + goto clean_n_exit; + } + + memcpy( &(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl)); + + kdb_setup_opt_functions( *lib ); + + if( (status=(*lib)->vftabl.init_library(krb5_set_err)) ) + { + /* ERROR. library not initialized cleanly */ + sprintf( buf, "%s library initialization failed, error code %ld\n", lib_name, status ); + status = -1; + krb5_db_set_err(kcontext, krb5_err_have_str, status, buf); + goto clean_n_exit; + } + + + clean_n_exit: + if( status ) + { + free(*lib), *lib = NULL; + } + return status; +} + +#else + +static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH; + +static krb5_error_code kdb_load_library( krb5_context kcontext, char *lib_name, db_library *lib ) +{ + krb5_error_code status = 0; + char dl_name[1024]; + int ndx; + void *vftabl_addr; + char *err_str = NULL; + + if( !strcmp("kdb_db2", lib_name) && (kdb_db2_pol_err_loaded == 0) ) + { + initialize_adb_error_table(); + kdb_db2_pol_err_loaded = 1; + } + + *lib = calloc( (size_t)1, sizeof(**lib)); + if( *lib == NULL ) + { + status = ENOMEM; + goto clean_n_exit; + } + + status = kdb_init_lib_lock( *lib ); + if( status ) + { + goto clean_n_exit; + } + + strcpy( (*lib)->name, lib_name ); + + for( ndx = 0; db_dl_location[ndx]; ndx++ ) + { + sprintf(dl_name, "%s/lib%s.so", db_dl_location[ndx], lib_name); + (*lib)->dl_handle = dlopen( dl_name, RTLD_NOW ); + if( (*lib)->dl_handle ) + { + /* found the module */ + sprintf( dl_name, "krb5_db_vftabl_%s", lib_name ); + + dlerror(); + vftabl_addr = dlsym( (*lib)->dl_handle, dl_name ); + if( vftabl_addr ) + { + memcpy( &(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl)); + + kdb_setup_opt_functions( *lib ); + + if( (status = (*lib)->vftabl.init_library(krb5_set_err)) ) + { + /* ERROR. library not initialized cleanly */ + goto clean_n_exit; + + } + } + else + { + status = -1; + krb5_set_err(kcontext, krb5_err_have_str, status, dlerror()); + goto clean_n_exit; + } + break; + } + else + { + /* set the error. Later if we find everything fine.. we will reset this */ + err_str = dlerror(); +/* fprintf(stderr, "Error loading library %s\n", t); */ + } + } + + if( ! (*lib)->dl_handle ) + { + /* library not found in the given list. Error str is already set */ + status = -1; + krb5_set_err(kcontext, krb5_err_have_str, status, err_str); + goto clean_n_exit; + } + + clean_n_exit: + if( status ) + { + if( *lib ) + { + kdb_destroy_lib_lock( *lib ); + if( (*lib)->dl_handle ) + { + dlclose( (*lib)->dl_handle ); + } + free(*lib); + *lib = NULL; + } + } + return status; +} + +#endif /* end of _KDB5_STATIC_LINK */ + +static krb5_error_code kdb_find_library( krb5_context kcontext, char *lib_name, db_library *lib) +{ + /* lock here so that no two threads try to do the same at the same time */ + krb5_error_code status = 0; + int locked = 0; + db_library curr_elt, prev_elt = NULL; + + if( (status = kdb_lock_list()) != 0 ) + { + goto clean_n_exit; + } + locked = 1; + + curr_elt = lib_list; + while ( curr_elt != NULL ) + { + if( strcmp( lib_name, curr_elt->name ) == 0 ) + { + *lib = curr_elt; + goto clean_n_exit; + } + prev_elt = curr_elt; + curr_elt = curr_elt->next; + } + + /* module not found. create and add to list */ + status = kdb_load_library( kcontext, lib_name, lib); + if( status ) + { + goto clean_n_exit; + } + + if( prev_elt ) + { + /* prev_elt points to the last element in the list */ + prev_elt->next = *lib; + (*lib)->prev = prev_elt; + } + else + { + lib_list = *lib; + } + + clean_n_exit: + if( *lib ) + { + (*lib)->reference_cnt++; + } + + if( locked ) + { + kdb_unlock_list(); + } + + return status; +} + + +static krb5_error_code kdb_free_library( db_library lib) +{ + krb5_error_code status = 0; + int locked = 0; + + if( (status = kdb_lock_list()) != 0 ) + { + goto clean_n_exit; + } + locked = 1; + + lib->reference_cnt--; + + if( lib->reference_cnt == 0 ) + { + status = lib->vftabl.fini_library(); + if( status ) + { + goto clean_n_exit; + } + + /* close the library */ + if( lib->dl_handle ) + { + dlclose( lib->dl_handle ); + } + + kdb_destroy_lib_lock( lib ); + + if( lib->prev == NULL ) + { + /* first element in the list */ + lib_list = lib->next; + } + else + { + lib->prev->next = lib->next; + } + + if( lib->next ) + { + lib->next->prev = lib->prev; + } + free(lib); + } + + clean_n_exit: + if( locked ) + { + kdb_unlock_list(); + } + + return status; +} + +static krb5_error_code kdb_setup_lib_handle( krb5_context kcontext ) +{ + char *library = NULL; + krb5_error_code status = 0; + db_library lib = NULL; + kdb5_dal_handle *dal_handle = NULL; + + dal_handle = calloc( (size_t)1, sizeof(kdb5_dal_handle) ); + if( dal_handle == NULL ) + { + status = ENOMEM; + goto clean_n_exit; + } + + library = kdb_get_library_name( kcontext ); + if( library == NULL ) + { + status = -1; + goto clean_n_exit; + } + + status = kdb_find_library( kcontext, library, &lib ); + if( status ) + { + goto clean_n_exit; + } + + dal_handle->lib_handle = lib; + kcontext->db_context = (void *) dal_handle; + + clean_n_exit: + free(library); + + if( status ) + { + free( dal_handle ); + if( lib ) + { + kdb_free_library( lib ); + } + } + + return status; +} + + +static krb5_error_code kdb_free_lib_handle( krb5_context kcontext ) +{ + krb5_error_code status = 0; + + status = kdb_free_library( ((kdb5_dal_handle *)kcontext->db_context)->lib_handle ); + if( status ) + { + goto clean_n_exit; + } + + free( kcontext->db_context ); + kcontext->db_context = NULL; + + clean_n_exit: + return status; +} + +/* + * External functions... DAL API + */ +void krb5_db_clr_error() +{ + krb5_clr_error(); +} + +krb5_error_code krb5_db_open( krb5_context kcontext, char **db_args, int mode ) +{ + krb5_error_code status = 0; + char *section = NULL; + kdb5_dal_handle *dal_handle; + char buf[KRB5_MAX_ERR_STR]; + + section = kdb_get_conf_section( kcontext ); + if( section == NULL ) + { + sprintf( buf, "unable to determine configuration section for realm %s\n", kcontext->default_realm ); + status = -1; + krb5_set_err(kcontext, krb5_err_have_str, status, buf); + goto clean_n_exit; + } + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.init_module(kcontext, section, db_args, mode ); + + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + if( section ) + free(section); + return status; +} + +const char * krb5_db_errcode2string ( krb5_context kcontext, long err_code ) +{ + const char *err_str = NULL; + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + err_str = dal_handle->lib_handle->vftabl.errcode_2_string(kcontext, err_code ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return err_str; +} + + +krb5_error_code krb5_db_inited ( krb5_context kcontext ) +{ + return !(kcontext && kcontext->db_context && + ((kdb5_dal_handle*)kcontext->db_context)->db_context); +} + +krb5_error_code krb5_db_create ( krb5_context kcontext, char **db_args ) +{ + krb5_error_code status = 0; + char *section = NULL; + kdb5_dal_handle *dal_handle; + char buf[KRB5_MAX_ERR_STR]; + + section = kdb_get_conf_section( kcontext ); + if( section == NULL ) + { + sprintf( buf, "unable to determine configuration section for realm %s\n", kcontext->default_realm ); + status = -1; + krb5_set_err(kcontext, krb5_err_have_str, status, buf); + goto clean_n_exit; + } + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_create(kcontext, section, db_args ); + + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + if( section ) + free(section); + return status; +} + +krb5_error_code krb5_db_fini ( krb5_context kcontext ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + /* module not loaded. So nothing to be done */ + goto clean_n_exit; + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.fini_module( kcontext ); + + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + if( status ) + { + goto clean_n_exit; + } + + status = kdb_free_lib_handle( kcontext ); + + clean_n_exit: + return status; +} + + +krb5_error_code krb5_db_destroy ( krb5_context kcontext, char **db_args ) +{ + krb5_error_code status = 0; + char * section = NULL; + kdb5_dal_handle *dal_handle; + char buf[KRB5_MAX_ERR_STR]; + + section = kdb_get_conf_section( kcontext ); + if( section == NULL ) + { + sprintf( buf, "unable to determine configuration section for realm %s\n", kcontext->default_realm ); + status = -1; + krb5_set_err(kcontext, krb5_err_have_str, status, buf); + goto clean_n_exit; + } + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_destroy(kcontext, section, db_args ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + if( section ) + free(section); + return status; +} + +krb5_error_code krb5_db_get_age ( krb5_context kcontext, char *db_name, time_t *t ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_get_age(kcontext, db_name, t ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_set_option ( krb5_context kcontext, int option, void *value ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_set_option(kcontext, option, value ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_lock ( krb5_context kcontext, int lock_mode ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + /* acquire an exclusive lock, ensures no other thread uses this context */ + status = kdb_lock_lib_lock( dal_handle->lib_handle, TRUE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_lock(kcontext, lock_mode ); + + /* exclusive lock is still held, so no other thread could use this context */ + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_unlock ( krb5_context kcontext ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + /* normal lock acquired and exclusive lock released */ + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_unlock( kcontext ); + + kdb_unlock_lib_lock( dal_handle->lib_handle, TRUE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_get_principal ( krb5_context kcontext, + krb5_const_principal search_for, + krb5_db_entry *entries, + int *nentries, + krb5_boolean *more ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_get_principal(kcontext, search_for, + entries, nentries, more); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_free_principal ( krb5_context kcontext, + krb5_db_entry *entry, + int count ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_free_principal( kcontext, entry, count ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + + +krb5_error_code krb5_db_put_principal ( krb5_context kcontext, + krb5_db_entry *entries, + int *nentries ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + char **db_args = NULL; + krb5_tl_data *prev, *curr, *next; + int db_args_size = 0; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + /* Giving db_args as part of tl data causes, db2 to store the tl_data as such. + To prevent this, tl_data is collated and passed as a sepearte argument. Currently supports only one principal. + but passing it as a seperate argument makes it difficult for kadmin remote to pass arguments to server */ + prev=NULL, curr=entries->tl_data; + while(curr) + { + if( curr->tl_data_type == KRB5_TL_DB_ARGS ) + { + char **t; + /* since this is expected to be NULL terminated string and this could come from any client, do a check + before passing it to db. */ + if( ((char*) curr->tl_data_contents)[curr->tl_data_length-1] != '\0' ) + { + /* not null terminated. Dangerous input */ + status = EINVAL; + goto clean_n_exit; + } + + db_args_size++; + t = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* 1 for NULL */ + if( t == NULL ) + { + status = ENOMEM; + goto clean_n_exit; + } + + db_args = t; + db_args[db_args_size-1] = (char*)curr->tl_data_contents; + db_args[db_args_size] = NULL; + + next = curr->tl_data_next; + if( prev == NULL ) + { + /* current node is the first in the linked list. remove it */ + entries->tl_data = curr->tl_data_next; + } + else + { + prev->tl_data_next = curr->tl_data_next; + } + entries->n_tl_data--; + krb5_db_free( kcontext, curr ); + + /* previous does not change */ + curr = next; + } + else + { + prev = curr; + curr = curr->tl_data_next; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_put_principal( kcontext, entries, + nentries, db_args ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + while( db_args_size ) + { + if( db_args[db_args_size-1] ) + krb5_db_free(kcontext, db_args[db_args_size-1]); + + db_args_size--; + } + + if( db_args ) + free(db_args); + + return status; +} + +krb5_error_code krb5_db_delete_principal ( krb5_context kcontext, + krb5_principal search_for, + int *nentries ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_delete_principal( kcontext, search_for, nentries ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_iterate ( krb5_context kcontext, + char *match_entry, + int (*func) (krb5_pointer, krb5_db_entry *), + krb5_pointer func_arg ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_iterate( kcontext, + match_entry, + func, + func_arg ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_supported_realms ( krb5_context kcontext, + char **realms ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_supported_realms( kcontext, realms ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_free_supported_realms ( krb5_context kcontext, + char **realms ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_free_supported_realms( kcontext, realms ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_set_master_key_ext ( krb5_context kcontext, + char *pwd, + krb5_keyblock *key ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.set_master_key( kcontext, + pwd, + key ); + + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_set_mkey ( krb5_context context, + krb5_keyblock *key) +{ + return krb5_db_set_master_key_ext ( context, NULL, key ); +} + + +krb5_error_code krb5_db_get_mkey ( krb5_context kcontext, + krb5_keyblock **key ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + /* lets use temp key and copy it later to avoid memory problems when freed by the caller */ + status = dal_handle->lib_handle->vftabl.get_master_key( kcontext, + key ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_store_master_key ( krb5_context kcontext, + char *db_arg, + krb5_principal mname, + krb5_keyblock *key, + char *master_pwd) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.store_master_key( kcontext, + db_arg, + mname, + key, + master_pwd); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + + +char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; +char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; + + +krb5_error_code krb5_db_fetch_mkey ( krb5_context context, + krb5_principal mname, + krb5_enctype etype, + krb5_boolean fromkeyboard, + krb5_boolean twice, + char *db_args, + krb5_data *salt, + krb5_keyblock *key) +{ + krb5_error_code retval; + char password[BUFSIZ]; + krb5_data pwd; + unsigned int size = sizeof(password); + int kvno; + krb5_keyblock tmp_key; + + memset( &tmp_key, 0, sizeof(tmp_key) ); + + if (fromkeyboard) { + krb5_data scratch; + + if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, + twice ? krb5_mkey_pwd_prompt2 : 0, + password, &size))) + { + goto clean_n_exit; + } + + pwd.data = password; + pwd.length = size; + if (!salt) { + retval = krb5_principal2salt(context, mname, &scratch); + if (retval) + goto clean_n_exit; + } + retval = krb5_c_string_to_key(context, etype, &pwd, salt?salt:&scratch, + key); + + if (!salt) + krb5_xfree(scratch.data); + memset(password, 0, sizeof(password)); /* erase it */ + + } else { + kdb5_dal_handle *dal_handle; + + if( context->db_context == NULL ) + { + retval = kdb_setup_lib_handle( context ); + if( retval ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) context->db_context; + retval = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( retval ) + { + goto clean_n_exit; + } + + tmp_key.enctype = key->enctype; + retval = dal_handle->lib_handle->vftabl.fetch_master_key( context, + mname, + &tmp_key, + &kvno, + db_args); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + if( retval ) + { + goto clean_n_exit; + } + + key->contents = malloc( tmp_key.length ); + if( key->contents == NULL ) + { + retval = ENOMEM; + goto clean_n_exit; + } + + key->magic = tmp_key.magic; + key->enctype = tmp_key.enctype; + key->length = tmp_key.length; + memcpy(key->contents, tmp_key.contents, tmp_key.length); + } + + clean_n_exit: + if( tmp_key.contents ) + { + memset( tmp_key.contents, 0, tmp_key.length ); + krb5_db_free( context, tmp_key.contents ); + } + return retval; +} + + +krb5_error_code krb5_db_verify_master_key ( krb5_context kcontext, + krb5_principal mprinc, + krb5_keyblock *mkey ) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.verify_master_key( kcontext, + mprinc, + mkey ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + + +void *krb5_db_alloc( krb5_context kcontext, + void *ptr, + size_t size ) +{ + krb5_error_code status; + kdb5_dal_handle *dal_handle; + void *new_ptr = NULL; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + + new_ptr = dal_handle->lib_handle->vftabl.db_alloc( kcontext, + ptr, + size ); + + clean_n_exit: + return new_ptr; +} + +void krb5_db_free( krb5_context kcontext, + void *ptr) +{ + krb5_error_code status; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + + dal_handle->lib_handle->vftabl.db_free( kcontext, + ptr ); + + clean_n_exit: + return; +} + +/* has to be modified */ + +krb5_error_code +krb5_dbe_find_enctype( 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 ); +} + + +krb5_error_code krb5_dbe_search_enctype ( krb5_context kcontext, + krb5_db_entry *dbentp, + krb5_int32 *start, + krb5_int32 ktype, + krb5_int32 stype, + krb5_int32 kvno, + krb5_key_data **kdatap) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.dbe_search_enctype( kcontext, + dbentp, + start, + ktype, + stype, + kvno, + kdatap ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + + +#define REALM_SEP_STRING "@" + +krb5_error_code +krb5_db_setup_mkey_name ( krb5_context context, + const char *keyname, + const char *realm, + char **fullname, + krb5_principal *principal) +{ + krb5_error_code retval; + size_t keylen; + size_t rlen = strlen(realm); + char *fname; + + if (!keyname) + keyname = KRB5_KDB_M_NAME; /* XXX external? */ + + keylen = strlen(keyname); + + fname = malloc(keylen+rlen+strlen(REALM_SEP_STRING)+1); + if (!fname) + return ENOMEM; + + strcpy(fname, keyname); + strcat(fname, REALM_SEP_STRING); + strcat(fname, realm); + + if ((retval = krb5_parse_name(context, fname, principal))) + return retval; + if (fullname) + *fullname = fname; + else + free(fname); + return 0; +} + + + + +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); +} + +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_create_key_data(context, entry) + krb5_context context; + krb5_db_entry * entry; +{ + if ((entry->key_data = + (krb5_key_data *) krb5_db_alloc(context, 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_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_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_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 = NULL; + krb5_octet * tmp; + + /* copy the new data first, so we can fail cleanly if malloc() + fails */ + if ((tmp = (krb5_octet *) krb5_db_alloc(context, NULL, 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 */ + + if( new_tl_data->tl_data_type != KRB5_TL_DB_ARGS ) /* db_args can be multiple */ + { + 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 *) krb5_db_alloc(context, NULL, sizeof(krb5_tl_data))) + == NULL) { + free(tmp); + return(ENOMEM); + } + memset( tl_data, 0, sizeof(krb5_tl_data)); + 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) + krb5_db_free(context, 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); +} + + + +/* change password functions */ +krb5_error_code +krb5_dbe_cpw( krb5_context kcontext, + krb5_keyblock * master_key, + krb5_key_salt_tuple * ks_tuple, + int ks_tuple_count, + char * passwd, + int new_kvno, + krb5_boolean keepold, + krb5_db_entry * db_entry) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_change_pwd( kcontext, + master_key, + ks_tuple, + ks_tuple_count, + passwd, + new_kvno, + keepold, + db_entry ); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + + +/* policy management functions */ +krb5_error_code krb5_db_create_policy( krb5_context kcontext, osa_policy_ent_t policy) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_get_policy ( krb5_context kcontext, char *name, osa_policy_ent_t *policy, int *cnt) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy, cnt); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_put_policy( krb5_context kcontext, osa_policy_ent_t policy) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_iter_policy( krb5_context kcontext, char *match_entry, osa_adb_iter_policy_func func, void *data) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry, func, data); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +krb5_error_code krb5_db_delete_policy( krb5_context kcontext, char *policy) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return status; +} + +void krb5_db_free_policy( krb5_context kcontext, osa_policy_ent_t policy) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + + if( kcontext->db_context == NULL ) + { + status = kdb_setup_lib_handle( kcontext ); + if( status ) + { + goto clean_n_exit; + } + } + + dal_handle = (kdb5_dal_handle *) kcontext->db_context; + status = kdb_lock_lib_lock( dal_handle->lib_handle, FALSE ); + if( status ) + { + goto clean_n_exit; + } + + dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy); + kdb_unlock_lib_lock( dal_handle->lib_handle, FALSE ); + + clean_n_exit: + return; +} + diff --git a/src/lib/kdb/kdb5.h b/src/lib/kdb/kdb5.h new file mode 100644 index 0000000..93b594a --- /dev/null +++ b/src/lib/kdb/kdb5.h @@ -0,0 +1,219 @@ +#ifndef _KRB5_KDB5_H_ +#define _KRB5_KDB5_H_ + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <utime.h> +#include <utime.h> +#include <k5-int.h> +#include "err_handle.h" + +#define KDB_MAX_DB_NAME 128 +#define KDB_REALM_SECTION "realms" +#define KDB_MODULE_POINTER "database_module" +#define KDB_MODULE_SECTION "db_modules" +#define KDB_LIB_POINTER "db_library" +#define KDB_DATABASE_CONF_FILE DEFAULT_SECURE_PROFILE_PATH +#define KDB_DATABASE_ENV_PROF KDC_PROFILE_ENV + +#define KRB5_KDB_OPEN_RW 0 +#define KRB5_KDB_OPEN_RO 1 + +#define KRB5_KDB_OPT_SET_DB_NAME 0 +#define KRB5_KDB_OPT_SET_LOCK_MODE 1 + +#define KRB5_DB_GET_DB_CONTEXT(kcontext) ( ((kdb5_dal_handle*) (kcontext)->db_context)->db_context ) +#define KRB5_DB_GET_PROFILE(kcontext) ( (kcontext)->profile ) +#define KRB5_DB_GET_REALM(kcontext) ( (kcontext)->default_realm ) + +#ifndef KRB5_DB_LOCKMODE_SHARED +#define KRB5_DB_LOCKMODE_SHARED 0x0001 +#endif + +#ifndef KRB5_DB_LOCKMODE_EXCLUSIVE +#define KRB5_DB_LOCKMODE_EXCLUSIVE 0x0002 +#endif + +#ifndef KRB5_DB_LOCKMODE_DONTBLOCK +#define KRB5_DB_LOCKMODE_DONTBLOCK 0x0004 +#endif + +#ifndef KRB5_DB_LOCKMODE_PERMANENT +#define KRB5_DB_LOCKMODE_PERMANENT 0x0008 +#endif + +typedef struct _kdb_vftabl{ + short int maj_ver; + short int min_ver; + + short int is_thread_safe; + + krb5_error_code (*init_library)(krb5_set_err_func_t); + krb5_error_code (*fini_library)(); + krb5_error_code (*init_module) ( krb5_context kcontext, + char * conf_section, + char ** db_args, + int mode ); + + krb5_error_code (*fini_module) ( krb5_context kcontext ); + + krb5_error_code (*db_create) ( krb5_context kcontext, + char * conf_section, + char ** db_args ); + + krb5_error_code (*db_destroy) ( krb5_context kcontext, + char *conf_section, + char ** db_args ); + + krb5_error_code (*db_get_age) ( krb5_context kcontext, + char *db_name, + time_t *age ); + + krb5_error_code (*db_set_option) ( krb5_context kcontext, + int option, + void *value ); + + krb5_error_code (*db_lock) ( krb5_context kcontext, + int mode ); + + krb5_error_code (*db_unlock) ( krb5_context kcontext); + + krb5_error_code (*db_get_principal) ( krb5_context kcontext, + krb5_const_principal search_for, + krb5_db_entry *entries, + int *nentries, + krb5_boolean *more ); + + krb5_error_code (*db_free_principal) ( krb5_context kcontext, + krb5_db_entry *entry, + int count ); + + krb5_error_code (*db_put_principal) ( krb5_context kcontext, + krb5_db_entry *entries, + int *nentries, + char **db_args); + + krb5_error_code (*db_delete_principal) ( krb5_context kcontext, + krb5_const_principal search_for, + int *nentries ); + + krb5_error_code (*db_iterate) ( krb5_context kcontext, + char *match_entry, + int (*func) (krb5_pointer, krb5_db_entry *), + krb5_pointer func_arg ); + + krb5_error_code (*db_create_policy) ( krb5_context kcontext, + osa_policy_ent_t policy ); + + krb5_error_code (*db_get_policy) ( krb5_context kcontext, + char *name, + osa_policy_ent_t *policy, + int *cnt); + + krb5_error_code (*db_put_policy) ( krb5_context kcontext, + osa_policy_ent_t policy ); + + krb5_error_code (*db_iter_policy) ( krb5_context kcontext, + char *match_entry, + osa_adb_iter_policy_func func, + void *data ); + + + krb5_error_code (*db_delete_policy) ( krb5_context kcontext, + char *policy ); + + void (*db_free_policy) ( krb5_context kcontext, + osa_policy_ent_t val ); + + krb5_error_code (*db_supported_realms) ( krb5_context kcontext, + char **realms ); + + krb5_error_code (*db_free_supported_realms) ( krb5_context kcontext, + char **realms ); + + + const char * (*errcode_2_string) ( krb5_context kcontext, + long err_code ); + + void * (*db_alloc) (krb5_context kcontext, void *ptr, size_t size); + void (*db_free) (krb5_context kcontext, void *ptr); + + + + /* optional functions */ + krb5_error_code (*set_master_key) ( krb5_context kcontext, + char *pwd, + krb5_keyblock *key); + + krb5_error_code (*get_master_key) ( krb5_context kcontext, + krb5_keyblock **key); + + + krb5_error_code (*setup_master_key_name) ( krb5_context kcontext, + char *keyname, + char *realm, + char **fullname, + krb5_principal *principal); + + krb5_error_code (*store_master_key) ( krb5_context kcontext, + char *db_arg, + krb5_principal mname, + krb5_keyblock *key, + char *master_pwd); + + krb5_error_code (*fetch_master_key) ( krb5_context kcontext, + krb5_principal mname, + krb5_keyblock *key, + int *kvno, + char *db_args); + + krb5_error_code (*verify_master_key) ( krb5_context kcontext, + krb5_principal mprinc, + krb5_keyblock *mkey ); + + krb5_error_code (*dbe_search_enctype) ( krb5_context kcontext, + krb5_db_entry *dbentp, + krb5_int32 *start, + krb5_int32 ktype, + krb5_int32 stype, + krb5_int32 kvno, + krb5_key_data **kdatap); + + + krb5_error_code + (*db_change_pwd) ( krb5_context context, + krb5_keyblock * master_key, + krb5_key_salt_tuple * ks_tuple, + int ks_tuple_count, + char * passwd, + int new_kvno, + krb5_boolean keepold, + krb5_db_entry * db_entry); + +} kdb_vftabl; + +typedef struct _db_library { + char name[KDB_MAX_DB_NAME]; + int reference_cnt; +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lib_lock; + pthread_cond_t unlocked; /* To check whether some one has called db_unlock */ + int recursive_cnt; /* this is used as lock to help recursive locking */ + pthread_t lock_holder; + int excl; +#endif + void *dl_handle; + kdb_vftabl vftabl; + struct _db_library *next, *prev; +} *db_library; + +typedef struct _kdb5_dal_handle +{ + void *db_context; /* helps us to change db_library without affecting modules to some extend */ + db_library lib_handle; +} kdb5_dal_handle; + +#endif /* end of _KRB5_KDB5_H_ */ diff --git a/src/lib/kdb/kdb_cpw.c b/src/lib/kdb/kdb_cpw.c index 962a2b5..f873a39 100644 --- a/src/lib/kdb/kdb_cpw.c +++ b/src/lib/kdb/kdb_cpw.c @@ -52,7 +52,6 @@ */ #include "k5-int.h" -#include "krb5/adm.h" #include <stdio.h> #include <errno.h> @@ -86,11 +85,11 @@ cleanup_key_data(context, count, data) for (i = 0; i < count; i++) { for (j = 0; j < data[i].key_data_ver; j++) { if (data[i].key_data_length[j]) { - free(data[i].key_data_contents[j]); + krb5_db_free(context, data[i].key_data_contents[j]); } } } - free(data); + krb5_db_free(context, data); } static krb5_error_code @@ -106,8 +105,13 @@ add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno) krb5_keyblock key; krb5_db_entry krbtgt_entry; krb5_boolean more; - int max_kvno, one, i, j; + int max_kvno, one, i, j, k; krb5_error_code retval; + krb5_key_data tmp_key_data; + krb5_key_data *tptr; + + memset( &tmp_key_data, 0, sizeof(tmp_key_data)); + retval = krb5_build_principal_ext(context, &krbtgt_princ, db_entry->princ->realm.length, @@ -176,19 +180,59 @@ add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno) &key))) goto add_key_rnd_err; + + /* db library will free this. Since, its a so, it could actually be using different memory management + function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used + here which will later be copied to the db_entry */ retval = krb5_dbekd_encrypt_key_data(context, master_key, &key, NULL, kvno, - &db_entry->key_data[db_entry->n_key_data-1]); + &tmp_key_data); krb5_free_keyblock_contents(context, &key); - - if (retval) + if( retval ) goto add_key_rnd_err; + + tptr = &db_entry->key_data[db_entry->n_key_data-1]; + + tptr->key_data_ver = tmp_key_data.key_data_ver; + tptr->key_data_kvno = tmp_key_data.key_data_kvno; + + for( k = 0; k < tmp_key_data.key_data_ver; k++ ) + { + tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; + tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; + if( tmp_key_data.key_data_contents[k] ) + { + tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]); + if( tptr->key_data_contents[k] == NULL ) + { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->key_data = NULL; + db_entry->n_key_data = 0; + retval = ENOMEM; + goto add_key_rnd_err; + } + memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); + + memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); + free( tmp_key_data.key_data_contents[k] ); + tmp_key_data.key_data_contents[k] = NULL; + } + } + } add_key_rnd_err: krb5_db_free_principal(context, &krbtgt_entry, one); + for( i = 0; i < tmp_key_data.key_data_ver; i++ ) + { + if( tmp_key_data.key_data_contents[i] ) + { + memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); + free( tmp_key_data.key_data_contents[i] ); + } + } return(retval); } @@ -242,6 +286,7 @@ krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry) db_entry->key_data[i+n_new_key_data] = key_data[i]; memset(&key_data[i], 0, sizeof(krb5_key_data)); } + krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */ } else { cleanup_key_data(context, key_data_count, key_data); } @@ -321,7 +366,11 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, krb5_keysalt key_salt; krb5_keyblock key; krb5_data pwd; - int i, j; + int i, j, k; + krb5_key_data tmp_key_data; + krb5_key_data *tptr; + + memset( &tmp_key_data, 0, sizeof(tmp_key_data)); retval = 0; @@ -424,18 +473,56 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, key_salt.data.length = krb5_princ_realm(context, db_entry->princ)->length; - if ((retval = krb5_dbekd_encrypt_key_data(context, master_key, &key, - (const krb5_keysalt *)&key_salt, - kvno, &db_entry->key_data[db_entry->n_key_data-1]))) { - if (key_salt.data.data) - free(key_salt.data.data); - krb5_xfree(key.contents); - return(retval); - } + /* memory allocation to be done by db. So, use temporary block and later copy + it to the memory allocated by db */ + retval = krb5_dbekd_encrypt_key_data(context, master_key, &key, + (const krb5_keysalt *)&key_salt, + kvno, &tmp_key_data); if (key_salt.data.data) - free(key_salt.data.data); + free(key_salt.data.data); krb5_xfree(key.contents); + + if( retval ) + return retval; + + tptr = &db_entry->key_data[db_entry->n_key_data-1]; + + tptr->key_data_ver = tmp_key_data.key_data_ver; + tptr->key_data_kvno = tmp_key_data.key_data_kvno; + + for( k = 0; k < tmp_key_data.key_data_ver; k++ ) + { + tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; + tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; + if( tmp_key_data.key_data_contents[k] ) + { + tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]); + if( tptr->key_data_contents[k] == NULL ) + { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->key_data = NULL; + db_entry->n_key_data = 0; + retval = ENOMEM; + goto add_key_pwd_err; + } + memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); + + memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); + free( tmp_key_data.key_data_contents[k] ); + tmp_key_data.key_data_contents[k] = NULL; + } + } + } + add_key_pwd_err: + for( i = 0; i < tmp_key_data.key_data_ver; i++ ) + { + if( tmp_key_data.key_data_contents[i] ) + { + memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); + free( tmp_key_data.key_data_contents[i] ); + } } + return(retval); } @@ -446,7 +533,7 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, * As a side effect all old keys are nuked if keepold is false. */ krb5_error_code -krb5_dbe_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd, +krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd, new_kvno, keepold, db_entry) krb5_context context; krb5_keyblock * master_key; @@ -495,6 +582,7 @@ krb5_dbe_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry->key_data[i+n_new_key_data] = key_data[i]; memset(&key_data[i], 0, sizeof(krb5_key_data)); } + krb5_db_free( context, key_data ); } else { cleanup_key_data(context, key_data_count, key_data); } @@ -556,3 +644,5 @@ krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry) } return(retval); } + + diff --git a/src/lib/kdb/kdb_db2/ChangeLog b/src/lib/kdb/kdb_db2/ChangeLog new file mode 100644 index 0000000..6ebc2a0 --- /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 0000000..ebd39f0 --- /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 0000000..97ce112 --- /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 0000000..e338cbb --- /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 0000000..dc002d8 --- /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 0000000..f511487 --- /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_compat.h b/src/lib/kdb/kdb_db2/kdb_compat.h index 540d4a2..540d4a2 100644 --- a/src/lib/kdb/kdb_compat.h +++ b/src/lib/kdb/kdb_db2/kdb_compat.h diff --git a/src/lib/kdb/kdb_db2.c b/src/lib/kdb/kdb_db2/kdb_db2.c index bcd08a2..2ac462e 100644 --- a/src/lib/kdb/kdb_db2.c +++ b/src/lib/kdb/kdb_db2/kdb_db2.c @@ -60,6 +60,12 @@ #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 @@ -71,14 +77,23 @@ static char *gen_dbsuffix (char *, char * ); -static krb5_error_code krb5_db2_db_start_update + +static krb5_error_code krb5_db2_db_start_update (krb5_context); -static krb5_error_code krb5_db2_db_end_update +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: @@ -129,8 +144,39 @@ static char default_db_name[] = DEFAULT_KDB_FILE; /* * Routines to deal with context. */ -#define k5db2_inited(c) (c && c->db_context && \ - ((krb5_db2_context *) c->db_context)->db_inited) +#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. @@ -155,25 +201,30 @@ k5db2_clear_context(dbctx) 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 (context->db_context == NULL) { + 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); - context->db_context = (void *) db_ctx; + dal_handle->db_context = (void *) db_ctx; } } return(0); } + /* * Utility routine: generate name of database file. */ @@ -196,6 +247,7 @@ gen_dbsuffix(db_name, sfx) return dbsuffix; } + static DB * k5db2_dbopen(dbc, fname, flags, mode) krb5_db2_context *dbc; @@ -248,10 +300,12 @@ krb5_db2_db_set_hashfirst(context, hashfirst) int hashfirst; { krb5_db2_context *dbc; + kdb5_dal_handle *dal_handle; if (k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; - dbc = (krb5_db2_context *) context->db_context; + dal_handle = (kdb5_dal_handle*) context->db_context; + dbc = (krb5_db2_context *) dal_handle->db_context; dbc->hashfirst = hashfirst; return 0; } @@ -267,6 +321,8 @@ krb5_db2_db_init(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; @@ -275,7 +331,8 @@ krb5_db2_db_init(context) if ((retval = k5db2_init_context(context))) return(retval); - db_ctx = context->db_context; + 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))) @@ -297,6 +354,14 @@ krb5_db2_db_init(context) 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: @@ -305,6 +370,7 @@ err_out: return (retval); } + /* * gracefully shut down database--must be called by ANY program that does * a krb5_db2_db_init @@ -315,8 +381,15 @@ krb5_db2_db_fini(context) { krb5_error_code retval = 0; krb5_db2_context *db_ctx; + kdb5_dal_handle *dal_handle; - db_ctx = (krb5_db2_context *) context->db_context; + 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)) @@ -325,13 +398,22 @@ krb5_db2_db_fini(context) 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(context->db_context); - context->db_context = NULL; + /* 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; @@ -350,6 +432,8 @@ krb5_db2_db_close_database(context) return 0; } +#endif // 0 -pradx + /* * Set/Get the master key associated with the database */ @@ -359,11 +443,13 @@ krb5_db2_db_set_mkey(context, key) krb5_keyblock *key; { krb5_db2_context *db_ctx; + kdb5_dal_handle *dal_handle; if (!k5db2_inited(context)) return(KRB5_KDB_DBNOTINITED); - db_ctx = context->db_context; + dal_handle = (kdb5_dal_handle*) context->db_context; + db_ctx = dal_handle->db_context; db_ctx->db_master_key = key; return 0; } @@ -374,11 +460,13 @@ krb5_db2_db_get_mkey(context, key) krb5_keyblock **key; { krb5_db2_context *db_ctx; + kdb5_dal_handle *dal_handle; if (!k5db2_inited(context)) return(KRB5_KDB_DBNOTINITED); - db_ctx = context->db_context; + dal_handle = (kdb5_dal_handle*)context->db_context; + db_ctx = dal_handle->db_context; *key = db_ctx->db_master_key; return 0; @@ -401,6 +489,7 @@ krb5_db2_db_set_name(context, 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; @@ -412,7 +501,8 @@ krb5_db2_db_set_name(context, name) if (name == NULL) name = default_db_name; - db_ctx = context->db_context; + 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; @@ -435,11 +525,14 @@ krb5_db2_db_get_age(context, db_name, age) time_t *age; { krb5_db2_context *db_ctx; + kdb5_dal_handle *dal_handle; struct stat st; if (!k5db2_inited(context)) return(KRB5_KDB_DBNOTINITED); - db_ctx = (krb5_db2_context *) context->db_context; + 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 @@ -468,6 +561,7 @@ krb5_db2_db_end_update(context) { krb5_error_code retval; krb5_db2_context *db_ctx; + kdb5_dal_handle *dal_handle; struct stat st; time_t now; struct utimbuf utbuf; @@ -476,7 +570,8 @@ krb5_db2_db_end_update(context) return(KRB5_KDB_DBNOTINITED); retval = 0; - db_ctx = context->db_context; + 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) { @@ -502,24 +597,43 @@ krb5_db2_db_end_update(context) } krb5_error_code -krb5_db2_db_lock(context, mode) +krb5_db2_db_lock(context, in_mode) krb5_context context; - int mode; + 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; - db_ctx = (krb5_db2_context *) context->db_context; + 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++; - return(0); + goto policy_lock; } if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE)) @@ -557,27 +671,42 @@ krb5_db2_db_lock(context, mode) db_ctx->db_lock_mode = mode; db_ctx->db_locks_held++; - return 0; + + 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; - (void) krb5_db2_db_unlock(context); + 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; - db_ctx = (krb5_db2_context *) context->db_context; + 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; @@ -603,15 +732,18 @@ krb5_db2_db_create(context, db_name, flags) 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); - db_ctx = (krb5_db2_context *) context->db_context; + 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))) @@ -643,6 +775,14 @@ krb5_db2_db_create(context, db_name, flags) 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; } @@ -748,9 +888,10 @@ krb5_db2_db_destroy(context, dbname) { krb5_error_code retval1, retval2; krb5_boolean tmpcontext; + char policy_db_name[1024], policy_lock_name[1024]; tmpcontext = 0; - if (!context->db_context) { + if ( !context->db_context || !((kdb5_dal_handle*)context->db_context)->db_context ) { tmpcontext = 1; if ((retval1 = k5db2_init_context(context))) return(retval1); @@ -761,17 +902,25 @@ krb5_db2_db_destroy(context, 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; + 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); - else - return 0; + + 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. @@ -791,13 +940,15 @@ krb5_db2_db_rename(context, from, to) DB *db; char *fromok; krb5_error_code retval; + kdb5_dal_handle *dal_handle; krb5_db2_context *s_context, *db_ctx; - s_context = context->db_context; - context->db_context = NULL; + 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 *) context->db_context; + db_ctx = (krb5_db2_context *) ((kdb5_dal_handle*)context->db_context)->db_context; /* * Create the database if it does not already exist; the @@ -860,21 +1011,23 @@ krb5_db2_db_rename(context, from, to) errfromok: free_dbsuffix(fromok); errout: - if (context->db_context) { + 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 *) context->db_context); - free(context->db_context); + k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle*)context->db_context)->db_context); + free(((kdb5_dal_handle*)context->db_context)->db_context); } - context->db_context = s_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 @@ -894,7 +1047,8 @@ krb5_db2_db_get_principal(context, searchfor, entries, nentries, more) DB *db; DBT key, contents; krb5_data keydata, contdata; - int trynum, dbret; + int try, dbret; + kdb5_dal_handle *dal_handle; *more = FALSE; *nentries = 0; @@ -902,8 +1056,10 @@ krb5_db2_db_get_principal(context, searchfor, entries, nentries, more) if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; - db_ctx = (krb5_db2_context *) context->db_context; - for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) { + 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); @@ -912,7 +1068,7 @@ krb5_db2_db_get_principal(context, searchfor, entries, nentries, more) } break; } - if (trynum == KRB5_DB2_MAX_RETRY) + if (try == KRB5_DB2_MAX_RETRY) return KRB5_KDB_DB_INUSE; /* XXX deal with wildcard lookups */ @@ -950,7 +1106,7 @@ cleanup: /* Free stuff returned by krb5_db2_db_get_principal. */ -void +krb5_error_code krb5_db2_db_free_principal(context, entries, nentries) krb5_context context; krb5_db_entry *entries; @@ -959,7 +1115,7 @@ krb5_db2_db_free_principal(context, entries, nentries) register int i; for (i = 0; i < nentries; i++) krb5_dbe_free_contents(context, &entries[i]); - return; + return 0; } /* @@ -973,10 +1129,11 @@ krb5_db2_db_free_principal(context, entries, nentries) */ krb5_error_code -krb5_db2_db_put_principal(context, entries, nentries) +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; @@ -984,13 +1141,24 @@ krb5_db2_db_put_principal(context, entries, nentries) 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; - db_ctx = (krb5_db2_context *) context->db_context; + 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; @@ -1048,11 +1216,13 @@ krb5_db2_db_delete_principal(context, searchfor, nentries) DBT key, contents; krb5_data keydata, contdata; int i, dbret; + kdb5_dal_handle *dal_handle; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; - db_ctx = (krb5_db2_context *) context->db_context; + 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); @@ -1131,6 +1301,7 @@ krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive) krb5_data contdata; krb5_db_entry entries; krb5_error_code retval; + kdb5_dal_handle *dal_handle; int dbret; void *cookie; @@ -1138,7 +1309,8 @@ krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive) if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; - db_ctx = (krb5_db2_context *) context->db_context; + 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) @@ -1198,14 +1370,15 @@ krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive) } krb5_error_code -krb5_db2_db_iterate(context, func, func_arg) - krb5_context context; - krb5_error_code (*func) (krb5_pointer, krb5_db_entry *); - krb5_pointer func_arg; +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; @@ -1213,15 +1386,18 @@ krb5_db2_db_set_lockmode(context, 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 ((db_ctx = (krb5_db2_context *) context->db_context)) { + 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. * @@ -1384,7 +1560,7 @@ kdb5_context_internalize(kcontext, argp, buffer, lenremain) dbctx = (krb5_db2_context *) tmpctx->db_context; (void) krb5_db2_db_set_lockmode(tmpctx, 0); if (lockmode) - kret = krb5_db_lock(tmpctx, lockmode); + kret = krb5_db2_db_lock(tmpctx, lockmode); if (!kret && lockmode) dbctx->db_locks_held = lockcount; nb_lock = nb_lockmode & 0xff; @@ -1432,3 +1608,393 @@ krb5_ser_db_context_init(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.h b/src/lib/kdb/kdb_db2/kdb_db2.h index 80f9495..ba03ea3 100644 --- a/src/lib/kdb/kdb_db2.h +++ b/src/lib/kdb/kdb_db2/kdb_db2.h @@ -27,29 +27,9 @@ * KDC Database backend definitions for Berkely DB. */ #ifndef KRB5_KDB_DB2_H +#define 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 krb5_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_ext krb5_db_iterate_ext -#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 +#include "policy_db.h" typedef struct _krb5_db2_context { krb5_boolean db_inited; /* Context initialized */ @@ -63,6 +43,7 @@ typedef struct _krb5_db2_context { 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 @@ -97,21 +78,23 @@ krb5_error_code krb5_db2_db_get_principal krb5_db_entry *, int *, krb5_boolean * ); -void krb5_db2_db_free_principal +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 * ); + 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, +(krb5_context,char *, krb5_error_code (*) (krb5_pointer, krb5_db_entry *), krb5_pointer ); @@ -127,4 +110,107 @@ krb5_error_code krb5_db2_db_open_database 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_xdr.c b/src/lib/kdb/kdb_db2/kdb_xdr.c index fb0a41e..a5332ea 100644 --- a/src/lib/kdb/kdb_xdr.c +++ b/src/lib/kdb/kdb_db2/kdb_xdr.c @@ -29,6 +29,7 @@ #include <string.h> #include <stdio.h> #include <errno.h> +#include "kdb_xdr.h" #define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n))) @@ -768,6 +769,7 @@ krb5_dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap) if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype, dbentp->key_data[i].key_data_type[0], &similar))) + return(ret); } 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 0000000..2ee068f --- /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 0000000..b6902eb --- /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 0000000..3776108 --- /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 0000000..772b24d --- /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__ */ diff --git a/src/lib/kdb/kdb_default.c b/src/lib/kdb/kdb_default.c new file mode 100644 index 0000000..07d1cef --- /dev/null +++ b/src/lib/kdb/kdb_default.c @@ -0,0 +1,329 @@ +/* + * lib/kdb/kdb_helper.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> + + +/* + * 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_def_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; +} + +/* + * kdb default functions. Ideally, some other file should have this functions. For now, TBD. + */ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +krb5_error_code +krb5_def_store_mkey(context, keyfile, mname, key, master_pwd) + krb5_context context; + char *keyfile; + krb5_principal mname; + krb5_keyblock *key; + char *master_pwd; +{ + FILE *kf; + krb5_error_code retval = 0; + krb5_ui_2 enctype; + char defkeyfile[MAXPATHLEN+1]; + krb5_data *realm = krb5_princ_realm(context, mname); +#if HAVE_UMASK + mode_t oumask; +#endif + + if (!keyfile) { + (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB); + (void) strncat(defkeyfile, realm->data, + min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1, + realm->length)); + defkeyfile[sizeof(defkeyfile) - 1] = '\0'; + keyfile = defkeyfile; + } + +#if HAVE_UMASK + oumask = umask(077); +#endif +#ifdef ANSI_STDIO + if (!(kf = fopen(keyfile, "wb"))) +#else + if (!(kf = fopen(keyfile, "w"))) +#endif + { +#if HAVE_UMASK + (void) umask(oumask); +#endif + return errno; + } + enctype = key->enctype; + if ((fwrite((krb5_pointer) &enctype, + 2, 1, kf) != 1) || + (fwrite((krb5_pointer) &key->length, + sizeof(key->length), 1, kf) != 1) || + (fwrite((krb5_pointer) key->contents, + sizeof(key->contents[0]), (unsigned) key->length, + kf) != key->length)) { + retval = errno; + (void) fclose(kf); + } + if (fclose(kf) == EOF) + retval = errno; +#if HAVE_UMASK + (void) umask(oumask); +#endif + return retval; +} + + +krb5_error_code +krb5_db_def_fetch_mkey( krb5_context context, + krb5_principal mname, + krb5_keyblock *key, + int *kvno, + char *db_args) +{ + krb5_error_code retval; + krb5_ui_2 enctype; + char defkeyfile[MAXPATHLEN+1]; + krb5_data *realm = krb5_princ_realm(context, mname); + FILE *kf = NULL; + + retval = 0; + key->magic = KV5M_KEYBLOCK; + (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB); + (void) strncat(defkeyfile, realm->data, + min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1, + realm->length)); + defkeyfile[sizeof(defkeyfile) - 1] = '\0'; + +#ifdef ANSI_STDIO + if (!(kf = fopen((db_args) ? db_args : defkeyfile, "rb"))) +#else + if (!(kf = fopen((db_args) ? db_args : defkeyfile, "r"))) +#endif + return KRB5_KDB_CANTREAD_STORED; + + if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) { + retval = KRB5_KDB_CANTREAD_STORED; + goto errout; + } + + if (key->enctype == ENCTYPE_UNKNOWN) + key->enctype = enctype; + else if (enctype != key->enctype) { + retval = KRB5_KDB_BADSTORED_MKEY; + goto errout; + } + + if (fread((krb5_pointer) &key->length, + sizeof(key->length), 1, kf) != 1) { + retval = KRB5_KDB_CANTREAD_STORED; + goto errout; + } + + if (!key->length || ((int) key->length) < 0) { + retval = KRB5_KDB_BADSTORED_MKEY; + goto errout; + } + + if (!(key->contents = (krb5_octet *)malloc(key->length))) { + retval = ENOMEM; + goto errout; + } + + if (fread((krb5_pointer) key->contents, + sizeof(key->contents[0]), key->length, kf) + != key->length) { + retval = KRB5_KDB_CANTREAD_STORED; + memset(key->contents, 0, key->length); + free(key->contents); + key->contents = 0; + } else + retval = 0; + + *kvno = 0; + + errout: + (void) fclose(kf); + return retval; + +} + + +krb5_error_code +krb5_def_verify_master_key(context, mprinc, mkey) + krb5_context context; + krb5_principal mprinc; + krb5_keyblock *mkey; +{ + krb5_error_code retval; + krb5_db_entry master_entry; + int nprinc; + krb5_boolean more; + krb5_keyblock tempkey; + + nprinc = 1; + if ((retval = krb5_db_get_principal(context, mprinc, + &master_entry, &nprinc, &more))) + return(retval); + + if (nprinc != 1) { + if (nprinc) + krb5_db_free_principal(context, &master_entry, nprinc); + return(KRB5_KDB_NOMASTERKEY); + } else if (more) { + krb5_db_free_principal(context, &master_entry, nprinc); + return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); + } + + if ((retval = krb5_dbekd_decrypt_key_data(context, mkey, + &master_entry.key_data[0], + &tempkey, NULL))) { + krb5_db_free_principal(context, &master_entry, nprinc); + return retval; + } + + if (mkey->length != tempkey.length || + memcmp((char *)mkey->contents, + (char *)tempkey.contents,mkey->length)) { + retval = KRB5_KDB_BADMASTERKEY; + } + + memset((char *)tempkey.contents, 0, tempkey.length); + krb5_xfree(tempkey.contents); + krb5_db_free_principal(context, &master_entry, nprinc); + + return retval; +} + + +krb5_error_code kdb_def_set_mkey ( krb5_context kcontext, + char *pwd, + krb5_keyblock *key ) +{ + printf("default set master key\n"); + return 0; +} + +krb5_error_code kdb_def_get_mkey ( krb5_context kcontext, + krb5_keyblock **key ) +{ + printf("default get master key\n"); + return 0; +} + diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c index 679ecad..227a42e 100644 --- a/src/lib/kdb/keytab.c +++ b/src/lib/kdb/keytab.c @@ -140,20 +140,19 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) xrealm_tgt = is_xrealm_tgt(context, principal); - /* Open database */ - /* krb5_db_init(context); */ - if ((kerror = krb5_db_open_database(context))) + /* Check whether database is inited. Open is commented */ + if ((kerror = krb5_db_inited(context))) return(kerror); /* get_principal */ kerror = krb5_db_get_principal(context, principal, & db_entry, &n, &more); if (kerror) { - krb5_db_close_database(context); + /* krb5_db_close_database(context); */ return(kerror); } if (n != 1) { - krb5_db_close_database(context); + /* krb5_db_close_database(context); */ return KRB5_KT_NOTFOUND; } @@ -207,8 +206,8 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) /* Close database */ error: - krb5_dbe_free_contents(context, &db_entry); - krb5_db_close_database(context); + krb5_db_free_principal(context, &db_entry, 1); + /* krb5_db_close_database(context); */ return(kerror); } diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports index 47e1f0e..c9d53fb 100644 --- a/src/lib/kdb/libkdb5.exports +++ b/src/lib/kdb/libkdb5.exports @@ -97,6 +97,11 @@ kdb2_mpool_put kdb2_mpool_sync kdb2_nextkey kdb2_store +krb5_db_open +krb5_db_inited +krb5_db_clr_error +krb5_db_alloc +krb5_db_free krb5_db_close_database krb5_db_create krb5_db_delete_principal @@ -120,6 +125,7 @@ krb5_db_set_name krb5_db_setup_mkey_name krb5_db_store_mkey krb5_db_unlock +krb5_db_store_master_key krb5_db_verify_master_key krb5_dbe_apw krb5_dbe_ark @@ -150,3 +156,10 @@ krb5_ktkdb_set_context krb5_mkey_pwd_prompt1 krb5_mkey_pwd_prompt2 krb5_ser_db_context_init +krb5_db_create_policy +krb5_db_get_policy +krb5_db_put_policy +krb5_db_iter_policy +krb5_db_delete_policy +krb5_db_free_policy +krb5_db_vftabl_kdb_db2 diff --git a/src/lib/kdb/setup_mkey.c b/src/lib/kdb/setup_mkey.c deleted file mode 100644 index 61f1ef3..0000000 --- a/src/lib/kdb/setup_mkey.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * lib/kdb/setup_mkey.c - * - * Copyright 1990 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. - * - * - * krb5_kdb_setup_mkey() - */ - -#include "k5-int.h" - -/* - * Given a key name and a realm name, construct a principal which can be used - * to fetch the master key from the database. - * - * If the key name is NULL, the default key name will be used. - */ - -#define REALM_SEP_STRING "@" - -krb5_error_code -krb5_db_setup_mkey_name(context, keyname, realm, fullname, principal) - krb5_context context; - const char *keyname; - const char *realm; - char **fullname; - krb5_principal *principal; -{ - krb5_error_code retval; - size_t keylen; - size_t rlen = strlen(realm); - char *fname; - - if (!keyname) - keyname = KRB5_KDB_M_NAME; /* XXX external? */ - - keylen = strlen(keyname); - - fname = malloc(keylen+rlen+strlen(REALM_SEP_STRING)+1); - if (!fname) - return ENOMEM; - - strcpy(fname, keyname); - strcat(fname, REALM_SEP_STRING); - strcat(fname, realm); - - if ((retval = krb5_parse_name(context, fname, principal))) - return retval; - if (fullname) - *fullname = fname; - else - free(fname); - return 0; -} diff --git a/src/lib/kdb/store_mkey.c b/src/lib/kdb/store_mkey.c deleted file mode 100644 index 587850e..0000000 --- a/src/lib/kdb/store_mkey.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * lib/kdb/store_mkey.c - * - * Copyright 1990 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. - * - * - * krb5_db_store_mkey(): - * Store a database master key in a file. - */ - - -#include <errno.h> -#include "k5-int.h" - -/* Just in case sysincl.h didn't get it */ - -#ifndef MAXPATHLEN -#define MAXPATHLEN 1024 -#endif - -/* - * Put the KDC database master key into a file. If keyfile is NULL, - * then a default name derived from the principal name mname is used. - */ - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -krb5_error_code -krb5_db_store_mkey(context, keyfile, mname, key) - krb5_context context; - char *keyfile; - krb5_principal mname; - krb5_keyblock *key; -{ - FILE *kf; - krb5_error_code retval = 0; - krb5_ui_2 enctype; - char defkeyfile[MAXPATHLEN+1]; - krb5_data *realm = krb5_princ_realm(context, mname); -#if HAVE_UMASK - mode_t oumask; -#endif - - if (!keyfile) { - (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB); - (void) strncat(defkeyfile, realm->data, - min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1, - realm->length)); - defkeyfile[sizeof(defkeyfile) - 1] = '\0'; - keyfile = defkeyfile; - } - -#if HAVE_UMASK - oumask = umask(077); -#endif -#ifdef ANSI_STDIO - if (!(kf = fopen(keyfile, "wb"))) -#else - if (!(kf = fopen(keyfile, "w"))) -#endif - { -#if HAVE_UMASK - (void) umask(oumask); -#endif - return errno; - } - enctype = key->enctype; - if ((fwrite((krb5_pointer) &enctype, - 2, 1, kf) != 1) || - (fwrite((krb5_pointer) &key->length, - sizeof(key->length), 1, kf) != 1) || - (fwrite((krb5_pointer) key->contents, - sizeof(key->contents[0]), (unsigned) key->length, - kf) != key->length)) { - retval = errno; - (void) fclose(kf); - } - if (fclose(kf) == EOF) - retval = errno; -#if HAVE_UMASK - (void) umask(oumask); -#endif - return retval; -} diff --git a/src/lib/kdb/t_kdb.c b/src/lib/kdb/t_kdb.c deleted file mode 100644 index 769d3e6..0000000 --- a/src/lib/kdb/t_kdb.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * lib/kdb/t_kdb.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. - * - */ - -/* - * t_kdb.c - Test [and optionally obtain timing information about] the - * Kerberos database functions. - */ - -#define KDB5_DISPATCH -#include "k5-int.h" -#include <ctype.h> -#include <sys/time.h> -#include <sys/wait.h> -#include "com_err.h" - -#if HAVE_SRAND48 -#define RAND() lrand48() -#define SRAND(a) srand48(a) -#define RAND_TYPE long -#elif HAVE_SRAND -#define RAND() rand() -#define SRAND(a) srand(a) -#define RAND_TYPE int -#elif HAVE_SRANDOM -#define RAND() random() -#define SRAND(a) srandom(a) -#define RAND_TYPE long -#else /* no random */ -need a random number generator -#endif /* no random */ - -#define T_KDB_N_PASSES 100 -#define T_KDB_DEF_DB "test_db" -#define MAX_PNAME_LEN 1024 -#define MAX_PRINC_COMPS 8 -#define MAX_COMP_SIZE 32 - -#define RANDOM(a,b) (a + (RAND() % (b-a))) - -enum dbtype { DB_UFO, DB_DEFAULT, DB_BERKELEY, DB_DBM }; - -char *programname = (char *) NULL; -krb5_data mprinc_data_entries[] = { - { 0, sizeof("master")-1, "master"}, - { 0, sizeof("key")-1, "key"} -}; - -krb5_principal_data master_princ_data = { - 0, /* Magic number */ - { 0, sizeof("test.realm")-1, "test.realm"}, /* Realm */ - mprinc_data_entries, /* Name/instance */ - sizeof(mprinc_data_entries)/ - sizeof(mprinc_data_entries[0]), /* Number */ - KRB5_NT_SRV_INST /* Type */ -}; - -struct timeval tstart_time, tend_time; -struct timezone dontcare; -krb5_principal *recorded_principals = (krb5_principal *) NULL; -char **recorded_names = (char **) NULL; - -#ifdef BERK_DB_DBM -extern DBM *db_dbm_open (char *, int, int); -extern void db_dbm_close (DBM *); -extern datum db_dbm_fetch (DBM *, datum); -extern datum db_dbm_firstkey (DBM *); -extern datum db_dbm_nextkey (DBM *); -extern int db_dbm_delete (DBM *, datum); -extern int db_dbm_store (DBM *, datum, datum, int); -extern int db_dbm_error (DBM *); -extern int db_dbm_clearerr (DBM *); -extern int db_dbm_dirfno (DBM *); - -static kdb5_dispatch_table berkeley_dispatch = { - "Berkeley Hashed Database", - ".db", /* Index file name ext */ - (char *) NULL, /* Data file name ext */ - ".ok", /* Lock file name ext */ - db_dbm_open, /* Open Database */ - db_dbm_close, /* Close Database */ - db_dbm_fetch, /* Fetch Key */ - db_dbm_firstkey, /* Fetch First Key */ - db_dbm_nextkey, /* Fetch Next Key */ - db_dbm_delete, /* Delete Key */ - db_dbm_store, /* Store Key */ - db_dbm_error, /* Get Database Error */ - db_dbm_clearerr, /* Clear Database Error */ - db_dbm_dirfno, /* Get Database FD num */ - (int (*)()) NULL /* Get Database FD num */ -}; -#endif - -#if defined(NDBM) || defined(ODBM) -/* - * The following prototypes are necessary in case dbm_error and - * dbm_clearerr are in the library but not prototyped - * (e.g. NetBSD-1.0) - */ -#ifdef MISSING_ERROR_PROTO -int dbm_error (DBM *); -#endif -#ifdef MISSING_CLEARERR_PROTO -int dbm_clearerr (DBM *); -#endif - -static kdb5_dispatch_table dbm_dispatch = { - "Stock [N]DBM Database", - ".dir", /* Index file name ext */ - ".pag", /* Data file name ext */ - ".ok", /* Lock file name ext */ - dbm_open, /* Open Database */ - dbm_close, /* Close Database */ - dbm_fetch, /* Fetch Key */ - dbm_firstkey, /* Fetch First Key */ - dbm_nextkey, /* Fetch Next Key */ - dbm_delete, /* Delete Key */ - dbm_store, /* Store Key */ - /* - * The following are #ifdef'd because they have the potential to be - * macros rather than functions. - */ -#ifdef dbm_error - (int (*)()) NULL, /* Get Database Error */ -#else /* dbm_error */ -#ifdef HAVE_DBM_ERROR - dbm_error, /* Get Database Error */ -#else - (int (*)()) NULL, /* Get Database Error */ -#endif -#endif /* dbm_error */ -#ifdef dbm_clearerr - (int (*)()) NULL, /* Clear Database Error */ -#else /* dbm_clearerr */ -#ifdef HAVE_DBM_CLEARERR - dbm_clearerr, /* Clear Database Error */ -#else - (int (*)()) NULL, /* Clear Database Error */ -#endif -#endif /* dbm_clearerr */ -#ifdef dbm_dirfno - (int (*)()) NULL, /* Get Database FD num */ -#else /* dbm_dirfno */ - dbm_dirfno, /* Get Database FD num */ -#endif /* dbm_dirfno */ -#ifdef dbm_pagfno - (int (*)()) NULL, /* Get Database FD num */ -#else /* dbm_pagfno */ - dbm_pagfno, /* Get Database FD num */ -#endif /* dbm_pagfno */ -}; -#endif /* NDBM || ODBM */ - - -/* - * Timer macros. - */ -#define swatch_on() ((void) gettimeofday(&tstart_time, &dontcare)) -#define swatch_eltime() ((gettimeofday(&tend_time, &dontcare)) ? -1.0 : \ - (((float) (tend_time.tv_sec - \ - tstart_time.tv_sec)) + \ - (((float) (tend_time.tv_usec - \ - tstart_time.tv_usec))/1000000.0))) - -/* - * Free all principals and names in the recorded names list. - */ -static void -free_principals(kcontext, nentries) - krb5_context kcontext; - int nentries; -{ - int i; - if (recorded_principals) { - for (i=0; i<nentries; i++) { - if (recorded_principals[i]) - krb5_free_principal(kcontext, recorded_principals[i]); - } - free(recorded_principals); - } - recorded_principals = (krb5_principal *) NULL; - - if (recorded_names) { - for (i=0; i<nentries; i++) { - if (recorded_names[i]) - free(recorded_names[i]); - } - free(recorded_names); - } - recorded_names = (char **) NULL; -} - -/* - * Initialize the recorded names list. - */ -static void -init_princ_recording(kcontext, nentries) - krb5_context kcontext; - int nentries; -{ - recorded_principals = (krb5_principal *) - malloc(nentries * sizeof(krb5_principal)); - if (!recorded_principals) - abort(); - memset((char *) recorded_principals, 0, - nentries * sizeof(krb5_principal)); - recorded_names = (char **) malloc(nentries * sizeof(char *)); - if (!recorded_names) - abort(); - memset((char *) recorded_names, 0, nentries * sizeof(char *)); -} - -/* - * Record a principal and name. - */ -static void -record_principal(slotno, princ, pname) - int slotno; - krb5_principal princ; - char *pname; -{ - recorded_principals[slotno] = princ; - recorded_names[slotno] = (char *) malloc(strlen(pname)+1); - if (recorded_names[slotno]) - strcpy(recorded_names[slotno], pname); -} - -#define playback_principal(slotno) (recorded_principals[slotno]) -#define playback_name(slotno) (recorded_names[slotno]) - -/* - * See if a principal already exists. - */ -static krb5_boolean -principal_found(nvalid, pname) - int nvalid; - char *pname; -{ - krb5_boolean found; - int i; - - found = 0; - for (i=0; i<nvalid; i++) { - if (!strcmp(recorded_names[i], pname)) { - found = 1; - break; - } - } - return(found); -} - -/* - * Add a principal to the database. - */ -static krb5_error_code -add_principal(kcontext, principal, mkey, key) - krb5_context kcontext; - krb5_principal principal; - krb5_keyblock * mkey; - krb5_keyblock * key; -{ - krb5_error_code kret; - krb5_db_entry dbent; - krb5_keyblock * rkey = NULL, lkey; - krb5_timestamp timenow; - int nentries = 1; - - memset((char *) &dbent, 0, sizeof(dbent)); - dbent.len = KRB5_KDB_V1_BASE_LENGTH; - - dbent.attributes = KRB5_KDB_DEF_FLAGS; - dbent.max_life = KRB5_KDB_MAX_LIFE; - dbent.expiration = KRB5_KDB_EXPIRATION; - dbent.max_renewable_life = KRB5_KDB_MAX_RLIFE; - - if ((kret = krb5_copy_principal(kcontext, principal, &dbent.princ))) - goto out; - - if ((kret = krb5_timeofday(kcontext, &timenow))) - goto out; - if ((kret = krb5_dbe_update_mod_princ_data(kcontext, &dbent, - timenow, principal))) - goto out; - - if (!key) { - kret = krb5_c_make_random_key (kcontext, mkey->enctype, &lkey); - if (kret) - goto out; - rkey = &lkey; - } else - rkey = key; - - if ((kret = krb5_dbe_create_key_data(kcontext, &dbent))) - goto out; - if ((kret = krb5_dbekd_encrypt_key_data(kcontext, mkey, rkey, NULL, 1, - &dbent.key_data[0]))) - goto out; - - if (!key) - krb5_free_keyblock_contents(kcontext, rkey); - - kret = krb5_db_put_principal(kcontext, &dbent, &nentries); - if ((!kret) && (nentries != 1)) - kret = KRB5_KDB_UK_SERROR; - out: - krb5_dbe_free_contents(kcontext, &dbent); - return(kret); -} - -/* - * Generate a principal name. - */ -static krb5_error_code -gen_principal(kcontext, realm, do_rand, n, princp, namep) - krb5_context kcontext; - char *realm; - int do_rand; - int n; - krb5_principal *princp; - char **namep; -{ - static char pnamebuf[MAX_PNAME_LEN]; - static char *instnames[] = { - "instance1", "xxx2", "whereami3", "ABCDEFG4", "foofoo5" }; - static char *princnames[] = { - "princ1", "user2", "service3" }; - - krb5_error_code kret; - char *instname; - char *princbase; - int ncomps; - int i, complen, j; - char *cp; - - if (do_rand) { - ncomps = RANDOM(1,MAX_PRINC_COMPS); - cp = pnamebuf; - for (i=0; i<ncomps; i++) { - complen = RANDOM(1,MAX_COMP_SIZE); - for (j=0; j<complen; j++) { - *cp = (char) RANDOM(0,256); - while (!isalnum(*cp & 0xff)) - *cp = (char) RANDOM(0,256); - cp++; - if(cp + strlen(realm) >= pnamebuf + sizeof(pnamebuf)) - break; - } - if(cp + strlen(realm) >= pnamebuf + sizeof(pnamebuf)) - break; - *cp = '/'; - cp++; - } - if(cp + strlen(realm) < pnamebuf + sizeof(pnamebuf)) { - cp[-1] = '@'; - strcpy(cp, realm); - } else { - strcpy(cp , ""); - } - } - else { - instname = instnames[n % (sizeof(instnames)/sizeof(instnames[0]))]; - princbase = princnames[n % (sizeof(princnames)/sizeof(princnames[0]))]; - sprintf(pnamebuf, "%s%d/%s@%s", princbase, n, instname, realm); - } - kret = krb5_parse_name(kcontext, pnamebuf, princp); - *namep = (!kret) ? pnamebuf : (char *) NULL; - return(kret); -} - -/* - * Find a principal in the database. - */ -static krb5_error_code -find_principal(kcontext, principal, docompare) - krb5_context kcontext; - krb5_principal principal; - krb5_boolean docompare; -{ - krb5_error_code kret; - krb5_db_entry dbent; - krb5_principal mod_princ; - krb5_timestamp mod_time; - int how_many; - krb5_boolean more; - - more = 0; - how_many = 1; - if ((kret = krb5_db_get_principal(kcontext, principal, &dbent, - &how_many, &more))) - return(kret); - if (how_many == 0) - return(KRB5_KDB_NOENTRY); - - if ((kret = krb5_dbe_lookup_mod_princ_data(kcontext, &dbent, - &mod_time, &mod_princ))) - - return(kret); - - if (docompare) { - if ((dbent.max_life != KRB5_KDB_MAX_LIFE) || - (dbent.max_renewable_life != KRB5_KDB_MAX_RLIFE) || - (dbent.expiration != KRB5_KDB_EXPIRATION) || - (dbent.attributes != KRB5_KDB_DEF_FLAGS) || - !krb5_principal_compare(kcontext, principal, dbent.princ) || - !krb5_principal_compare(kcontext, principal, mod_princ)) - kret = KRB5_PRINC_NOMATCH; - } - - krb5_db_free_principal(kcontext, &dbent, how_many); - krb5_free_principal(kcontext, mod_princ); - if (!kret) - return(((how_many == 1) && (more == 0)) ? 0 : KRB5KRB_ERR_GENERIC); - else - return(kret); - -} - -/* - * Delete a principal. - */ -static krb5_error_code -delete_principal(kcontext, principal) - krb5_context kcontext; - krb5_principal principal; -{ - krb5_error_code kret; - int num2delete; - - num2delete = 1; - if ((kret = krb5_db_delete_principal(kcontext, principal, &num2delete))) - return(kret); - return((num2delete == 1) ? 0 : KRB5KRB_ERR_GENERIC); -} - -static int -do_testing(db, passes, verbose, timing, rcases, check, save_db, dontclean, - ptest, hash) - char *db; - int passes; - int verbose; - int timing; - int rcases; - int check; - int save_db; - int dontclean; - int ptest; - int hash; -{ - krb5_error_code kret; - krb5_context kcontext; - char *op, *linkage, *oparg; - krb5_principal master_princ; - int master_princ_set = 0; - char *mkey_name; - char *realm; - char *mkey_fullname; - char *master_passwd; - krb5_data salt_data; - krb5_encrypt_block master_encblock; - krb5_keyblock master_keyblock; - krb5_data passwd; - krb5_pointer rseed; - krb5_boolean db_open, db_created; - int passno; - krb5_principal principal; - char *pname; - float elapsed; - krb5_keyblock stat_kb; - krb5_int32 crflags; - - mkey_name = "master/key"; - realm = master_princ_data.realm.data; - mkey_fullname = (char *) NULL; - master_princ = (krb5_principal) NULL; - master_passwd = "master_password"; - db_open = 0; - db_created = 0; - linkage = ""; - oparg = ""; - crflags = hash ? KRB5_KDB_CREATE_HASH : KRB5_KDB_CREATE_BTREE; - - memset(&master_keyblock, 0, sizeof(master_keyblock)); - - /* Set up some initial context */ - op = "initializing krb5"; - kret = krb5_init_context(&kcontext); - if (kret) - goto goodbye; - - /* - * The database had better not exist. - */ - op = "making sure database doesn't exist"; - if (!(kret = krb5_db_set_name(kcontext, db))) { - kret = EEXIST; - goto goodbye; - } - - /* Set up the master key name */ - op = "setting up master key name"; - if ((kret = krb5_db_setup_mkey_name(kcontext, mkey_name, realm, - &mkey_fullname, &master_princ))) - goto goodbye; - - master_princ_set = 1; - if (verbose) - fprintf(stdout, "%s: Initializing '%s', master key is '%s'\n", - programname, db, mkey_fullname); - - free(mkey_fullname); - mkey_fullname = 0; - - op = "salting master key"; - if ((kret = krb5_principal2salt(kcontext, master_princ, &salt_data))) - goto goodbye; - - op = "converting master key"; - krb5_use_enctype(kcontext, &master_encblock, DEFAULT_KDC_ENCTYPE); - master_keyblock.enctype = DEFAULT_KDC_ENCTYPE; - passwd.length = strlen(master_passwd); - passwd.data = master_passwd; - if ((kret = krb5_string_to_key(kcontext, &master_encblock, - &master_keyblock, &passwd, &salt_data))) - goto goodbye; - /* Clean up */ - free(salt_data.data); - - /* Process master key */ - op = "processing master key"; - if ((kret = krb5_process_key(kcontext, &master_encblock, - &master_keyblock))) - goto goodbye; - - /* Initialize random key generator */ - op = "initializing random key generator"; - if ((kret = krb5_init_random_key(kcontext, - &master_encblock, - &master_keyblock, - &rseed))) - goto goodbye; - - /* Create database */ - op = "creating database"; - if ((kret = krb5_db_create(kcontext, db, crflags))) - goto goodbye; - - db_created = 1; - - /* Set this database as active. */ - op = "setting active database"; - if ((kret = krb5_db_set_name(kcontext, db))) - goto goodbye; - - /* Initialize database */ - op = "initializing database"; - if ((kret = krb5_db_init(kcontext))) - goto goodbye; - - db_open = 1; - op = "adding master principal"; - if ((kret = add_principal(kcontext, - master_princ, - &master_keyblock, - &master_keyblock))) - goto goodbye; - - - stat_kb.enctype = DEFAULT_KDC_ENCTYPE; - stat_kb.length = 8; - stat_kb.contents = (krb5_octet *) "helpmeee"; - - /* We are now ready to proceed to test. */ - if (verbose) - fprintf(stdout, "%s: Beginning %stest\n", - programname, (rcases) ? "random " : ""); - init_princ_recording(kcontext, passes); - if (rcases) { - struct tacc { - float t_time; - int t_number; - } accumulated[3]; - int i, nvalid, discrim, highwater, coinflip; - krb5_keyblock *kbp; - - /* Generate random cases */ - for (i=0; i<3; i++) { - accumulated[i].t_time = 0.0; - accumulated[i].t_number = 0; - } - - /* - * Generate principal names. - */ - if (verbose > 1) - fprintf(stdout, "%s: generating %d names\n", - programname, passes); - for (passno=0; passno<passes; passno++) { - op = "generating principal name"; - do { - if ((kret = gen_principal(kcontext, realm, rcases, - passno, &principal, &pname))) - goto goodbye; - } while (principal_found(passno-1, pname)); - record_principal(passno, principal, pname); - } - - /* Prime the database with some number of entries */ - nvalid = passes/4; - if (nvalid < 10) - nvalid = 10; - if (nvalid > passes) - nvalid = passes; - - if (verbose > 1) - fprintf(stdout, "%s: priming database with %d principals\n", - programname, nvalid); - highwater = 0; - for (passno=0; passno<nvalid; passno++) { - op = "adding principal"; - coinflip = RANDOM(0,2); - kbp = (coinflip) ? &stat_kb : (krb5_keyblock *) NULL; - if (timing) { - swatch_on(); - } - if ((kret = add_principal(kcontext, playback_principal(passno), - &master_keyblock, kbp))) { - linkage = "initially "; - oparg = playback_name(passno); - goto cya; - } - if (timing) { - elapsed = swatch_eltime(); - accumulated[0].t_time += elapsed; - accumulated[0].t_number++; - } - if (verbose > 4) - fprintf(stderr, "*A(%s)\n", playback_name(passno)); - highwater++; - } - - if (verbose > 1) - fprintf(stderr, "%s: beginning random loop\n", programname); - /* Loop through some number of times and pick random operations */ - for (i=0; i<3*passes; i++) { - discrim = RANDOM(0,100); - - /* Add a principal 25% of the time, if possible */ - if ((discrim < 25) && (nvalid < passes)) { - op = "adding principal"; - coinflip = RANDOM(0,2); - kbp = (coinflip) ? &stat_kb : (krb5_keyblock *) NULL; - if (timing) { - swatch_on(); - } - if ((kret = add_principal(kcontext, - playback_principal(nvalid), - &master_keyblock, kbp))) { - oparg = playback_name(nvalid); - goto cya; - } - if (timing) { - elapsed = swatch_eltime(); - accumulated[0].t_time += elapsed; - accumulated[0].t_number++; - } - if (verbose > 4) - fprintf(stderr, "*A(%s)\n", playback_name(nvalid)); - nvalid++; - if (nvalid > highwater) - highwater = nvalid; - } - /* Delete a principal 15% of the time, if possible */ - else if ((discrim > 85) && (nvalid > 10)) { - op = "deleting principal"; - if (timing) { - swatch_on(); - } - if ((kret = delete_principal(kcontext, - playback_principal(nvalid-1)))) { - oparg = playback_name(nvalid-1); - goto cya; - } - if (timing) { - elapsed = swatch_eltime(); - accumulated[2].t_time += elapsed; - accumulated[2].t_number++; - } - if (verbose > 4) - fprintf(stderr, "XD(%s)\n", playback_name(nvalid-1)); - nvalid--; - } - /* Otherwise, find a principal */ - else { - op = "looking up principal"; - passno = RANDOM(0, nvalid); - if (timing) { - swatch_on(); - } - if ((kret = find_principal(kcontext, - playback_principal(passno), - check))) { - oparg = playback_name(passno); - goto cya; - } - if (timing) { - elapsed = swatch_eltime(); - accumulated[1].t_time += elapsed; - accumulated[1].t_number++; - } - if (verbose > 4) - fprintf(stderr, "-S(%s)\n", playback_name(passno)); - } - } - - if (!dontclean) { - /* Clean up the remaining principals */ - if (verbose > 1) - fprintf(stdout, "%s: deleting remaining %d principals\n", - programname, nvalid); - for (passno=0; passno<nvalid; passno++) { - op = "deleting principal"; - if (timing) { - swatch_on(); - } - if ((kret = delete_principal(kcontext, - playback_principal(passno)))) { - linkage = "finally "; - oparg = playback_name(passno); - goto cya; - } - if (timing) { - elapsed = swatch_eltime(); - accumulated[2].t_time += elapsed; - accumulated[2].t_number++; - } - if (verbose > 4) - fprintf(stderr, "XD(%s)\n", playback_name(passno)); - } - } - cya: - if (verbose) - fprintf(stdout, - "%s: highwater mark was %d principals\n", - programname, highwater); - if (accumulated[0].t_number && timing) - fprintf(stdout, - "%s: performed %8d additions in %9.4f seconds (%9.4f/add)\n", - programname, accumulated[0].t_number, - accumulated[0].t_time, - accumulated[0].t_time / (float) accumulated[0].t_number); - if (accumulated[1].t_number && timing) - fprintf(stdout, - "%s: performed %8d lookups in %9.4f seconds (%9.4f/search)\n", - programname, accumulated[1].t_number, - accumulated[1].t_time, - accumulated[1].t_time / (float) accumulated[1].t_number); - if (accumulated[2].t_number && timing) - fprintf(stdout, - "%s: performed %8d deletions in %9.4f seconds (%9.4f/delete)\n", - programname, accumulated[2].t_number, - accumulated[2].t_time, - accumulated[2].t_time / (float) accumulated[2].t_number); - if (kret) - goto goodbye; - } - else { - /* - * Generate principal names. - */ - for (passno=0; passno<passes; passno++) { - op = "generating principal name"; - if ((kret = gen_principal(kcontext, realm, rcases, - passno, &principal, &pname))) - goto goodbye; - record_principal(passno, principal, pname); - } - /* - * Add principals. - */ - if (timing) { - swatch_on(); - } - for (passno=0; passno<passes; passno++) { - op = "adding principal"; - if ((kret = add_principal(kcontext, playback_principal(passno), - &master_keyblock, &stat_kb))) - goto goodbye; - if (verbose > 4) - fprintf(stderr, "*A(%s)\n", playback_name(passno)); - } - if (timing) { - elapsed = swatch_eltime(); - fprintf(stdout, - "%s: added %d principals in %9.4f seconds (%9.4f/add)\n", - programname, passes, elapsed, elapsed/((float) passes)); - } - - /* - * Lookup principals. - */ - if (timing) { - swatch_on(); - } - for (passno=0; passno<passes; passno++) { - op = "looking up principal"; - if ((kret = find_principal(kcontext, playback_principal(passno), - check))) - goto goodbye; - if (verbose > 4) - fprintf(stderr, "-S(%s)\n", playback_name(passno)); - } - if (timing) { - elapsed = swatch_eltime(); - fprintf(stdout, - "%s: found %d principals in %9.4f seconds (%9.4f/search)\n", - programname, passes, elapsed, elapsed/((float) passes)); - } - - /* - * Delete principals. - */ - if (!dontclean) { - if (timing) { - swatch_on(); - } - for (passno=passes-1; passno>=0; passno--) { - op = "deleting principal"; - if ((kret = delete_principal(kcontext, - playback_principal(passno)))) - goto goodbye; - if (verbose > 4) - fprintf(stderr, "XD(%s)\n", playback_name(passno)); - } - if (timing) { - elapsed = swatch_eltime(); - fprintf(stdout, - "%s: deleted %d principals in %9.4f seconds (%9.4f/delete)\n", - programname, passes, elapsed, - elapsed/((float) passes)); - } - } - - } - - goodbye: - if(master_princ_set) { - krb5_free_principal(kcontext, master_princ); - } - if (kret) - fprintf(stderr, "%s: error while %s %s%s(%s)\n", - programname, op, linkage, oparg, error_message(kret)); - - if (!kret && ptest) { - int nper; - pid_t children[32], child; - int nprocs, existat, i, j, fd; - - nprocs = ptest + 1; - if (nprocs > 32) - nprocs = 32; - - nper = passes / nprocs; - unlink("./test.lock"); - for (i=0; i<nprocs; i++) { - child = fork(); - if (child == 0) { - /* Child */ - int base; - krb5_context ccontext; - struct stat stbuf; - - while (stat("./test.lock", &stbuf) == -1) - kret = krb5_init_context(&ccontext); - if (kret) { - com_err(programname, kret, "while initializing krb5"); - exit(1); - } - if ((kret = krb5_db_set_name(ccontext, db)) || - (kret = krb5_db_init(ccontext))) - exit(1); - base = i*nper; - for (j=0; j<nper; j++) { - if ((kret = add_principal(ccontext, - playback_principal(base+j), - &master_keyblock, - &stat_kb))) { - fprintf(stderr, - "%ld: (%d,%d) Failed add of %s with %s\n", - (long) getpid(), i, j, playback_name(base+j), - error_message(kret)); - break; - } - if (verbose > 4) - fprintf(stderr, "*A[%ld](%s)\n", (long) getpid(), - playback_name(base+j)); - } - for (j=0; (j<nper) && (!kret); j++) { - if ((kret = find_principal(ccontext, - playback_principal(base+j), - check))) { - fprintf(stderr, - "%ld: (%d,%d) Failed lookup of %s with %s\n", - (long) getpid(), i, j, playback_name(base+j), - error_message(kret)); - break; - } - if (verbose > 4) - fprintf(stderr, "-S[%ld](%s)\n", (long) getpid(), - playback_name(base+j)); - } - for (j=0; (j<nper) && (!kret); j++) { - if ((kret = delete_principal(ccontext, - playback_principal(base+j)))) { - fprintf(stderr, - "%ld: (%d,%d) Failed delete of %s with %s\n", - (long) getpid(), i, j, playback_name(base+j), - error_message(kret)); - break; - } - if (verbose > 4) - fprintf(stderr, "XD[%ld](%s)\n", (long) getpid(), - playback_name(base+j)); - } - krb5_db_fini(ccontext); - krb5_free_context(ccontext); - exit((kret) ? 1 : 0); - } - else - children[i] = child; - } - fd = open("./test.lock", O_CREAT|O_RDWR|O_EXCL, 0666); - close(fd); - sleep(1); - unlink("./test.lock"); - for (i=0; i<nprocs; i++) { - if (waitpid(children[i], &existat, 0) == children[i]) { - if (verbose) - fprintf(stderr, "%ld finished with %d\n", - (long) children[i], existat); - if (existat) - kret = KRB5KRB_ERR_GENERIC; - } - else - fprintf(stderr, "Wait for %ld failed\n", (long) children[i]); - } - } - - free_principals(kcontext, passes); - if (db_open) - (void) krb5_db_fini(kcontext); - if (db_created) { - if (!kret && !save_db) { - krb5_db_destroy(kcontext, db); - krb5_db_fini(kcontext); - } else { - if (kret && verbose) - fprintf(stderr, "%s: database not deleted because of error\n", - programname); - } - } - - krb5_free_keyblock_contents(kcontext, &master_keyblock); - krb5_free_context(kcontext); - - return((kret) ? 1 : 0); -} - -/* - * usage: - * t_kdb [-t] - Get timing information. - * [-r] - Generate random cases. - * [-n <num>] - Use <num> as the number of passes. - * [-c] - Check contents. - * [-v] - Verbose output. - * [-d <dbname>] - Database name. - * [-s] - Save database even on successful completion. - * [-D] - Leave database dirty. - */ -int -main(argc, argv) - int argc; - char *argv[]; -{ - int option; - extern char *optarg; - - int do_time, do_random, num_passes, check_cont, verbose, error; - int save_db, dont_clean, do_ptest, hash; - char *db_name; - - programname = argv[0]; - if (strrchr(programname, (int) '/')) - programname = strrchr(programname, (int) '/') + 1; - SRAND((RAND_TYPE)time((void *) NULL)); - - /* Default values. */ - do_time = 0; - do_random = 0; - num_passes = T_KDB_N_PASSES; - check_cont = 0; - verbose = 0; - db_name = T_KDB_DEF_DB; - save_db = 0; - dont_clean = 0; - error = 0; - do_ptest = 0; - hash = 0; - - /* Parse argument list */ - while ((option = getopt(argc, argv, "cd:n:prstvDh")) != -1) { - switch (option) { - case 'c': - check_cont = 1; - break; - case 'd': - db_name = optarg; - break; - case 'n': - if (sscanf(optarg, "%d", &num_passes) != 1) { - fprintf(stderr, "%s: %s is not a valid number for %c option\n", - programname, optarg, option); - error++; - } - break; - case 'p': - do_ptest++; - break; - case 'r': - do_random = 1; - break; - case 's': - save_db = 1; - break; - case 't': - do_time = 1; - break; - case 'v': - verbose++; - break; - case 'D': - dont_clean = 1; - break; - case 'h': - hash = 1; - break; - default: - error++; - break; - } - } - if (error) - fprintf(stderr, "%s: usage is %s [-cprstv] [-d <dbname>] [-n <num>]\n", - programname, programname); - else - error = do_testing(db_name, - num_passes, - verbose, - do_time, - do_random, - check_cont, - save_db, - dont_clean, - do_ptest, - hash); - return(error); -} - - diff --git a/src/lib/kdb/t_krb5.conf b/src/lib/kdb/t_krb5.conf deleted file mode 100644 index 5882d97..0000000 --- a/src/lib/kdb/t_krb5.conf +++ /dev/null @@ -1,29 +0,0 @@ -[libdefaults] - ticket_lifetime = 600 - default_realm = ATHENA.MIT.EDU - -[realms] - ATHENA.MIT.EDU = { - kdc = KERBEROS-2.MIT.EDU:88 - kdc = KERBEROS.MIT.EDU - kdc = KERBEROS-1.MIT.EDU - admin_server = KERBEROS.MIT.EDU - default_domain = MIT.EDU - v4_instance_convert = { - mit = mit.edu - lithium = lithium.lcs.mit.edu - } - } - CYGNUS.COM = { - kdc = KERBEROS-1.CYGNUS.COM - kdc = KERBEROS.CYGNUS.COM - admin_server = KERBEROS.MIT.EDU - } - -[domain_realm] - .mit.edu = ATHENA.MIT.EDU - mit.edu = ATHENA.MIT.EDU - .media.mit.edu = MEDIA-LAB.MIT.EDU - media.mit.edu = MEDIA-LAB.MIT.EDU - .ucsc.edu = CATS.UCSC.EDU - diff --git a/src/lib/kdb/verify_mky.c b/src/lib/kdb/verify_mky.c deleted file mode 100644 index 452dc45..0000000 --- a/src/lib/kdb/verify_mky.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * lib/kdb/verify_mky.c - * - * Copyright 1990,1991 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. - * - * - * krb5_db_verify_master_key(); - */ - -#include "k5-int.h" - -/* - * Verify that the master key in *mkey matches the database entry - * for mprinc. - */ - -krb5_error_code -krb5_db_verify_master_key(context, mprinc, mkey) - krb5_context context; - krb5_principal mprinc; - krb5_keyblock *mkey; -{ - krb5_error_code retval; - krb5_db_entry master_entry; - int nprinc; - krb5_boolean more; - krb5_keyblock tempkey; - - nprinc = 1; - if ((retval = krb5_db_get_principal(context, mprinc, - &master_entry, &nprinc, &more))) - return(retval); - - if (nprinc != 1) { - if (nprinc) - krb5_db_free_principal(context, &master_entry, nprinc); - return(KRB5_KDB_NOMASTERKEY); - } else if (more) { - krb5_db_free_principal(context, &master_entry, nprinc); - return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); - } - - if ((retval = krb5_dbekd_decrypt_key_data(context, mkey, - &master_entry.key_data[0], - &tempkey, NULL))) { - krb5_db_free_principal(context, &master_entry, nprinc); - return retval; - } - - if (mkey->length != tempkey.length || - memcmp((char *)mkey->contents, - (char *)tempkey.contents,mkey->length)) { - retval = KRB5_KDB_BADMASTERKEY; - } - - memset((char *)tempkey.contents, 0, tempkey.length); - krb5_xfree(tempkey.contents); - krb5_db_free_principal(context, &master_entry, nprinc); - - return retval; -} |