diff options
Diffstat (limited to 'lib/hdb')
-rw-r--r-- | lib/hdb/Makefile.am | 41 | ||||
-rw-r--r-- | lib/hdb/Makefile.in | 531 | ||||
-rw-r--r-- | lib/hdb/NTMakefile | 17 | ||||
-rw-r--r-- | lib/hdb/common.c | 140 | ||||
-rw-r--r-- | lib/hdb/db.c | 143 | ||||
-rw-r--r-- | lib/hdb/db3.c | 235 | ||||
-rw-r--r-- | lib/hdb/dbinfo.c | 41 | ||||
-rw-r--r-- | lib/hdb/ext.c | 106 | ||||
-rw-r--r-- | lib/hdb/hdb-ldap.c | 231 | ||||
-rw-r--r-- | lib/hdb/hdb-mdb.c | 399 | ||||
-rw-r--r-- | lib/hdb/hdb-mitdb.c | 1013 | ||||
-rw-r--r-- | lib/hdb/hdb-private.h | 22 | ||||
-rw-r--r-- | lib/hdb/hdb-protos.h | 180 | ||||
-rw-r--r-- | lib/hdb/hdb-sqlite.c | 446 | ||||
-rw-r--r-- | lib/hdb/hdb.asn1 | 27 | ||||
-rw-r--r-- | lib/hdb/hdb.c | 318 | ||||
-rw-r--r-- | lib/hdb/hdb.h | 61 | ||||
-rw-r--r-- | lib/hdb/hdb.schema | 7 | ||||
-rw-r--r-- | lib/hdb/hdb_err.et | 3 | ||||
-rw-r--r-- | lib/hdb/hdb_locl.h | 3 | ||||
-rw-r--r-- | lib/hdb/keys.c | 527 | ||||
-rw-r--r-- | lib/hdb/keytab.c | 24 | ||||
-rw-r--r-- | lib/hdb/libhdb-exports.def | 20 | ||||
-rw-r--r-- | lib/hdb/mkey.c | 187 | ||||
-rw-r--r-- | lib/hdb/print.c | 372 | ||||
-rw-r--r-- | lib/hdb/test_dbinfo.c | 4 | ||||
-rw-r--r-- | lib/hdb/test_hdbkeys.c | 12 | ||||
-rw-r--r-- | lib/hdb/test_hdbplugin.c | 107 | ||||
-rw-r--r-- | lib/hdb/test_mkey.c | 6 | ||||
-rw-r--r-- | lib/hdb/version-script.map | 34 |
30 files changed, 4241 insertions, 1016 deletions
diff --git a/lib/hdb/Makefile.am b/lib/hdb/Makefile.am index b629f56258d2..448b0242f3e7 100644 --- a/lib/hdb/Makefile.am +++ b/lib/hdb/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 $(INCLUDE_hcrypto) +AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 AM_CPPFLAGS += $(INCLUDE_openldap) -DHDB_DB_DIR=\"$(DIR_hdbdir)\" AM_CPPFLAGS += -I$(srcdir)/../krb5 AM_CPPFLAGS += $(INCLUDE_sqlite3) @@ -29,22 +29,24 @@ gen_files_hdb = \ asn1_HDB_Ext_Lan_Manager_OWF.x \ asn1_HDB_Ext_Password.x \ asn1_HDB_Ext_Aliases.x \ + asn1_HDB_Ext_KeySet.x \ asn1_HDB_extension.x \ asn1_HDB_extensions.x \ asn1_hdb_entry.x \ asn1_hdb_entry_alias.x \ - asn1_hdb_keyset.x + asn1_hdb_keyset.x \ + asn1_Keys.x CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \ - hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.c* + hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.[cx] LDADD = libhdb.la \ - $(LIB_openldap) \ - $(LIB_libintl) \ ../krb5/libkrb5.la \ ../asn1/libasn1.la \ $(LIB_hcrypto) \ $(LIB_roken) \ + $(LIB_openldap) \ + $(LIB_libintl) \ $(LIB_ldopen) @@ -70,7 +72,7 @@ if versionscript libhdb_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map endif -noinst_PROGRAMS = test_dbinfo test_hdbkeys test_mkey +noinst_PROGRAMS = test_dbinfo test_hdbkeys test_mkey test_hdbplugin dist_libhdb_la_SOURCES = \ common.c \ @@ -81,9 +83,9 @@ dist_libhdb_la_SOURCES = \ hdb.c \ hdb-sqlite.c \ hdb-keytab.c \ + hdb-mdb.c \ hdb-mitdb.c \ hdb_locl.h \ - hdb-private.h \ keys.c \ keytab.c \ dbinfo.c \ @@ -95,9 +97,11 @@ nodist_libhdb_la_SOURCES = $(BUILT_SOURCES) libhdb_la_DEPENDENCIES = version-script.map -include_HEADERS = hdb.h hdb-protos.h +include_HEADERS = hdb.h $(srcdir)/hdb-protos.h nodist_include_HEADERS = hdb_err.h hdb_asn1.h +noinst_HEADERS = $(srcdir)/hdb-private.h + libhdb_la_LIBADD = \ $(LIB_com_err) \ ../krb5/libkrb5.la \ @@ -106,27 +110,34 @@ libhdb_la_LIBADD = \ $(LIBADD_roken) \ $(ldap_lib) \ $(LIB_dlopen) \ - $(DBLIB) \ - $(LIB_NDBM) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) + +HDB_PROTOS = $(srcdir)/hdb-protos.h $(srcdir)/hdb-private.h + +ALL_OBJECTS = $(libhdb_la_OBJECTS) +ALL_OBJECTS += $(test_dbinfo_OBJECTS) +ALL_OBJECTS += $(test_hdbkeys_OBJECTS) +ALL_OBJECTS += $(test_mkey_OBJECTS) +ALL_OBJECTS += $(test_hdbplugin_OBJECTS) -$(libhdb_la_OBJECTS): $(srcdir)/hdb-protos.h $(srcdir)/hdb-private.h -$(libhdb_la_OBJECTS): hdb_asn1.h hdb_asn1-priv.h hdb_err.h +$(ALL_OBJECTS): $(HDB_PROTOS) hdb_asn1.h hdb_asn1-priv.h hdb_err.h -$(srcdir)/hdb-protos.h: +$(srcdir)/hdb-protos.h: $(dist_libhdb_la_SOURCES) cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -o hdb-protos.h $(dist_libhdb_la_SOURCES) || rm -f hdb-protos.h -$(srcdir)/hdb-private.h: +$(srcdir)/hdb-private.h: $(dist_libhdb_la_SOURCES) cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p hdb-private.h $(dist_libhdb_la_SOURCES) || rm -f hdb-private.h $(gen_files_hdb) hdb_asn1.hx hdb_asn1-priv.hx: hdb_asn1_files hdb_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/hdb.asn1 - $(ASN1_COMPILE) $(srcdir)/hdb.asn1 hdb_asn1 + $(ASN1_COMPILE) --sequence=HDB-Ext-KeySet --sequence=Keys $(srcdir)/hdb.asn1 hdb_asn1 test_dbinfo_LIBS = libhdb.la test_hdbkeys_LIBS = ../krb5/libkrb5.la libhdb.la test_mkey_LIBS = $(test_hdbkeys_LIBS) +test_hdbplugin_LIBS = $(test_hdbkeys_LIBS) # to help stupid solaris make diff --git a/lib/hdb/Makefile.in b/lib/hdb/Makefile.in index 9fcd77000c47..065c4fc1ae5e 100644 --- a/lib/hdb/Makefile.in +++ b/lib/hdb/Makefile.in @@ -1,9 +1,8 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.15.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# Copyright (C) 1994-2017 Free Software Foundation, Inc. + # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -24,6 +23,61 @@ VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -42,13 +96,10 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in $(top_srcdir)/Makefile.am.common \ - $(top_srcdir)/cf/Makefile.am.common @HAVE_DBHEADER_TRUE@am__append_1 = -I$(DBHEADER) @versionscript_TRUE@am__append_2 = $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map noinst_PROGRAMS = test_dbinfo$(EXEEXT) test_hdbkeys$(EXEEXT) \ - test_mkey$(EXEEXT) + test_mkey$(EXEEXT) test_hdbplugin$(EXEEXT) subdir = lib/hdb ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \ @@ -64,8 +115,7 @@ am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \ $(top_srcdir)/cf/check-man.m4 \ $(top_srcdir)/cf/check-netinet-ip-and-tcp.m4 \ $(top_srcdir)/cf/check-type-extra.m4 \ - $(top_srcdir)/cf/check-var.m4 $(top_srcdir)/cf/check-x.m4 \ - $(top_srcdir)/cf/check-xau.m4 $(top_srcdir)/cf/crypto.m4 \ + $(top_srcdir)/cf/check-var.m4 $(top_srcdir)/cf/crypto.m4 \ $(top_srcdir)/cf/db.m4 $(top_srcdir)/cf/destdirs.m4 \ $(top_srcdir)/cf/dispatch.m4 $(top_srcdir)/cf/dlopen.m4 \ $(top_srcdir)/cf/find-func-no-libs.m4 \ @@ -78,6 +128,7 @@ am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \ $(top_srcdir)/cf/krb-bigendian.m4 \ $(top_srcdir)/cf/krb-func-getlogin.m4 \ $(top_srcdir)/cf/krb-ipv6.m4 $(top_srcdir)/cf/krb-prog-ln-s.m4 \ + $(top_srcdir)/cf/krb-prog-perl.m4 \ $(top_srcdir)/cf/krb-readline.m4 \ $(top_srcdir)/cf/krb-struct-spwd.m4 \ $(top_srcdir)/cf/krb-struct-winsize.m4 \ @@ -97,6 +148,8 @@ am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \ + $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = @@ -122,6 +175,12 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" \ "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) @@ -131,17 +190,21 @@ am__DEPENDENCIES_1 = am__hdb_ldap_la_SOURCES_DIST = hdb-ldap.c @OPENLDAP_MODULE_TRUE@am_hdb_ldap_la_OBJECTS = hdb-ldap.lo hdb_ldap_la_OBJECTS = $(am_hdb_ldap_la_OBJECTS) -hdb_ldap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +hdb_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdb_ldap_la_LDFLAGS) $(LDFLAGS) -o $@ @OPENLDAP_MODULE_TRUE@am_hdb_ldap_la_rpath = -rpath $(libdir) @OPENLDAP_MODULE_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) am__dist_libhdb_la_SOURCES_DIST = common.c db.c db3.c ext.c hdb-ldap.c \ - hdb.c hdb-sqlite.c hdb-keytab.c hdb-mitdb.c hdb_locl.h \ - hdb-private.h keys.c keytab.c dbinfo.c mkey.c ndbm.c print.c + hdb.c hdb-sqlite.c hdb-keytab.c hdb-mdb.c hdb-mitdb.c \ + hdb_locl.h keys.c keytab.c dbinfo.c mkey.c ndbm.c print.c @OPENLDAP_MODULE_FALSE@am__objects_1 = hdb-ldap.lo dist_libhdb_la_OBJECTS = common.lo db.lo db3.lo ext.lo \ - $(am__objects_1) hdb.lo hdb-sqlite.lo hdb-keytab.lo \ + $(am__objects_1) hdb.lo hdb-sqlite.lo hdb-keytab.lo hdb-mdb.lo \ hdb-mitdb.lo keys.lo keytab.lo dbinfo.lo mkey.lo ndbm.lo \ print.lo am__objects_2 = asn1_Salt.lo asn1_Key.lo asn1_Event.lo \ @@ -149,61 +212,116 @@ am__objects_2 = asn1_Salt.lo asn1_Key.lo asn1_Event.lo \ asn1_HDB_Ext_PKINIT_cert.lo asn1_HDB_Ext_PKINIT_hash.lo \ asn1_HDB_Ext_Constrained_delegation_acl.lo \ asn1_HDB_Ext_Lan_Manager_OWF.lo asn1_HDB_Ext_Password.lo \ - asn1_HDB_Ext_Aliases.lo asn1_HDB_extension.lo \ - asn1_HDB_extensions.lo asn1_hdb_entry.lo \ - asn1_hdb_entry_alias.lo asn1_hdb_keyset.lo + asn1_HDB_Ext_Aliases.lo asn1_HDB_Ext_KeySet.lo \ + asn1_HDB_extension.lo asn1_HDB_extensions.lo asn1_hdb_entry.lo \ + asn1_hdb_entry_alias.lo asn1_hdb_keyset.lo asn1_Keys.lo am__objects_3 = $(am__objects_2) hdb_err.lo nodist_libhdb_la_OBJECTS = $(am__objects_3) libhdb_la_OBJECTS = $(dist_libhdb_la_OBJECTS) \ $(nodist_libhdb_la_OBJECTS) -libhdb_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +libhdb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libhdb_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(noinst_PROGRAMS) test_dbinfo_SOURCES = test_dbinfo.c test_dbinfo_OBJECTS = test_dbinfo.$(OBJEXT) test_dbinfo_LDADD = $(LDADD) -test_dbinfo_DEPENDENCIES = libhdb.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) ../krb5/libkrb5.la ../asn1/libasn1.la \ +test_dbinfo_DEPENDENCIES = libhdb.la ../krb5/libkrb5.la \ + ../asn1/libasn1.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) test_hdbkeys_SOURCES = test_hdbkeys.c test_hdbkeys_OBJECTS = test_hdbkeys.$(OBJEXT) test_hdbkeys_LDADD = $(LDADD) -test_hdbkeys_DEPENDENCIES = libhdb.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) ../krb5/libkrb5.la ../asn1/libasn1.la \ +test_hdbkeys_DEPENDENCIES = libhdb.la ../krb5/libkrb5.la \ + ../asn1/libasn1.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +test_hdbplugin_SOURCES = test_hdbplugin.c +test_hdbplugin_OBJECTS = test_hdbplugin.$(OBJEXT) +test_hdbplugin_LDADD = $(LDADD) +test_hdbplugin_DEPENDENCIES = libhdb.la ../krb5/libkrb5.la \ + ../asn1/libasn1.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) test_mkey_SOURCES = test_mkey.c test_mkey_OBJECTS = test_mkey.$(OBJEXT) test_mkey_LDADD = $(LDADD) -test_mkey_DEPENDENCIES = libhdb.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) ../krb5/libkrb5.la ../asn1/libasn1.la \ +test_mkey_DEPENDENCIES = libhdb.la ../krb5/libkrb5.la \ + ../asn1/libasn1.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = SOURCES = $(hdb_ldap_la_SOURCES) $(dist_libhdb_la_SOURCES) \ $(nodist_libhdb_la_SOURCES) test_dbinfo.c test_hdbkeys.c \ - test_mkey.c + test_hdbplugin.c test_mkey.c DIST_SOURCES = $(am__hdb_ldap_la_SOURCES_DIST) \ $(am__dist_libhdb_la_SOURCES_DIST) test_dbinfo.c \ - test_hdbkeys.c test_mkey.c -HEADERS = $(include_HEADERS) $(nodist_include_HEADERS) + test_hdbkeys.c test_hdbplugin.c test_mkey.c +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(include_HEADERS) $(nodist_include_HEADERS) \ + $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/Makefile.am.common \ + $(top_srcdir)/cf/Makefile.am.common $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AIX_EXTRA_KAFS = @AIX_EXTRA_KAFS@ AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ +AS = @AS@ ASN1_COMPILE = @ASN1_COMPILE@ ASN1_COMPILE_DEP = @ASN1_COMPILE_DEP@ AUTOCONF = @AUTOCONF@ @@ -222,12 +340,12 @@ COMPILE_ET = @COMPILE_ET@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ +DB1LIB = @DB1LIB@ +DB3LIB = @DB3LIB@ DBHEADER = @DBHEADER@ -DBLIB = @DBLIB@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DIR_com_err = @DIR_com_err@ -DIR_hcrypto = @DIR_hcrypto@ DIR_hdbdir = @DIR_hdbdir@ DIR_roken = @DIR_roken@ DLLTOOL = @DLLTOOL@ @@ -237,17 +355,17 @@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ +ENABLE_AFS_STRING_TO_KEY = @ENABLE_AFS_STRING_TO_KEY@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GCD_MIG = @GCD_MIG@ GREP = @GREP@ GROFF = @GROFF@ INCLUDES_roken = @INCLUDES_roken@ -INCLUDE_hcrypto = @INCLUDE_hcrypto@ -INCLUDE_hesiod = @INCLUDE_hesiod@ -INCLUDE_krb4 = @INCLUDE_krb4@ INCLUDE_libedit = @INCLUDE_libedit@ INCLUDE_libintl = @INCLUDE_libintl@ INCLUDE_openldap = @INCLUDE_openldap@ +INCLUDE_openssl_crypto = @INCLUDE_openssl_crypto@ INCLUDE_readline = @INCLUDE_readline@ INCLUDE_sqlite3 = @INCLUDE_sqlite3@ INSTALL = @INSTALL@ @@ -266,12 +384,9 @@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_AUTH_SUBDIRS = @LIB_AUTH_SUBDIRS@ -LIB_NDBM = @LIB_NDBM@ -LIB_XauFileName = @LIB_XauFileName@ -LIB_XauReadAuth = @LIB_XauReadAuth@ -LIB_XauWriteAuth = @LIB_XauWriteAuth@ LIB_bswap16 = @LIB_bswap16@ LIB_bswap32 = @LIB_bswap32@ +LIB_bswap64 = @LIB_bswap64@ LIB_com_err = @LIB_com_err@ LIB_com_err_a = @LIB_com_err_a@ LIB_com_err_so = @LIB_com_err_so@ @@ -280,6 +395,7 @@ LIB_db_create = @LIB_db_create@ LIB_dbm_firstkey = @LIB_dbm_firstkey@ LIB_dbopen = @LIB_dbopen@ LIB_dispatch_async_f = @LIB_dispatch_async_f@ +LIB_dladdr = @LIB_dladdr@ LIB_dlopen = @LIB_dlopen@ LIB_dn_expand = @LIB_dn_expand@ LIB_dns_search = @LIB_dns_search@ @@ -296,10 +412,8 @@ LIB_hcrypto = @LIB_hcrypto@ LIB_hcrypto_a = @LIB_hcrypto_a@ LIB_hcrypto_appl = @LIB_hcrypto_appl@ LIB_hcrypto_so = @LIB_hcrypto_so@ -LIB_hesiod = @LIB_hesiod@ LIB_hstrerror = @LIB_hstrerror@ LIB_kdb = @LIB_kdb@ -LIB_krb4 = @LIB_krb4@ LIB_libedit = @LIB_libedit@ LIB_libintl = @LIB_libintl@ LIB_loadquery = @LIB_loadquery@ @@ -307,6 +421,7 @@ LIB_logout = @LIB_logout@ LIB_logwtmp = @LIB_logwtmp@ LIB_openldap = @LIB_openldap@ LIB_openpty = @LIB_openpty@ +LIB_openssl_crypto = @LIB_openssl_crypto@ LIB_otp = @LIB_otp@ LIB_pidfile = @LIB_pidfile@ LIB_readline = @LIB_readline@ @@ -321,12 +436,15 @@ LIB_sqlite3 = @LIB_sqlite3@ LIB_syslog = @LIB_syslog@ LIB_tgetent = @LIB_tgetent@ LIPO = @LIPO@ +LMDBLIB = @LMDBLIB@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ +NDBMLIB = @NDBMLIB@ NM = @NM@ NMEDIT = @NMEDIT@ NO_AFS = @NO_AFS@ @@ -343,6 +461,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LDADD = @PTHREAD_LDADD@ @@ -357,13 +476,7 @@ STRIP = @STRIP@ VERSION = @VERSION@ VERSIONING = @VERSIONING@ WFLAGS = @WFLAGS@ -WFLAGS_NOIMPLICITINT = @WFLAGS_NOIMPLICITINT@ -WFLAGS_NOUNUSED = @WFLAGS_NOUNUSED@ -XMKMF = @XMKMF@ -X_CFLAGS = @X_CFLAGS@ -X_EXTRA_LIBS = @X_EXTRA_LIBS@ -X_LIBS = @X_LIBS@ -X_PRE_LIBS = @X_PRE_LIBS@ +WFLAGS_LITE = @WFLAGS_LITE@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ @@ -387,6 +500,8 @@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ +db_type = @db_type@ +db_type_preference = @db_type_preference@ docdir = @docdir@ dpagaix_cflags = @dpagaix_cflags@ dpagaix_ldadd = @dpagaix_ldadd@ @@ -422,32 +537,40 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUFFIXES = .et .h .x .z .hx .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 +SUFFIXES = .et .h .pc.in .pc .x .z .hx .1 .3 .5 .7 .8 .cat1 .cat3 \ + .cat5 .cat7 .cat8 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include AM_CPPFLAGS = $(INCLUDES_roken) -I../asn1 -I$(srcdir)/../asn1 \ - $(INCLUDE_hcrypto) $(INCLUDE_openldap) \ - -DHDB_DB_DIR=\"$(DIR_hdbdir)\" -I$(srcdir)/../krb5 \ - $(INCLUDE_sqlite3) $(INCLUDE_libintl) $(am__append_1) + $(INCLUDE_openldap) -DHDB_DB_DIR=\"$(DIR_hdbdir)\" \ + -I$(srcdir)/../krb5 $(INCLUDE_sqlite3) $(INCLUDE_libintl) \ + $(am__append_1) @do_roken_rename_TRUE@ROKEN_RENAME = -DROKEN_RENAME AM_CFLAGS = $(WFLAGS) CP = cp buildinclude = $(top_builddir)/include +LIB_XauReadAuth = @LIB_XauReadAuth@ LIB_el_init = @LIB_el_init@ LIB_getattr = @LIB_getattr@ LIB_getpwent_r = @LIB_getpwent_r@ LIB_odm_initialize = @LIB_odm_initialize@ LIB_setpcred = @LIB_setpcred@ -HESIODLIB = @HESIODLIB@ -HESIODINCLUDE = @HESIODINCLUDE@ +INCLUDE_krb4 = @INCLUDE_krb4@ +LIB_krb4 = @LIB_krb4@ libexec_heimdaldir = $(libexecdir)/heimdal NROFF_MAN = groff -mandoc -Tascii -LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_KAFS) +@NO_AFS_FALSE@LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_KAFS) +@NO_AFS_TRUE@LIB_kafs = @KRB5_TRUE@LIB_krb5 = $(top_builddir)/lib/krb5/libkrb5.la \ @KRB5_TRUE@ $(top_builddir)/lib/asn1/libasn1.la @KRB5_TRUE@LIB_gssapi = $(top_builddir)/lib/gssapi/libgssapi.la -LIB_heimbase = $(top_builddir)/base/libheimbase.la +LIB_heimbase = $(top_builddir)/lib/base/libheimbase.la @DCE_TRUE@LIB_kdfs = $(top_builddir)/lib/kdfs/libkdfs.la + +#silent-rules +heim_verbose = $(heim_verbose_$(V)) +heim_verbose_ = $(heim_verbose_$(AM_DEFAULT_VERBOSITY)) +heim_verbose_0 = @echo " GEN "$@; BUILT_SOURCES = \ $(gen_files_hdb:.x=.c) \ hdb_err.c \ @@ -466,22 +589,24 @@ gen_files_hdb = \ asn1_HDB_Ext_Lan_Manager_OWF.x \ asn1_HDB_Ext_Password.x \ asn1_HDB_Ext_Aliases.x \ + asn1_HDB_Ext_KeySet.x \ asn1_HDB_extension.x \ asn1_HDB_extensions.x \ asn1_hdb_entry.x \ asn1_hdb_entry_alias.x \ - asn1_hdb_keyset.x + asn1_hdb_keyset.x \ + asn1_Keys.x CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \ - hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.c* + hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.[cx] LDADD = libhdb.la \ - $(LIB_openldap) \ - $(LIB_libintl) \ ../krb5/libkrb5.la \ ../asn1/libasn1.la \ $(LIB_hcrypto) \ $(LIB_roken) \ + $(LIB_openldap) \ + $(LIB_libintl) \ $(LIB_ldopen) @OPENLDAP_MODULE_TRUE@ldap_so = hdb_ldap.la @@ -501,9 +626,9 @@ dist_libhdb_la_SOURCES = \ hdb.c \ hdb-sqlite.c \ hdb-keytab.c \ + hdb-mdb.c \ hdb-mitdb.c \ hdb_locl.h \ - hdb-private.h \ keys.c \ keytab.c \ dbinfo.c \ @@ -513,8 +638,9 @@ dist_libhdb_la_SOURCES = \ nodist_libhdb_la_SOURCES = $(BUILT_SOURCES) libhdb_la_DEPENDENCIES = version-script.map -include_HEADERS = hdb.h hdb-protos.h +include_HEADERS = hdb.h $(srcdir)/hdb-protos.h nodist_include_HEADERS = hdb_err.h hdb_asn1.h +noinst_HEADERS = $(srcdir)/hdb-private.h libhdb_la_LIBADD = \ $(LIB_com_err) \ ../krb5/libkrb5.la \ @@ -523,12 +649,16 @@ libhdb_la_LIBADD = \ $(LIBADD_roken) \ $(ldap_lib) \ $(LIB_dlopen) \ - $(DBLIB) \ - $(LIB_NDBM) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) +HDB_PROTOS = $(srcdir)/hdb-protos.h $(srcdir)/hdb-private.h +ALL_OBJECTS = $(libhdb_la_OBJECTS) $(test_dbinfo_OBJECTS) \ + $(test_hdbkeys_OBJECTS) $(test_mkey_OBJECTS) \ + $(test_hdbplugin_OBJECTS) test_dbinfo_LIBS = libhdb.la test_hdbkeys_LIBS = ../krb5/libkrb5.la libhdb.la test_mkey_LIBS = $(test_hdbkeys_LIBS) +test_hdbplugin_LIBS = $(test_hdbkeys_LIBS) EXTRA_DIST = \ NTMakefile \ libhdb-version.rc \ @@ -544,7 +674,7 @@ all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: -.SUFFIXES: .et .h .x .z .hx .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 .c .lo .o .obj +.SUFFIXES: .et .h .pc.in .pc .x .z .hx .1 .3 .5 .7 .8 .cat1 .cat3 .cat5 .cat7 .cat8 .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.am.common $(top_srcdir)/cf/Makefile.am.common $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -557,7 +687,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/hdb/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign lib/hdb/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -566,6 +695,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; +$(top_srcdir)/Makefile.am.common $(top_srcdir)/cf/Makefile.am.common $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh @@ -575,9 +705,9 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): + install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) - test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ @@ -585,6 +715,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) else :; fi; \ done; \ test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } @@ -600,16 +732,20 @@ uninstall-libLTLIBRARIES: clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -hdb_ldap.la: $(hdb_ldap_la_OBJECTS) $(hdb_ldap_la_DEPENDENCIES) - $(hdb_ldap_la_LINK) $(am_hdb_ldap_la_rpath) $(hdb_ldap_la_OBJECTS) $(hdb_ldap_la_LIBADD) $(LIBS) -libhdb.la: $(libhdb_la_OBJECTS) $(libhdb_la_DEPENDENCIES) - $(libhdb_la_LINK) -rpath $(libdir) $(libhdb_la_OBJECTS) $(libhdb_la_LIBADD) $(LIBS) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +hdb_ldap.la: $(hdb_ldap_la_OBJECTS) $(hdb_ldap_la_DEPENDENCIES) $(EXTRA_hdb_ldap_la_DEPENDENCIES) + $(AM_V_CCLD)$(hdb_ldap_la_LINK) $(am_hdb_ldap_la_rpath) $(hdb_ldap_la_OBJECTS) $(hdb_ldap_la_LIBADD) $(LIBS) + +libhdb.la: $(libhdb_la_OBJECTS) $(libhdb_la_DEPENDENCIES) $(EXTRA_libhdb_la_DEPENDENCIES) + $(AM_V_CCLD)$(libhdb_la_LINK) -rpath $(libdir) $(libhdb_la_OBJECTS) $(libhdb_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ @@ -619,15 +755,22 @@ clean-noinstPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list -test_dbinfo$(EXEEXT): $(test_dbinfo_OBJECTS) $(test_dbinfo_DEPENDENCIES) + +test_dbinfo$(EXEEXT): $(test_dbinfo_OBJECTS) $(test_dbinfo_DEPENDENCIES) $(EXTRA_test_dbinfo_DEPENDENCIES) @rm -f test_dbinfo$(EXEEXT) - $(LINK) $(test_dbinfo_OBJECTS) $(test_dbinfo_LDADD) $(LIBS) -test_hdbkeys$(EXEEXT): $(test_hdbkeys_OBJECTS) $(test_hdbkeys_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(test_dbinfo_OBJECTS) $(test_dbinfo_LDADD) $(LIBS) + +test_hdbkeys$(EXEEXT): $(test_hdbkeys_OBJECTS) $(test_hdbkeys_DEPENDENCIES) $(EXTRA_test_hdbkeys_DEPENDENCIES) @rm -f test_hdbkeys$(EXEEXT) - $(LINK) $(test_hdbkeys_OBJECTS) $(test_hdbkeys_LDADD) $(LIBS) -test_mkey$(EXEEXT): $(test_mkey_OBJECTS) $(test_mkey_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(test_hdbkeys_OBJECTS) $(test_hdbkeys_LDADD) $(LIBS) + +test_hdbplugin$(EXEEXT): $(test_hdbplugin_OBJECTS) $(test_hdbplugin_DEPENDENCIES) $(EXTRA_test_hdbplugin_DEPENDENCIES) + @rm -f test_hdbplugin$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_hdbplugin_OBJECTS) $(test_hdbplugin_LDADD) $(LIBS) + +test_mkey$(EXEEXT): $(test_mkey_OBJECTS) $(test_mkey_DEPENDENCIES) $(EXTRA_test_mkey_DEPENDENCIES) @rm -f test_mkey$(EXEEXT) - $(LINK) $(test_mkey_OBJECTS) $(test_mkey_LDADD) $(LIBS) + $(AM_V_CCLD)$(LINK) $(test_mkey_OBJECTS) $(test_mkey_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -640,6 +783,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDBFlags.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Aliases.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Constrained_delegation_acl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_KeySet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Lan_Manager_OWF.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_PKINIT_acl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_PKINIT_cert.Plo@am__quote@ @@ -648,6 +792,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_extension.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_extensions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Key.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Keys.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Salt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_hdb_entry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_hdb_entry_alias.Plo@am__quote@ @@ -659,6 +804,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-keytab.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-ldap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-mdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-mitdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-sqlite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb.Plo@am__quote@ @@ -670,28 +816,29 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dbinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hdbkeys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hdbplugin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mkey.Po@am__quote@ .c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo @@ -700,8 +847,11 @@ clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) - test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ @@ -715,13 +865,14 @@ uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(includedir)" && rm -f $$files + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) install-nodist_includeHEADERS: $(nodist_include_HEADERS) @$(NORMAL_INSTALL) - test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ @@ -735,30 +886,17 @@ uninstall-nodist_includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(includedir)" && rm -f $$files - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ + $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ @@ -770,15 +908,11 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $$unique; \ fi; \ fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique @@ -787,6 +921,21 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -844,10 +993,15 @@ install-am: all-am installcheck: installcheck-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: @@ -891,9 +1045,8 @@ install-dvi: install-dvi-am install-dvi-am: -install-exec-am: install-libLTLIBRARIES - @$(NORMAL_INSTALL) - $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-exec-am: install-exec-local install-libLTLIBRARIES + install-html: install-html-am install-html-am: @@ -937,42 +1090,56 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \ @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: all check check-am install install-am install-data-am \ - install-exec-am install-strip uninstall-am - -.PHONY: CTAGS GTAGS all all-am all-local check check-am check-local \ - clean clean-generic clean-libLTLIBRARIES clean-libtool \ - clean-noinstPROGRAMS ctags dist-hook distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am \ - install-data-hook install-dvi install-dvi-am install-exec \ - install-exec-am install-exec-hook install-html install-html-am \ - install-includeHEADERS install-info install-info-am \ - install-libLTLIBRARIES install-man \ - install-nodist_includeHEADERS install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ + install-strip uninstall-am + +.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am \ + check-local clean clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am dist-hook distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-data-hook install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-local \ + install-html install-html-am install-includeHEADERS \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-nodist_includeHEADERS install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-hook \ + tags tags-am uninstall uninstall-am uninstall-hook \ uninstall-includeHEADERS uninstall-libLTLIBRARIES \ uninstall-nodist_includeHEADERS +.PRECIOUS: Makefile + install-suid-programs: @foo='$(bin_SUIDS)'; \ for file in $$foo; do \ - x=$(DESTDIR)$(bindir)/$$file; \ - if chown 0:0 $$x && chmod u+s $$x; then :; else \ - echo "*"; \ - echo "* Failed to install $$x setuid root"; \ - echo "*"; \ - fi; done + x=$(DESTDIR)$(bindir)/$$file; \ + if chown 0:0 $$x && chmod u+s $$x; then :; else \ + echo "*"; \ + echo "* Failed to install $$x setuid root"; \ + echo "*"; \ + fi; \ + done + +install-exec-local: install-suid-programs -install-exec-hook: install-suid-programs +codesign-all: + @if [ X"$$CODE_SIGN_IDENTITY" != X ] ; then \ + foo='$(bin_PROGRAMS) $(sbin_PROGRAMS) $(libexec_PROGRAMS)' ; \ + for file in $$foo ; do \ + echo "CODESIGN $$file" ; \ + codesign -f -s "$$CODE_SIGN_IDENTITY" $$file || exit 1 ; \ + done ; \ + fi -install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(nobase_include_HEADERS) - @foo='$(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ)'; \ +all-local: codesign-all + +install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(nobase_include_HEADERS) $(noinst_HEADERS) + @foo='$(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(noinst_HEADERS)'; \ for f in $$foo; do \ f=`basename $$f`; \ if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \ @@ -980,7 +1147,7 @@ install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_incl if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \ : ; else \ echo " $(CP) $$file $(buildinclude)/$$f"; \ - $(CP) $$file $(buildinclude)/$$f; \ + $(CP) $$file $(buildinclude)/$$f || true; \ fi ; \ done ; \ foo='$(nobase_include_HEADERS)'; \ @@ -1037,6 +1204,8 @@ check-local:: $(NROFF_MAN) $< > $@ .5.cat5: $(NROFF_MAN) $< > $@ +.7.cat7: + $(NROFF_MAN) $< > $@ .8.cat8: $(NROFF_MAN) $< > $@ @@ -1079,6 +1248,19 @@ dist-cat5-mans: $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ done +dist-cat7-mans: + @foo='$(man7_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.7) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat7/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + dist-cat8-mans: @foo='$(man8_MANS)'; \ bar='$(man_MANS)'; \ @@ -1092,13 +1274,13 @@ dist-cat8-mans: $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ done -dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat8-mans +dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat7-mans dist-cat8-mans install-cat-mans: - $(SHELL) $(top_srcdir)/cf/install-catman.sh install "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man8_MANS) + $(SHELL) $(top_srcdir)/cf/install-catman.sh install "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man7_MANS) $(man8_MANS) uninstall-cat-mans: - $(SHELL) $(top_srcdir)/cf/install-catman.sh uninstall "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man8_MANS) + $(SHELL) $(top_srcdir)/cf/install-catman.sh uninstall "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man7_MANS) $(man8_MANS) install-data-hook: install-cat-mans uninstall-hook: uninstall-cat-mans @@ -1129,19 +1311,18 @@ distdir-in-tree: $(DISTFILES) $(INFO_DEPS) fi ; \ done -$(libhdb_la_OBJECTS): $(srcdir)/hdb-protos.h $(srcdir)/hdb-private.h -$(libhdb_la_OBJECTS): hdb_asn1.h hdb_asn1-priv.h hdb_err.h +$(ALL_OBJECTS): $(HDB_PROTOS) hdb_asn1.h hdb_asn1-priv.h hdb_err.h -$(srcdir)/hdb-protos.h: +$(srcdir)/hdb-protos.h: $(dist_libhdb_la_SOURCES) cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -o hdb-protos.h $(dist_libhdb_la_SOURCES) || rm -f hdb-protos.h -$(srcdir)/hdb-private.h: +$(srcdir)/hdb-private.h: $(dist_libhdb_la_SOURCES) cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p hdb-private.h $(dist_libhdb_la_SOURCES) || rm -f hdb-private.h $(gen_files_hdb) hdb_asn1.hx hdb_asn1-priv.hx: hdb_asn1_files hdb_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/hdb.asn1 - $(ASN1_COMPILE) $(srcdir)/hdb.asn1 hdb_asn1 + $(ASN1_COMPILE) --sequence=HDB-Ext-KeySet --sequence=Keys $(srcdir)/hdb.asn1 hdb_asn1 # to help stupid solaris make diff --git a/lib/hdb/NTMakefile b/lib/hdb/NTMakefile index ef696fb3a93c..01671b07805c 100644 --- a/lib/hdb/NTMakefile +++ b/lib/hdb/NTMakefile @@ -37,7 +37,7 @@ gen_files_hdb = $(OBJ)\asn1_hdb_asn1.x $(gen_files_hdb) $(OBJ)\hdb_asn1.hx $(OBJ)\hdb_asn1-priv.hx: $(BINDIR)\asn1_compile.exe hdb.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --sequence=HDB-Ext-Keyset --sequence=Keys --one-code-file $(SRCDIR)\hdb.asn1 hdb_asn1 + $(BINDIR)\asn1_compile.exe --sequence=HDB-Ext-KeySet --sequence=Keys --one-code-file $(SRCDIR)\hdb.asn1 hdb_asn1 cd $(SRCDIR) $(gen_files_hdb:.x=.c): $$(@R).x @@ -73,6 +73,7 @@ dist_libhdb_la_SOURCES = \ hdb-sqlite.c \ hdb-keytab.c \ hdb-mitdb.c \ + hdb-mdb.c \ hdb_locl.h \ keys.c \ keytab.c \ @@ -127,9 +128,9 @@ RES=$(OBJ)\libhdb-version.res $(LIBHDB): $(BINDIR)\libhdb.dll -$(BINDIR)\libhdb.dll: $(libhdb_OBJs) $(ldap_lib) $(LIBHEIMDAL) $(LIBSQLITE) $(LIBCOMERR) $(LIBROKEN) $(RES) +$(BINDIR)\libhdb.dll: $(libhdb_OBJs) $(ldap_lib) $(LIBHEIMBASE) $(LIBHEIMDAL) $(LIBSQLITE) $(LIBCOMERR) $(LIBROKEN) $(RES) $(DLLGUILINK) -def:libhdb-exports.def -implib:$(LIBHDB) - $(DLLPREP) + $(DLLPREP_NODIST) clean:: -$(RM) $(BINDIR)\libhdb.* @@ -149,7 +150,7 @@ clean:: test:: test-binaries test-run -test-binaries: $(OBJ)\test_dbinfo.exe $(OBJ)\test_hdbkeys.exe +test-binaries: $(OBJ)\test_dbinfo.exe $(OBJ)\test_hdbkeys.exe $(OBJ)\test_hdbplugin.exe $(OBJ)\test_dbinfo.exe: $(OBJ)\test_dbinfo.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) $(EXECONLINK) @@ -159,9 +160,15 @@ $(OBJ)\test_hdbkeys.exe: $(OBJ)\test_hdbkeys.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBRO $(EXECONLINK) $(EXEPREP_NODIST) +$(OBJ)\test_hdbplugin.exe: $(OBJ)\test_hdbplugin.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + test-run: cd $(OBJ) - test_dbinfo.exe + -test_dbinfo.exe + -test_hdbkeys.exe + -test_hdbplugin.exe cd $(SRCDIR) !ifdef OPENLDAP_INC diff --git a/lib/hdb/common.c b/lib/hdb/common.c index 2715adf63dca..2c8bb9f305e0 100644 --- a/lib/hdb/common.c +++ b/lib/hdb/common.c @@ -105,7 +105,6 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, krb5_principal enterprise_principal = NULL; krb5_data key, value; krb5_error_code ret; - int code; if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { if (principal->name.name_string.len != 1) { @@ -125,43 +124,74 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, hdb_principal2key(context, principal, &key); if (enterprise_principal) krb5_free_principal(context, enterprise_principal); - code = db->hdb__get(context, db, key, &value); + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if(code) - return code; - code = hdb_value2entry(context, &value, &entry->entry); - if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) { + if(ret) + return ret; + ret = hdb_value2entry(context, &value, &entry->entry); + if (ret == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) { krb5_data_free(&value); return HDB_ERR_NOENTRY; - } else if (code == ASN1_BAD_ID) { + } else if (ret == ASN1_BAD_ID) { hdb_entry_alias alias; - code = hdb_value2entry_alias(context, &value, &alias); - if (code) { + ret = hdb_value2entry_alias(context, &value, &alias); + if (ret) { krb5_data_free(&value); - return code; + return ret; } hdb_principal2key(context, alias.principal, &key); krb5_data_free(&value); free_hdb_entry_alias(&alias); - code = db->hdb__get(context, db, key, &value); + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if (code) - return code; - code = hdb_value2entry(context, &value, &entry->entry); - if (code) { + if (ret) + return ret; + ret = hdb_value2entry(context, &value, &entry->entry); + if (ret) { krb5_data_free(&value); - return code; + return ret; } } krb5_data_free(&value); - if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); - if (code) + if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) { + /* Decrypt the current keys */ + ret = hdb_unseal_keys(context, db, &entry->entry); + if (ret) { hdb_free_entry(context, entry); + return ret; + } + /* Decrypt the key history too */ + ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry); + if (ret) { + hdb_free_entry(context, entry); + return ret; + } + } else if ((flags & HDB_F_DECRYPT)) { + if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) { + /* Decrypt the current keys */ + ret = hdb_unseal_keys(context, db, &entry->entry); + if (ret) { + hdb_free_entry(context, entry); + return ret; + } + } else { + if ((flags & HDB_F_ALL_KVNOS)) + kvno = 0; + /* + * Find and decrypt the keys from the history that we want, + * and swap them with the current keys + */ + ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry); + if (ret) { + hdb_free_entry(context, entry); + return ret; + } + } } - return code; + + return 0; } static krb5_error_code @@ -192,9 +222,11 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) for (i = 0; i < aliases->aliases.len; i++) { krb5_data akey; - hdb_principal2key(context, &aliases->aliases.val[i], &akey); - code = db->hdb__del(context, db, akey); - krb5_data_free(&akey); + code = hdb_principal2key(context, &aliases->aliases.val[i], &akey); + if (code == 0) { + code = db->hdb__del(context, db, akey); + krb5_data_free(&akey); + } if (code) { free_hdb_entry(&oldentry); return code; @@ -221,14 +253,15 @@ hdb_add_aliases(krb5_context context, HDB *db, hdb_entry_alias entryalias; entryalias.principal = entry->entry.principal; - hdb_principal2key(context, &aliases->aliases.val[i], &key); code = hdb_entry_alias2value(context, &entryalias, &value); - if (code) { - krb5_data_free(&key); + if (code) return code; - } - code = db->hdb__put(context, db, flags, key, value); - krb5_data_free(&key); + + code = hdb_principal2key(context, &aliases->aliases.val[i], &key); + if (code == 0) { + code = db->hdb__put(context, db, flags, key, value); + krb5_data_free(&key); + } krb5_data_free(&value); if (code) return code; @@ -253,9 +286,11 @@ hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry) hdb_entry_alias alias; krb5_data akey, value; - hdb_principal2key(context, &aliases->aliases.val[i], &akey); - code = db->hdb__get(context, db, akey, &value); - krb5_data_free(&akey); + code = hdb_principal2key(context, &aliases->aliases.val[i], &akey); + if (code == 0) { + code = db->hdb__get(context, db, akey, &value); + krb5_data_free(&akey); + } if (code == HDB_ERR_NOENTRY) continue; else if (code) @@ -284,11 +319,29 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) krb5_data key, value; int code; + if (entry->entry.flags.do_not_store) + return HDB_ERR_MISUSE; /* check if new aliases already is used */ code = hdb_check_aliases(context, db, entry); if (code) return code; + if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE)) + return 0; + + if ((flags & HDB_F_PRECHECK)) { + code = hdb_principal2key(context, entry->entry.principal, &key); + if (code) + return code; + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code == 0) + krb5_data_free(&value); + if (code == HDB_ERR_NOENTRY) + return 0; + return code ? code : HDB_ERR_EXISTS; + } + if(entry->entry.generation == NULL) { struct timeval t; entry->entry.generation = malloc(sizeof(*entry->entry.generation)); @@ -328,13 +381,32 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) } krb5_error_code -_hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) +_hdb_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) { - krb5_data key; + krb5_data key, value; int code; hdb_principal2key(context, principal, &key); + if ((flags & HDB_F_PRECHECK)) { + /* + * We don't check that we can delete the aliases because we + * assume that the DB is consistent. If we did check for alias + * consistency we'd also have to provide a way to fsck the DB, + * otherwise admins would have no way to recover -- papering + * over this here is less work, but we really ought to provide + * an HDB fsck. + */ + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code == 0) { + krb5_data_free(&value); + return 0; + } + return code; + } + code = hdb_remove_aliases(context, db, &key); if (code) { krb5_data_free(&key); diff --git a/lib/hdb/db.c b/lib/hdb/db.c index 69940edf89dc..c6cf58813814 100644 --- a/lib/hdb/db.c +++ b/lib/hdb/db.c @@ -33,7 +33,7 @@ #include "hdb_locl.h" -#if HAVE_DB1 +#if defined(HAVE_DB1) #if defined(HAVE_DB_185_H) #include <db_185.h> @@ -41,11 +41,27 @@ #include <db.h> #endif +typedef struct { + HDB hdb; /* generic members */ + int lock_fd; /* DB-specific */ +} DB1_HDB; + static krb5_error_code DB_close(krb5_context context, HDB *db) { + DB1_HDB *db1 = (DB1_HDB *)db; DB *d = (DB*)db->hdb_db; + + heim_assert(d != 0, "Closing already closed HDB"); + (*d->close)(d); + db->hdb_db = 0; + + if (db1->lock_fd >= 0) { + close(db1->lock_fd); + db1->lock_fd = -1; + } + return 0; } @@ -63,27 +79,15 @@ DB_destroy(krb5_context context, HDB *db) static krb5_error_code DB_lock(krb5_context context, HDB *db, int operation) { - DB *d = (DB*)db->hdb_db; - int fd = (*d->fd)(d); - if(fd < 0) { - krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, - "Can't lock database: %s", db->hdb_name); - return HDB_ERR_CANT_LOCK_DB; - } - return hdb_lock(fd, operation); + + return 0; } static krb5_error_code DB_unlock(krb5_context context, HDB *db) { - DB *d = (DB*)db->hdb_db; - int fd = (*d->fd)(d); - if(fd < 0) { - krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, - "Can't unlock database: %s", db->hdb_name); - return HDB_ERR_CANT_LOCK_DB; - } - return hdb_unlock(fd); + + return 0; } @@ -96,13 +100,7 @@ DB_seq(krb5_context context, HDB *db, krb5_data key_data, data; int code; - code = db->hdb_lock(context, db, HDB_RLOCK); - if(code == -1) { - krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); - return HDB_ERR_DB_INUSE; - } code = (*d->seq)(d, &key, &value, flag); - db->hdb_unlock(context, db); /* XXX check value */ if(code == -1) { code = errno; krb5_set_error_message(context, code, "Database %s seq error: %s", @@ -159,6 +157,10 @@ DB_rename(krb5_context context, HDB *db, const char *new_name) int ret; char *old, *new; + if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0) + new_name += sizeof("db:") - 1; + else if (strncmp(new_name, "db1:", sizeof("db1:") - 1) == 0) + new_name += sizeof("db1:") - 1; asprintf(&old, "%s.db", db->hdb_name); asprintf(&new, "%s.db", new_name); ret = rename(old, new); @@ -181,11 +183,7 @@ DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) k.data = key.data; k.size = key.length; - code = db->hdb_lock(context, db, HDB_RLOCK); - if(code) - return code; code = (*d->get)(d, &k, &v, 0); - db->hdb_unlock(context, db); if(code < 0) { code = errno; krb5_set_error_message(context, code, "Database %s get error: %s", @@ -213,11 +211,8 @@ DB__put(krb5_context context, HDB *db, int replace, k.size = key.length; v.data = value.data; v.size = value.length; - code = db->hdb_lock(context, db, HDB_WLOCK); - if(code) - return code; + krb5_clear_error_message(context); code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); - db->hdb_unlock(context, db); if(code < 0) { code = errno; krb5_set_error_message(context, code, "Database %s put error: %s", @@ -225,9 +220,15 @@ DB__put(krb5_context context, HDB *db, int replace, return code; } if(code == 1) { - krb5_clear_error_message(context); return HDB_ERR_EXISTS; } + code = (*d->sync)(d, 0); + if (code == -1) { + code = errno; + krb5_set_error_message(context, code, "Database %s put sync error: %s", + db->hdb_name, strerror(code)); + return code; + } return 0; } @@ -239,25 +240,65 @@ DB__del(krb5_context context, HDB *db, krb5_data key) krb5_error_code code; k.data = key.data; k.size = key.length; - code = db->hdb_lock(context, db, HDB_WLOCK); - if(code) - return code; + krb5_clear_error_message(context); code = (*d->del)(d, &k, 0); - db->hdb_unlock(context, db); - if(code == 1) { + if (code == 1) + return HDB_ERR_NOENTRY; + if (code < 0) { code = errno; - krb5_set_error_message(context, code, "Database %s put error: %s", + krb5_set_error_message(context, code, "Database %s del error: %s", + db->hdb_name, strerror(code)); + return code; + } + code = (*d->sync)(d, 0); + if (code == -1) { + code = errno; + krb5_set_error_message(context, code, "Database %s del sync error: %s", db->hdb_name, strerror(code)); return code; } - if(code < 0) - return errno; return 0; } +static DB * +_open_db(char *fn, int flags, int mode, int *fd) +{ +#ifndef O_EXLOCK + int op; + int ret; + + *fd = open(fn, flags, mode); + if (*fd == -1) + return NULL; + + if ((flags & O_ACCMODE) == O_RDONLY) + op = LOCK_SH; + else + op = LOCK_EX; + + ret = flock(*fd, op); + if (ret == -1) { + int saved_errno; + + saved_errno = errno; + close(*fd); + errno = saved_errno; + return NULL; + } +#else + if ((flags & O_ACCMODE) == O_RDONLY) + flags |= O_SHLOCK; + else + flags |= O_EXLOCK; +#endif + + return dbopen(fn, flags, mode, DB_BTREE, NULL); +} + static krb5_error_code DB_open(krb5_context context, HDB *db, int flags, mode_t mode) { + DB1_HDB *db1 = (DB1_HDB *)db; char *fn; krb5_error_code ret; @@ -266,16 +307,15 @@ DB_open(krb5_context context, HDB *db, int flags, mode_t mode) krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } - db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); + db->hdb_db = _open_db(fn, flags, mode, &db1->lock_fd); free(fn); /* try to open without .db extension */ if(db->hdb_db == NULL && errno == ENOENT) - db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); + db->hdb_db = _open_db(db->hdb_name, flags, mode, &db1->lock_fd); if(db->hdb_db == NULL) { - ret = errno; - krb5_set_error_message(context, ret, "dbopen (%s): %s", - db->hdb_name, strerror(ret)); - return ret; + krb5_set_error_message(context, errno, "dbopen (%s): %s", + db->hdb_name, strerror(errno)); + return errno; } if((flags & O_ACCMODE) == O_RDONLY) ret = hdb_check_db_format(context, db); @@ -296,10 +336,11 @@ DB_open(krb5_context context, HDB *db, int flags, mode_t mode) } krb5_error_code -hdb_db_create(krb5_context context, HDB **db, - const char *filename) +hdb_db1_create(krb5_context context, HDB **db, + const char *filename) { - *db = calloc(1, sizeof(**db)); + DB1_HDB **db1 = (DB1_HDB **)db; + *db = calloc(1, sizeof(**db1)); /* Allocate space for the larger db1 */ if (*db == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; @@ -330,7 +371,9 @@ hdb_db_create(krb5_context context, HDB **db, (*db)->hdb__put = DB__put; (*db)->hdb__del = DB__del; (*db)->hdb_destroy = DB_destroy; + + (*db1)->lock_fd = -1; return 0; } -#endif /* HAVE_DB1 */ +#endif /* defined(HAVE_DB1) */ diff --git a/lib/hdb/db3.c b/lib/hdb/db3.c index 58f892ff6777..cd2e33f067ad 100644 --- a/lib/hdb/db3.c +++ b/lib/hdb/db3.c @@ -33,10 +33,14 @@ #include "hdb_locl.h" +#include <fcntl.h> + #if HAVE_DB3 #ifdef HAVE_DBHEADER #include <db.h> +#elif HAVE_DB6_DB_H +#include <db6/db.h> #elif HAVE_DB5_DB_H #include <db5/db.h> #elif HAVE_DB4_DB_H @@ -47,15 +51,32 @@ #include <db.h> #endif +typedef struct { + HDB hdb; /* generic members */ + int lock_fd; /* DB3-specific */ +} DB3_HDB; + + static krb5_error_code DB_close(krb5_context context, HDB *db) { + DB3_HDB *db3 = (DB3_HDB *)db; DB *d = (DB*)db->hdb_db; DBC *dbcp = (DBC*)db->hdb_dbc; - (*dbcp->c_close)(dbcp); + heim_assert(d != 0, "Closing already closed HDB"); + + if (dbcp != NULL) + dbcp->c_close(dbcp); + if (d != NULL) + d->close(d, 0); + if (db3->lock_fd >= 0) + close(db3->lock_fd); + + db3->lock_fd = -1; db->hdb_dbc = 0; - (*d->close)(d, 0); + db->hdb_db = 0; + return 0; } @@ -73,21 +94,15 @@ DB_destroy(krb5_context context, HDB *db) static krb5_error_code DB_lock(krb5_context context, HDB *db, int operation) { - DB *d = (DB*)db->hdb_db; - int fd; - if ((*d->fd)(d, &fd)) - return HDB_ERR_CANT_LOCK_DB; - return hdb_lock(fd, operation); + + return 0; } static krb5_error_code DB_unlock(krb5_context context, HDB *db) { - DB *d = (DB*)db->hdb_db; - int fd; - if ((*d->fd)(d, &fd)) - return HDB_ERR_CANT_LOCK_DB; - return hdb_unlock(fd); + + return 0; } @@ -102,10 +117,7 @@ DB_seq(krb5_context context, HDB *db, memset(&key, 0, sizeof(DBT)); memset(&value, 0, sizeof(DBT)); - if ((*db->hdb_lock)(context, db, HDB_RLOCK)) - return HDB_ERR_DB_INUSE; code = (*dbcp->c_get)(dbcp, &key, &value, flag); - (*db->hdb_unlock)(context, db); /* XXX check value */ if (code == DB_NOTFOUND) return HDB_ERR_NOENTRY; if (code) @@ -156,16 +168,29 @@ DB_rename(krb5_context context, HDB *db, const char *new_name) int ret; char *old, *new; - asprintf(&old, "%s.db", db->hdb_name); - asprintf(&new, "%s.db", new_name); + if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0) + new_name += sizeof("db:") - 1; + else if (strncmp(new_name, "db3:", sizeof("db3:") - 1) == 0) + new_name += sizeof("db3:") - 1; + + ret = asprintf(&old, "%s.db", db->hdb_name); + if (ret == -1) + return ENOMEM; + ret = asprintf(&new, "%s.db", new_name); + if (ret == -1) { + free(old); + return ENOMEM; + } ret = rename(old, new); free(old); - free(new); - if(ret) + if(ret) { + free(new); return errno; + } free(db->hdb_name); - db->hdb_name = strdup(new_name); + new[strlen(new) - 3] = '\0'; + db->hdb_name = new; return 0; } @@ -181,10 +206,7 @@ DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) k.data = key.data; k.size = key.length; k.flags = 0; - if ((code = (*db->hdb_lock)(context, db, HDB_RLOCK))) - return code; code = (*d->get)(d, NULL, &k, &v, 0); - (*db->hdb_unlock)(context, db); if(code == DB_NOTFOUND) return HDB_ERR_NOENTRY; if(code) @@ -210,14 +232,49 @@ DB__put(krb5_context context, HDB *db, int replace, v.data = value.data; v.size = value.length; v.flags = 0; - if ((code = (*db->hdb_lock)(context, db, HDB_WLOCK))) - return code; code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); - (*db->hdb_unlock)(context, db); if(code == DB_KEYEXIST) return HDB_ERR_EXISTS; - if(code) - return errno; + if (code) { + /* + * Berkeley DB 3 and up have a terrible error reporting + * interface... + * + * DB->err() doesn't output a string. + * DB->set_errcall()'s callback function doesn't have a void * + * argument that can be used to place the error somewhere. + * + * The only thing we could do is fopen()/fdopen() a file, set it + * with DB->set_errfile(), then call DB->err(), then read the + * message from the file, unset it with DB->set_errfile(), close + * it and delete it. That's a lot of work... so we don't do it. + */ + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s put error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s put error: unknown (%d)", + db->hdb_name, code); + } + return code; + } + code = (*d->sync)(d, 0); + if (code) { + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s put sync error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s put sync error: unknown (%d)", + db->hdb_name, code); + } + return code; + } return 0; } @@ -231,26 +288,96 @@ DB__del(krb5_context context, HDB *db, krb5_data key) k.data = key.data; k.size = key.length; k.flags = 0; - code = (*db->hdb_lock)(context, db, HDB_WLOCK); - if(code) - return code; code = (*d->del)(d, NULL, &k, 0); - (*db->hdb_unlock)(context, db); if(code == DB_NOTFOUND) return HDB_ERR_NOENTRY; - if(code) + if (code) { + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s del error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s del error: unknown (%d)", + db->hdb_name, code); + } return code; + } + code = (*d->sync)(d, 0); + if (code) { + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s del sync error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s del sync error: unknown (%d)", + db->hdb_name, code); + } + return code; + } return 0; } +#define RD_CACHE_SZ 0x8000 /* Minimal read cache size */ +#define WR_CACHE_SZ 0x8000 /* Minimal write cache size */ + +static int +_open_db(DB *d, char *fn, int myflags, int flags, mode_t mode, int *fd) +{ + int ret; + int cache_size = (myflags & DB_RDONLY) ? RD_CACHE_SZ : WR_CACHE_SZ; + + *fd = open(fn, flags, mode); + + if (*fd == -1) + return errno; + + /* + * Without DB_FCNTL_LOCKING, the DB library complains when initializing + * a database in an empty file. Since the database is our lock file, + * we create it before Berkeley DB does, so a new DB always starts empty. + */ + myflags |= DB_FCNTL_LOCKING; + + ret = flock(*fd, (myflags&DB_RDONLY) ? LOCK_SH : LOCK_EX); + if (ret == -1) { + ret = errno; + close(*fd); + *fd = -1; + return ret; + } + + d->set_cachesize(d, 0, cache_size, 0); + +#if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR >= 1)) + ret = (*d->open)(d, NULL, fn, NULL, DB_BTREE, myflags, mode); +#else + ret = (*d->open)(d, fn, NULL, DB_BTREE, myflags, mode); +#endif + + if (ret != 0) { + close(*fd); + *fd = -1; + } + + return ret; +} + static krb5_error_code DB_open(krb5_context context, HDB *db, int flags, mode_t mode) { + DB3_HDB *db3 = (DB3_HDB *)db; DBC *dbc = NULL; char *fn; krb5_error_code ret; DB *d; int myflags = 0; + int aret; + + heim_assert(db->hdb_db == 0, "Opening already open HDB"); if (flags & O_CREAT) myflags |= DB_CREATE; @@ -264,11 +391,12 @@ DB_open(krb5_context context, HDB *db, int flags, mode_t mode) if (flags & O_TRUNC) myflags |= DB_TRUNCATE; - asprintf(&fn, "%s.db", db->hdb_name); - if (fn == NULL) { + aret = asprintf(&fn, "%s.db", db->hdb_name); + if (aret == -1) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + if (db_create(&d, NULL, 0) != 0) { free(fn); krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); @@ -276,33 +404,29 @@ DB_open(krb5_context context, HDB *db, int flags, mode_t mode) } db->hdb_db = d; -#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) - ret = (*d->open)(db->hdb_db, NULL, fn, NULL, DB_BTREE, myflags, mode); -#else - ret = (*d->open)(db->hdb_db, fn, NULL, DB_BTREE, myflags, mode); -#endif + /* From here on out always DB_close() before returning on error */ + ret = _open_db(d, fn, myflags, flags, mode, &db3->lock_fd); + free(fn); if (ret == ENOENT) { /* try to open without .db extension */ -#if (DB_VERSION_MAJOR >= 4) && (DB_VERSION_MINOR >= 1) - ret = (*d->open)(db->hdb_db, NULL, db->hdb_name, NULL, DB_BTREE, - myflags, mode); -#else - ret = (*d->open)(db->hdb_db, db->hdb_name, NULL, DB_BTREE, - myflags, mode); -#endif + ret = _open_db(d, db->hdb_name, myflags, flags, mode, &db3->lock_fd); } if (ret) { - free(fn); + DB_close(context, db); krb5_set_error_message(context, ret, "opening %s: %s", - db->hdb_name, strerror(ret)); + db->hdb_name, strerror(ret)); return ret; } - free(fn); - ret = (*d->cursor)(d, NULL, &dbc, 0); +#ifndef DB_CURSOR_BULK +# define DB_CURSOR_BULK 0 /* Missing with DB < 4.8 */ +#endif + ret = (*d->cursor)(d, NULL, &dbc, DB_CURSOR_BULK); + if (ret) { + DB_close(context, db); krb5_set_error_message(context, ret, "d->cursor: %s", strerror(ret)); return ret; } @@ -326,10 +450,11 @@ DB_open(krb5_context context, HDB *db, int flags, mode_t mode) } krb5_error_code -hdb_db_create(krb5_context context, HDB **db, - const char *filename) +hdb_db3_create(krb5_context context, HDB **db, + const char *filename) { - *db = calloc(1, sizeof(**db)); + DB3_HDB **db3 = (DB3_HDB **)db; + *db3 = calloc(1, sizeof(**db3)); /* Allocate space for the larger db3 */ if (*db == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; @@ -360,6 +485,8 @@ hdb_db_create(krb5_context context, HDB **db, (*db)->hdb__put = DB__put; (*db)->hdb__del = DB__del; (*db)->hdb_destroy = DB_destroy; + + (*db3)->lock_fd = -1; return 0; } #endif /* HAVE_DB3 */ diff --git a/lib/hdb/dbinfo.c b/lib/hdb/dbinfo.c index 52e394106eca..e2890255b2ef 100644 --- a/lib/hdb/dbinfo.c +++ b/lib/hdb/dbinfo.c @@ -108,11 +108,9 @@ hdb_get_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) NULL); if (db_binding) { - ret = get_dbinfo(context, db_binding, "default", &di); - if (ret == 0 && di) { - databases = di; - dt = &di->next; - } + ret = get_dbinfo(context, db_binding, "default", &databases); + if (ret == 0 && databases != NULL) + dt = &databases->next; for ( ; db_binding != NULL; db_binding = db_binding->next) { @@ -129,36 +127,41 @@ hdb_get_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) if (dt) *dt = di; - else + else { + hdb_free_dbinfo(context, &databases); databases = di; + } dt = &di->next; } } - if(databases == NULL) { + if (databases == NULL) { /* if there are none specified, create one and use defaults */ - di = calloc(1, sizeof(*di)); - databases = di; - di->label = strdup("default"); + databases = calloc(1, sizeof(*databases)); + databases->label = strdup("default"); } - for(di = databases; di; di = di->next) { - if(di->dbname == NULL) { + for (di = databases; di; di = di->next) { + if (di->dbname == NULL) { di->dbname = strdup(default_dbname); if (di->mkey_file == NULL) di->mkey_file = strdup(default_mkey); } - if(di->mkey_file == NULL) { + if (di->mkey_file == NULL) { p = strrchr(di->dbname, '.'); if(p == NULL || strchr(p, '/') != NULL) /* final pathname component does not contain a . */ - asprintf(&di->mkey_file, "%s.mkey", di->dbname); + ret = asprintf(&di->mkey_file, "%s.mkey", di->dbname); else /* the filename is something.else, replace .else with .mkey */ - asprintf(&di->mkey_file, "%.*s.mkey", - (int)(p - di->dbname), di->dbname); + ret = asprintf(&di->mkey_file, "%.*s.mkey", + (int)(p - di->dbname), di->dbname); + if (ret == -1) { + hdb_free_dbinfo(context, &databases); + return ENOMEM; + } } if(di->acl_file == NULL) di->acl_file = strdup(default_acl); @@ -248,6 +251,12 @@ hdb_free_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) const char * hdb_db_dir(krb5_context context) { + const char *p; + + p = krb5_config_get_string(context, NULL, "hdb", "db-dir", NULL); + if (p) + return p; + return HDB_DB_DIR; } diff --git a/lib/hdb/ext.c b/lib/hdb/ext.c index d2a4373b9b38..ecefe931b74f 100644 --- a/lib/hdb/ext.c +++ b/lib/hdb/ext.c @@ -101,7 +101,7 @@ hdb_replace_extension(krb5_context context, ext2 = hdb_find_extension(entry, ext->data.element); } else { /* - * This is an unknown extention, and we are asked to replace a + * This is an unknown extension, and we are asked to replace a * possible entry in `entry' that is of the same type. This * might seem impossible, but ASN.1 CHOICE comes to our * rescue. The first tag in each branch in the CHOICE is @@ -120,7 +120,7 @@ hdb_replace_extension(krb5_context context, &size); if (ret) { krb5_set_error_message(context, ret, "hdb: failed to decode " - "replacement hdb extention"); + "replacement hdb extension"); return ret; } @@ -136,7 +136,7 @@ hdb_replace_extension(krb5_context context, &size); if (ret) { krb5_set_error_message(context, ret, "hdb: failed to decode " - "present hdb extention"); + "present hdb extension"); return ret; } @@ -153,7 +153,7 @@ hdb_replace_extension(krb5_context context, ret = copy_HDB_extension(ext, ext2); if (ret) krb5_set_error_message(context, ret, "hdb: failed to copy replacement " - "hdb extention"); + "hdb extension"); return ret; } @@ -432,3 +432,101 @@ hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a) return 0; } + +unsigned int +hdb_entry_get_kvno_diff_clnt(const hdb_entry *entry) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, + choice_HDB_extension_data_hist_kvno_diff_clnt); + if (ext) + return ext->data.u.hist_kvno_diff_clnt; + return 1; +} + +krb5_error_code +hdb_entry_set_kvno_diff_clnt(krb5_context context, hdb_entry *entry, + unsigned int diff) +{ + HDB_extension ext; + + if (diff > 16384) + return EINVAL; + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt; + ext.data.u.hist_kvno_diff_clnt = diff; + return hdb_replace_extension(context, entry, &ext); +} + +krb5_error_code +hdb_entry_clear_kvno_diff_clnt(krb5_context context, hdb_entry *entry) +{ + return hdb_clear_extension(context, entry, + choice_HDB_extension_data_hist_kvno_diff_clnt); +} + +unsigned int +hdb_entry_get_kvno_diff_svc(const hdb_entry *entry) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, + choice_HDB_extension_data_hist_kvno_diff_svc); + if (ext) + return ext->data.u.hist_kvno_diff_svc; + return 1024; /* max_life effectively provides a better default */ +} + +krb5_error_code +hdb_entry_set_kvno_diff_svc(krb5_context context, hdb_entry *entry, + unsigned int diff) +{ + HDB_extension ext; + + if (diff > 16384) + return EINVAL; + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc; + ext.data.u.hist_kvno_diff_svc = diff; + return hdb_replace_extension(context, entry, &ext); +} + +krb5_error_code +hdb_entry_clear_kvno_diff_svc(krb5_context context, hdb_entry *entry) +{ + return hdb_clear_extension(context, entry, + choice_HDB_extension_data_hist_kvno_diff_svc); +} + +krb5_error_code +hdb_set_last_modified_by(krb5_context context, hdb_entry *entry, + krb5_principal modby, time_t modtime) +{ + krb5_error_code ret; + Event *old_ev; + Event *ev; + + old_ev = entry->modified_by; + + ev = calloc(1, sizeof (*ev)); + if (!ev) + return ENOMEM; + if (modby) + ret = krb5_copy_principal(context, modby, &ev->principal); + else + ret = krb5_parse_name(context, "root/admin", &ev->principal); + if (ret) { + free(ev); + return ret; + } + ev->time = modtime; + if (!ev->time) + time(&ev->time); + + entry->modified_by = ev; + if (old_ev) + free_Event(old_ev); + return 0; +} + diff --git a/lib/hdb/hdb-ldap.c b/lib/hdb/hdb-ldap.c index 1b4024aa540a..9ce4ba74f823 100644 --- a/lib/hdb/hdb-ldap.c +++ b/lib/hdb/hdb-ldap.c @@ -2,6 +2,7 @@ * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd. * Copyright (c) 2004, Andrew Bartlett. * Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan. + * Copyright (c) 2015, Timothy Pearson. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,6 +51,7 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, static const char *default_structural_object = "account"; static char *structural_object; +static const char *default_ldap_url = "ldapi:///"; static krb5_boolean samba_forwardable; struct hdbldapdb { @@ -57,6 +59,9 @@ struct hdbldapdb { int h_msgid; char *h_base; char *h_url; + char *h_bind_dn; + char *h_bind_password; + krb5_boolean h_start_tls; char *h_createbase; }; @@ -66,6 +71,8 @@ struct hdbldapdb { do { ((struct hdbldapdb *)(db)->hdb_db)->h_msgid = msgid; } while(0) #define HDB2BASE(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_base) #define HDB2URL(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_url) +#define HDB2BINDDN(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_dn) +#define HDB2BINDPW(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_password) #define HDB2CREATE(db) (((struct hdbldapdb *)(db)->hdb_db)->h_createbase) /* @@ -85,6 +92,7 @@ static char * krb5kdcentry_attrs[] = { "krb5PasswordEnd", "krb5PrincipalName", "krb5PrincipalRealm", + "krb5ExtendedAttributes", "krb5ValidEnd", "krb5ValidStart", "modifiersName", @@ -510,6 +518,33 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, goto out; } + if (is_heimdal_entry && ent->entry.extensions) { + if (!is_new_entry) { + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes"); + if (vals) { + ldap_value_free_len(vals); + ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5ExtendedAttributes", NULL); + if (ret) + goto out; + } + } + + for (i = 0; i < ent->entry.extensions->len; i++) { + unsigned char *buf; + size_t size, sz = 0; + + ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->entry.extensions->val[i], &sz, ret); + if (ret) + goto out; + if (size != sz) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5ExtendedAttributes", buf, sz); + if (ret) + goto out; + } + } + if (is_heimdal_entry && ent->entry.valid_start) { if (orig.entry.valid_end == NULL || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) { @@ -797,10 +832,10 @@ need_quote(unsigned char c) (c == 0x7f); } -const static char hexchar[] = "0123456789ABCDEF"; +static const char hexchar[] = "0123456789ABCDEF"; static krb5_error_code -escape_value(krb5_context context, const unsigned char *unquoted, char **quoted) +escape_value(krb5_context context, const char *unquoted, char **quoted) { size_t i, len; @@ -816,7 +851,7 @@ escape_value(krb5_context context, const unsigned char *unquoted, char **quoted) } for (i = 0; unquoted[0] ; unquoted++) { - if (need_quote((unsigned char *)unquoted[0])) { + if (need_quote((unsigned char)unquoted[0])) { (*quoted)[i++] = '\\'; (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf]; (*quoted)[i++] = hexchar[(unquoted[0] ) & 0xf]; @@ -975,6 +1010,7 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; struct berval **keys; + struct berval **extensions; struct berval **vals; int tmp, tmp_time, i, ret, have_arcfour = 0; @@ -1013,7 +1049,6 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (keys != NULL) { - int i; size_t l; ent->entry.keys.len = ldap_count_values_len(keys); @@ -1043,10 +1078,35 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, #endif } + extensions = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes"); + if (extensions != NULL) { + size_t l; + + ent->entry.extensions = calloc(1, sizeof(*(ent->entry.extensions))); + if (ent->entry.extensions == NULL) { + ret = krb5_enomem(context); + goto out; + } + ent->entry.extensions->len = ldap_count_values_len(extensions); + ent->entry.extensions->val = (HDB_extension *) calloc(ent->entry.extensions->len, sizeof(HDB_extension)); + if (ent->entry.extensions->val == NULL) { + ent->entry.extensions->len = 0; + ret = krb5_enomem(context); + goto out; + } + for (i = 0; i < ent->entry.extensions->len; i++) { + ret = decode_HDB_extension((unsigned char *) extensions[i]->bv_val, + (size_t) extensions[i]->bv_len, &ent->entry.extensions->val[i], &l); + if (ret) + krb5_set_error_message(context, ret, "decode_HDB_extension failed"); + } + ber_bvecfree(extensions); + } else { + ent->entry.extensions = NULL; + } + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); if (vals != NULL) { - int i; - ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); if (ent->entry.etypes == NULL) { ret = ENOMEM; @@ -1054,7 +1114,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, goto out; } ent->entry.etypes->len = ldap_count_values_len(vals); - ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int)); + ent->entry.etypes->val = calloc(ent->entry.etypes->len, + sizeof(ent->entry.etypes->val[0])); if (ent->entry.etypes->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); @@ -1089,24 +1150,22 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN); if (ret == 0 && have_arcfour == 0) { unsigned *etypes; - Key *keys; - int i; + Key *ks; - keys = realloc(ent->entry.keys.val, - (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0])); - if (keys == NULL) { - free(ntPasswordIN); + ks = realloc(ent->entry.keys.val, + (ent->entry.keys.len + 1) * + sizeof(ent->entry.keys.val[0])); + if (ks == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } - ent->entry.keys.val = keys; + ent->entry.keys.val = ks; memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key)); ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16); if (ret) { krb5_set_error_message(context, ret, "malloc: out of memory"); - free(ntPasswordIN); ret = ENOMEM; goto out; } @@ -1239,21 +1298,24 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, if (ret == 0) { time_t delta; - if (ent->entry.pw_end == NULL) { - ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); - if (ent->entry.pw_end == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, "malloc: out of memory"); - goto out; - } - } - delta = krb5_config_get_time_default(context, NULL, - 365 * 24 * 60 * 60, + 0, "kadmin", "password_lifetime", NULL); - *ent->entry.pw_end = tmp_time + delta; + + if (delta) { + if (ent->entry.pw_end == NULL) { + ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); + if (ent->entry.pw_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + } + + *ent->entry.pw_end = tmp_time + delta; + } } ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); @@ -1333,7 +1395,6 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, */ - int i; int flags_len = strlen(samba_acct_flags); if (flags_len < 2) @@ -1397,8 +1458,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ret = 0; out: - if (unparsed_name) - free(unparsed_name); + free(unparsed_name); + free(ntPasswordIN); if (ret) hdb_free_entry(context, ent); @@ -1513,7 +1574,7 @@ LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, "(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))", krb5kdcentry_attrs, 0, NULL, NULL, NULL, 0, &msgid); - if (msgid < 0) + if (ret != LDAP_SUCCESS || msgid < 0) return HDB_ERR_NOENTRY; HDBSETMSGID(db, msgid); @@ -1539,6 +1600,16 @@ LDAP__connect(krb5_context context, HDB * db) * bind in progress message. */ struct berval bv = { 0, "" }; + const char *sasl_method = "EXTERNAL"; + const char *bind_dn = NULL; + + if (HDB2BINDDN(db) != NULL && HDB2BINDPW(db) != NULL) { + /* A bind DN was specified; use SASL SIMPLE */ + bind_dn = HDB2BINDDN(db); + sasl_method = LDAP_SASL_SIMPLE; + bv.bv_val = HDB2BINDPW(db); + bv.bv_len = strlen(bv.bv_val); + } if (HDB2LDAP(db)) { /* connection has been opened. ping server. */ @@ -1572,7 +1643,18 @@ LDAP__connect(krb5_context context, HDB * db) return HDB_ERR_BADVERSION; } - rc = ldap_sasl_bind_s(HDB2LDAP(db), NULL, "EXTERNAL", &bv, + if (((struct hdbldapdb *)db->hdb_db)->h_start_tls) { + rc = ldap_start_tls_s(HDB2LDAP(db), NULL, NULL); + + if (rc != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_start_tls_s: %s", ldap_err2string(rc)); + LDAP_close(context, db); + return HDB_ERR_BADVERSION; + } + } + + rc = ldap_sasl_bind_s(HDB2LDAP(db), bind_dn, sasl_method, &bv, NULL, NULL, NULL); if (rc != LDAP_SUCCESS) { krb5_set_error_message(context, HDB_ERR_BADVERSION, @@ -1635,6 +1717,7 @@ LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, return ret; } +#if 0 static krb5_error_code LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, unsigned flags, hdb_entry_ex * entry) @@ -1642,6 +1725,7 @@ LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, return LDAP_fetch_kvno(context, db, principal, flags & (~HDB_F_KVNO_SPECIFIED), 0, entry); } +#endif static krb5_error_code LDAP_store(krb5_context context, HDB * db, unsigned flags, @@ -1654,6 +1738,9 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags, LDAPMessage *msg = NULL, *e = NULL; char *dn = NULL, *name = NULL; + if ((flags & HDB_F_PRECHECK)) + return 0; /* we can't guarantee whether we'll be able to perform it */ + ret = LDAP_principal2message(context, db, entry->entry.principal, &msg); if (ret == 0) e = ldap_first_entry(HDB2LDAP(db), msg); @@ -1725,13 +1812,17 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags, } static krb5_error_code -LDAP_remove(krb5_context context, HDB *db, krb5_const_principal principal) +LDAP_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) { krb5_error_code ret; LDAPMessage *msg, *e; char *dn = NULL; int rc, limit = LDAP_NO_LIMIT; + if ((flags & HDB_F_PRECHECK)) + return 0; /* we can't guarantee whether we'll be able to perform it */ + ret = LDAP_principal2message(context, db, principal, &msg); if (ret) goto out; @@ -1803,8 +1894,19 @@ hdb_ldap_common(krb5_context context, { struct hdbldapdb *h; const char *create_base = NULL; + const char *ldap_secret_file = NULL; + + if (url == NULL || url[0] == '\0') { + const char *p; + p = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-url", NULL); + if (p == NULL) + p = default_ldap_url; - if (search_base == NULL && search_base[0] == '\0') { + url = p; + } + + if (search_base == NULL || search_base[0] == '\0') { krb5_set_error_message(context, ENOMEM, "ldap search base not configured"); return ENOMEM; /* XXX */ } @@ -1860,6 +1962,34 @@ hdb_ldap_common(krb5_context context, return ENOMEM; } + ldap_secret_file = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-secret-file", NULL); + if (ldap_secret_file != NULL) { + krb5_config_binding *tmp; + krb5_error_code ret; + const char *p; + + ret = krb5_config_parse_file(context, ldap_secret_file, &tmp); + if (ret) + return ret; + + p = krb5_config_get_string(context, tmp, "kdc", + "hdb-ldap-bind-dn", NULL); + if (p != NULL) + h->h_bind_dn = strdup(p); + + p = krb5_config_get_string(context, tmp, "kdc", + "hdb-ldap-bind-password", NULL); + if (p != NULL) + h->h_bind_password = strdup(p); + + krb5_config_file_free(context, tmp); + } + + h->h_start_tls = + krb5_config_get_bool_default(context, NULL, FALSE, + "kdc", "hdb-ldap-start-tls", NULL); + create_base = krb5_config_get_string(context, NULL, "kdc", "hdb-ldap-create-base", NULL); if (create_base == NULL) @@ -1875,7 +2005,7 @@ hdb_ldap_common(krb5_context context, (*db)->hdb_master_key_set = 0; (*db)->hdb_openp = 0; - (*db)->hdb_capability_flags = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_SHARED_DIRECTORY; (*db)->hdb_open = LDAP_open; (*db)->hdb_close = LDAP_close; (*db)->hdb_fetch_kvno = LDAP_fetch_kvno; @@ -1894,20 +2024,27 @@ hdb_ldap_common(krb5_context context, return 0; } +#ifdef OPENLDAP_MODULE +static +#endif + krb5_error_code hdb_ldap_create(krb5_context context, HDB ** db, const char *arg) { - return hdb_ldap_common(context, db, arg, "ldapi:///"); + return hdb_ldap_common(context, db, arg, NULL); } +#ifdef OPENLDAP_MODULE +static +#endif + krb5_error_code hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg) { krb5_error_code ret; char *search_base, *p; - asprintf(&p, "ldapi:%s", arg); - if (p == NULL) { + if (asprintf(&p, "ldapi:%s", arg) == -1 || p == NULL) { *db = NULL; krb5_set_error_message(context, ENOMEM, "out of memory"); return ENOMEM; @@ -1928,19 +2065,33 @@ hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg) } #ifdef OPENLDAP_MODULE +static krb5_error_code +init(krb5_context context, void **ctx) +{ + *ctx = NULL; + return 0; +} -struct hdb_so_method hdb_ldap_interface = { +static void +fini(void *ctx) +{ +} + +struct hdb_method hdb_ldap_interface = { HDB_INTERFACE_VERSION, + init, + fini, "ldap", hdb_ldap_create }; -struct hdb_so_method hdb_ldapi_interface = { +struct hdb_method hdb_ldapi_interface = { HDB_INTERFACE_VERSION, + init, + fini, "ldapi", hdb_ldapi_create }; - #endif #endif /* OPENLDAP */ diff --git a/lib/hdb/hdb-mdb.c b/lib/hdb/hdb-mdb.c new file mode 100644 index 000000000000..920d7780e844 --- /dev/null +++ b/lib/hdb/hdb-mdb.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (c) 2011 - Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#if HAVE_LMDB + +/* LMDB */ + +#include <lmdb.h> + +#define KILO 1024 + +typedef struct mdb_info { + MDB_env *e; + MDB_txn *t; + MDB_dbi d; + MDB_cursor *c; +} mdb_info; + +static krb5_error_code +DB_close(krb5_context context, HDB *db) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + + mdb_cursor_close(mi->c); + mdb_txn_abort(mi->t); + mdb_env_close(mi->e); + mi->c = 0; + mi->t = 0; + mi->e = 0; + return 0; +} + +static krb5_error_code +DB_destroy(krb5_context context, HDB *db) +{ + krb5_error_code ret; + + ret = hdb_clear_master_key (context, db); + free(db->hdb_name); + free(db->hdb_db); + free(db); + return ret; +} + +static krb5_error_code +DB_lock(krb5_context context, HDB *db, int operation) +{ + db->lock_count++; + return 0; +} + +static krb5_error_code +DB_unlock(krb5_context context, HDB *db) +{ + if (db->lock_count > 1) { + db->lock_count--; + return 0; + } + heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); + db->lock_count--; + return 0; +} + + +static krb5_error_code +DB_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry_ex *entry, int flag) +{ + mdb_info *mi = db->hdb_db; + MDB_val key, value; + krb5_data key_data, data; + int code; + + key.mv_size = 0; + value.mv_size = 0; + code = mdb_cursor_get(mi->c, &key, &value, flag); + if (code == MDB_NOTFOUND) + return HDB_ERR_NOENTRY; + if (code) + return code; + + key_data.data = key.mv_data; + key_data.length = key.mv_size; + data.data = value.mv_data; + data.length = value.mv_size; + memset(entry, 0, sizeof(*entry)); + if (hdb_value2entry(context, &data, &entry->entry)) + return DB_seq(context, db, flags, entry, MDB_NEXT); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, &entry->entry); + if (code) + hdb_free_entry (context, entry); + } + if (entry->entry.principal == NULL) { + entry->entry.principal = malloc(sizeof(*entry->entry.principal)); + if (entry->entry.principal == NULL) { + hdb_free_entry (context, entry); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } else { + hdb_key2principal(context, &key_data, entry->entry.principal); + } + } + return 0; +} + + +static krb5_error_code +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +{ + mdb_info *mi = db->hdb_db; + int code; + + /* Always start with a fresh cursor to pick up latest DB state */ + if (mi->t) + mdb_txn_abort(mi->t); + + code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &mi->t); + if (code) + return code; + + code = mdb_cursor_open(mi->t, mi->d, &mi->c); + if (code) + return code; + + return DB_seq(context, db, flags, entry, MDB_FIRST); +} + + +static krb5_error_code +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +{ + return DB_seq(context, db, flags, entry, MDB_NEXT); +} + +static krb5_error_code +DB_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old, *new; + + if (strncmp(new_name, "mdb:", sizeof("mdb:") - 1) == 0) + new_name += sizeof("mdb:") - 1; + else if (strncmp(new_name, "lmdb:", sizeof("lmdb:") - 1) == 0) + new_name += sizeof("lmdb:") - 1; + if (asprintf(&old, "%s.mdb", db->hdb_name) == -1) + return ENOMEM; + if (asprintf(&new, "%s.mdb", new_name) == -1) { + free(old); + return ENOMEM; + } + ret = rename(old, new); + free(old); + free(new); + if(ret) + return errno; + + free(db->hdb_name); + db->hdb_name = strdup(new_name); + return 0; +} + +static krb5_error_code +DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn; + MDB_val k, v; + int code; + + k.mv_data = key.data; + k.mv_size = key.length; + + code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &txn); + if (code) + return code; + + code = mdb_get(txn, mi->d, &k, &v); + if (code == 0) + krb5_data_copy(reply, v.mv_data, v.mv_size); + mdb_txn_abort(txn); + if(code == MDB_NOTFOUND) + return HDB_ERR_NOENTRY; + return code; +} + +static krb5_error_code +DB__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn; + MDB_val k, v; + int code; + + k.mv_data = key.data; + k.mv_size = key.length; + v.mv_data = value.data; + v.mv_size = value.length; + + code = mdb_txn_begin(mi->e, NULL, 0, &txn); + if (code) + return code; + + code = mdb_put(txn, mi->d, &k, &v, replace ? 0 : MDB_NOOVERWRITE); + if (code) + mdb_txn_abort(txn); + else + code = mdb_txn_commit(txn); + if(code == MDB_KEYEXIST) + return HDB_ERR_EXISTS; + return code; +} + +static krb5_error_code +DB__del(krb5_context context, HDB *db, krb5_data key) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn; + MDB_val k; + krb5_error_code code; + + k.mv_data = key.data; + k.mv_size = key.length; + + code = mdb_txn_begin(mi->e, NULL, 0, &txn); + if (code) + return code; + + code = mdb_del(txn, mi->d, &k, NULL); + if (code) + mdb_txn_abort(txn); + else + code = mdb_txn_commit(txn); + if(code == MDB_NOTFOUND) + return HDB_ERR_NOENTRY; + return code; +} + +static krb5_error_code +DB_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + MDB_txn *txn; + char *fn; + krb5_error_code ret; + int myflags = MDB_NOSUBDIR, tmp; + + if((flags & O_ACCMODE) == O_RDONLY) + myflags |= MDB_RDONLY; + + if (asprintf(&fn, "%s.mdb", db->hdb_name) == -1) + return krb5_enomem(context); + if (mdb_env_create(&mi->e)) { + free(fn); + return krb5_enomem(context); + } + + tmp = krb5_config_get_int_default(context, NULL, 0, "kdc", + "hdb-mdb-maxreaders", NULL); + if (tmp) { + ret = mdb_env_set_maxreaders(mi->e, tmp); + if (ret) { + free(fn); + krb5_set_error_message(context, ret, "setting maxreaders on %s: %s", + db->hdb_name, mdb_strerror(ret)); + return ret; + } + } + + tmp = krb5_config_get_int_default(context, NULL, 0, "kdc", + "hdb-mdb-mapsize", NULL); + if (tmp) { + size_t maps = tmp; + maps *= KILO; + ret = mdb_env_set_mapsize(mi->e, maps); + if (ret) { + free(fn); + krb5_set_error_message(context, ret, "setting mapsize on %s: %s", + db->hdb_name, mdb_strerror(ret)); + return ret; + } + } + + ret = mdb_env_open(mi->e, fn, myflags, mode); + free(fn); + if (ret) { +fail: + mdb_env_close(mi->e); + mi->e = 0; + krb5_set_error_message(context, ret, "opening %s: %s", + db->hdb_name, mdb_strerror(ret)); + return ret; + } + + ret = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &txn); + if (ret) + goto fail; + + ret = mdb_open(txn, NULL, 0, &mi->d); + mdb_txn_abort(txn); + if (ret) + goto fail; + + if((flags & O_ACCMODE) == O_RDONLY) + ret = hdb_check_db_format(context, db); + else + ret = hdb_init_db(context, db); + if(ret == HDB_ERR_NOENTRY) + return 0; + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (flags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + + return ret; +} + +krb5_error_code +hdb_mdb_create(krb5_context context, HDB **db, + const char *filename) +{ + *db = calloc(1, sizeof(**db)); + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = calloc(1, sizeof(mdb_info)); + if ((*db)->hdb_db == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free((*db)->hdb_db); + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + (*db)->hdb_open = DB_open; + (*db)->hdb_close = DB_close; + (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; + (*db)->hdb_store = _hdb_store; + (*db)->hdb_remove = _hdb_remove; + (*db)->hdb_firstkey = DB_firstkey; + (*db)->hdb_nextkey= DB_nextkey; + (*db)->hdb_lock = DB_lock; + (*db)->hdb_unlock = DB_unlock; + (*db)->hdb_rename = DB_rename; + (*db)->hdb__get = DB__get; + (*db)->hdb__put = DB__put; + (*db)->hdb__del = DB__del; + (*db)->hdb_destroy = DB_destroy; + return 0; +} +#endif /* HAVE_LMDB */ diff --git a/lib/hdb/hdb-mitdb.c b/lib/hdb/hdb-mitdb.c index cd619b3b8eb4..4e4fcdc58556 100644 --- a/lib/hdb/hdb-mitdb.c +++ b/lib/hdb/hdb-mitdb.c @@ -91,18 +91,28 @@ salt: #include "hdb_locl.h" -#define KDB_V1_BASE_LENGTH 38 - -#if HAVE_DB1 +static void +attr_to_flags(unsigned attr, HDBFlags *flags) +{ + flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); + flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); + flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); + flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); + flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); + /* DUP_SKEY */ + flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); + flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); + flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); + flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); + flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); + flags->client = 1; /* XXX */ +} -#if defined(HAVE_DB_185_H) -#include <db_185.h> -#elif defined(HAVE_DB_H) -#include <db.h> -#endif +#define KDB_V1_BASE_LENGTH 38 #define CHECK(x) do { if ((x)) goto out; } while(0) +#ifdef HAVE_DB1 static krb5_error_code mdb_principal2key(krb5_context context, krb5_const_principal principal, @@ -118,6 +128,7 @@ mdb_principal2key(krb5_context context, key->length = strlen(str) + 1; return 0; } +#endif /* HAVE_DB1 */ #define KRB5_KDB_SALTTYPE_NORMAL 0 #define KRB5_KDB_SALTTYPE_V4 1 @@ -128,10 +139,10 @@ mdb_principal2key(krb5_context context, #define KRB5_KDB_SALTTYPE_CERTHASH 6 static krb5_error_code -fix_salt(krb5_context context, hdb_entry *ent, int key_num) +fix_salt(krb5_context context, hdb_entry *ent, Key *k) { krb5_error_code ret; - Salt *salt = ent->keys.val[key_num].salt; + Salt *salt = k->salt; /* fix salt type */ switch((int)salt->type) { case KRB5_KDB_SALTTYPE_NORMAL: @@ -187,8 +198,8 @@ fix_salt(krb5_context context, hdb_entry *ent, int key_num) break; case KRB5_KDB_SALTTYPE_CERTHASH: krb5_data_free(&salt->salt); - free(ent->keys.val[key_num].salt); - ent->keys.val[key_num].salt = NULL; + free(k->salt); + k->salt = NULL; break; default: abort(); @@ -197,16 +208,216 @@ fix_salt(krb5_context context, hdb_entry *ent, int key_num) } +/** + * This function takes a key from a krb5_storage from an MIT KDB encoded + * entry and places it in the given Key object. + * + * @param context Context + * @param entry HDB entry + * @param sp krb5_storage with current offset set to the beginning of a + * key + * @param version See comments in caller body for the backstory on this + * @param k Key * to load the key into + */ +static krb5_error_code +mdb_keyvalue2key(krb5_context context, hdb_entry *entry, krb5_storage *sp, uint16_t version, Key *k) +{ + size_t i; + uint16_t u16, type; + krb5_error_code ret; + + k->mkvno = malloc(sizeof(*k->mkvno)); + if (k->mkvno == NULL) { + ret = ENOMEM; + goto out; + } + *k->mkvno = 1; + + for (i = 0; i < version; i++) { + CHECK(ret = krb5_ret_uint16(sp, &type)); + CHECK(ret = krb5_ret_uint16(sp, &u16)); + if (i == 0) { + /* This "version" means we have a key */ + k->key.keytype = type; + /* + * MIT stores keys encrypted keys as {16-bit length + * of plaintext key, {encrypted key}}. The reason + * for this is that the Kerberos cryptosystem is not + * length-preserving. Heimdal's approach is to + * truncate the plaintext to the expected length of + * the key given its enctype, so we ignore this + * 16-bit length-of-plaintext-key field. + */ + if (u16 > 2) { + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ + k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ + k->key.keyvalue.data = malloc(k->key.keyvalue.length); + krb5_storage_read(sp, k->key.keyvalue.data, + k->key.keyvalue.length); + } else { + /* We'll ignore this key; see our caller */ + k->key.keyvalue.length = 0; + k->key.keyvalue.data = NULL; + krb5_storage_seek(sp, u16, SEEK_CUR); /* skip real length */ + } + } else if (i == 1) { + /* This "version" means we have a salt */ + k->salt = calloc(1, sizeof(*k->salt)); + if (k->salt == NULL) { + ret = ENOMEM; + goto out; + } + k->salt->type = type; + if (u16 != 0) { + k->salt->salt.data = malloc(u16); + if (k->salt->salt.data == NULL) { + ret = ENOMEM; + goto out; + } + k->salt->salt.length = u16; + krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); + } + fix_salt(context, entry, k); + } else { + /* + * Whatever this "version" might be, we skip it + * + * XXX A krb5.conf parameter requesting that we log + * about strangeness like this, or return an error + * from here, might be nice. + */ + krb5_storage_seek(sp, u16, SEEK_CUR); + } + } + + return 0; + +out: + free_Key(k); + return ret; +} + + +static krb5_error_code +add_1des_dup(krb5_context context, Keys *keys, Key *key, krb5_keytype keytype) +{ + key->key.keytype = keytype; + return add_Keys(keys, key); +} + +/* + * This monstrosity is here so we can avoid having to do enctype + * similarity checking in the KDC. This helper function dups 1DES keys + * in a keyset for all the similar 1DES enctypes for which keys are + * missing. And, of course, we do this only if there's any 1DES keys in + * the keyset to begin with. + */ static krb5_error_code -mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry) +dup_similar_keys_in_keyset(krb5_context context, Keys *keys) +{ + krb5_error_code ret; + size_t i, k; + Key key; + int keyset_has_1des_crc = 0; + int keyset_has_1des_md4 = 0; + int keyset_has_1des_md5 = 0; + + memset(&key, 0, sizeof (key)); + k = keys->len; + for (i = 0; i < keys->len; i++) { + if (keys->val[i].key.keytype == ETYPE_DES_CBC_CRC) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD4) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD5) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } + } + if (k == keys->len) + return 0; + + ret = copy_Key(&keys->val[k], &key); + if (ret) + return ret; + if (!keyset_has_1des_crc) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_CRC); + if (ret) + goto out; + } + if (!keyset_has_1des_md4) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD4); + if (ret) + goto out; + } + if (!keyset_has_1des_md5) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD5); + if (ret) + goto out; + } + +out: + free_Key(&key); + return ret; +} + + +static krb5_error_code +dup_similar_keys(krb5_context context, hdb_entry *entry) +{ + krb5_error_code ret; + HDB_Ext_KeySet *hist_keys; + HDB_extension *extp; + size_t i; + + ret = dup_similar_keys_in_keyset(context, &entry->keys); + if (ret) + return ret; + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) + return 0; + + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + ret = dup_similar_keys_in_keyset(context, &hist_keys->val[i].keys); + if (ret) + return ret; + } + return 0; +} + + +/** + * This function parses an MIT krb5 encoded KDB entry and fills in the + * given HDB entry with it. + * + * @param context krb5_context + * @param data Encoded MIT KDB entry + * @param target_kvno Desired kvno, or 0 for the entry's current kvno + * @param entry Desired kvno, or 0 for the entry's current kvno + */ +krb5_error_code +_hdb_mdb_value2entry(krb5_context context, krb5_data *data, + krb5_kvno target_kvno, hdb_entry *entry) { krb5_error_code ret; krb5_storage *sp; + Key k; + krb5_kvno key_kvno; uint32_t u32; uint16_t u16, num_keys, num_tl; - size_t i, j; + ssize_t sz; + size_t i; char *p; + memset(&k, 0, sizeof (k)); + memset(entry, 0, sizeof(*entry)); + sp = krb5_storage_from_data(data); if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "out of memory"); @@ -228,24 +439,14 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry * XXX But... surely we ought to log about this extra data, or skip * it, or something, in case anyone has MIT KDBs with ancient * entries in them... Logging would allow the admin to know which - * entries to dump with MIT krb5's kdb5_util. + * entries to dump with MIT krb5's kdb5_util. But logging would be + * noisy. For now we do nothing. */ CHECK(ret = krb5_ret_uint16(sp, &u16)); if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } /* 32: attributes */ CHECK(ret = krb5_ret_uint32(sp, &u32)); - entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED); - entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE); - entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED); - entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE); - entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE); - /* DUP_SKEY */ - entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX); - entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH); - entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH); - entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR); - entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE); - entry->flags.client = 1; /* XXX */ + attr_to_flags(u32, &entry->flags); /* 32: max time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); @@ -296,7 +497,11 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry ret = ENOMEM; goto out; } - krb5_storage_read(sp, p, u16); + sz = krb5_storage_read(sp, p, u16); + if (sz != u16) { + ret = EINVAL; /* XXX */ + goto out; + } p[u16] = '\0'; CHECK(ret = krb5_parse_name(context, p, &entry->principal)); free(p); @@ -305,12 +510,53 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry 16: tl data type 16: tl data length length: length */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 for (i = 0; i < num_tl; i++) { + int tl_type; + krb5_principal modby; /* 16: TL data type */ CHECK(ret = krb5_ret_uint16(sp, &u16)); + tl_type = u16; /* 16: TL data length */ CHECK(ret = krb5_ret_uint16(sp, &u16)); - krb5_storage_seek(sp, u16, SEEK_CUR); + /* + * For rollback to MIT purposes we really must understand some + * TL data! + * + * XXX Move all this to separate functions, one per-TL type. + */ + switch (tl_type) { + case mit_KRB5_TL_LAST_PWD_CHANGE: + CHECK(ret = krb5_ret_uint32(sp, &u32)); + CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32)); + break; + case mit_KRB5_TL_MOD_PRINC: + if (u16 < 5) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */ + p = malloc(u16 - 4 + 1); + if (!p) { + ret = ENOMEM; + goto out; + } + p[u16 - 4] = '\0'; + sz = krb5_storage_read(sp, p, u16 - 4); + if (sz != u16 - 4) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_parse_name(context, p, &modby)); + ret = hdb_set_last_modified_by(context, entry, modby, u32); + krb5_free_principal(context, modby); + free(p); + break; + default: + krb5_storage_seek(sp, u16, SEEK_CUR); + break; + } } /* * for num key data times @@ -326,140 +572,92 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry * That's right... hold that gag reflex, you can do it. */ for (i = 0; i < num_keys; i++) { - int keep = 0; uint16_t version; - void *ptr; CHECK(ret = krb5_ret_uint16(sp, &u16)); version = u16; CHECK(ret = krb5_ret_uint16(sp, &u16)); + key_kvno = u16; - /* - * First time through, and until we find one matching key, - * entry->kvno == 0. - */ - if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) { - keep = 1; - entry->kvno = u16; + ret = mdb_keyvalue2key(context, entry, sp, version, &k); + if (ret) + goto out; + if (k.key.keytype == 0 || k.key.keyvalue.length == 0) { /* - * Found a higher kvno than earlier, so free the old highest - * kvno keys. + * Older MIT KDBs may have enctype 0 / length 0 keys. We + * ignore these. + */ + free_Key(&k); + continue; + } + + if ((target_kvno == 0 && entry->kvno < key_kvno) || + (target_kvno == key_kvno && entry->kvno != target_kvno)) { + /* + * MIT's KDB doesn't keep track of kvno. The highest kvno + * is the current kvno, and we just found a new highest + * kvno or the desired kvno. + * + * Note that there's no guarantee of any key ordering, but + * generally MIT KDB entries have keys in strictly + * descending kvno order. * - * XXX Of course, we actually want to extract the old kvnos - * as well, for some of the kadm5 APIs. We shouldn't free - * these keys, but keep them elsewhere. + * XXX We do assume that keys are clustered by kvno. If + * not, then bad. It might be possible to construct + * non-clustered keys via the kadm5 API. It wouldn't be + * hard to cope with this, since if it happens the worst + * that will happen is that some of the current keys can be + * found in the history extension, and we could just pull + * them back out in that case. */ - for (j = 0; j < entry->keys.len; j++) - free_Key(&entry->keys.val[j]); - free(entry->keys.val); - entry->keys.len = 0; - entry->keys.val = NULL; - } else if (entry->kvno == u16) - /* Accumulate keys */ - keep = 1; - - if (keep) { - Key *k; - - ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1)); - if (ptr == NULL) { - ret = ENOMEM; + ret = hdb_add_current_keys_to_history(context, entry); + if (ret) goto out; - } - entry->keys.val = ptr; - - /* k points to current Key */ - k = &entry->keys.val[entry->keys.len]; - - memset(k, 0, sizeof(*k)); - entry->keys.len += 1; - - k->mkvno = malloc(sizeof(*k->mkvno)); - if (k->mkvno == NULL) { - ret = ENOMEM; + free_Keys(&entry->keys); + ret = add_Keys(&entry->keys, &k); + free_Key(&k); + if (ret) goto out; - } - *k->mkvno = 1; - - for (j = 0; j < version; j++) { - uint16_t type; - CHECK(ret = krb5_ret_uint16(sp, &type)); - CHECK(ret = krb5_ret_uint16(sp, &u16)); - if (j == 0) { - /* This "version" means we have a key */ - k->key.keytype = type; - if (u16 < 2) { - ret = EINVAL; - goto out; - } - /* - * MIT stores keys encrypted keys as {16-bit length - * of plaintext key, {encrypted key}}. The reason - * for this is that the Kerberos cryptosystem is not - * length-preserving. Heimdal's approach is to - * truncate the plaintext to the expected length of - * the key given its enctype, so we ignore this - * 16-bit length-of-plaintext-key field. - */ - krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ - k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ - k->key.keyvalue.data = malloc(k->key.keyvalue.length); - krb5_storage_read(sp, k->key.keyvalue.data, - k->key.keyvalue.length); - } else if (j == 1) { - /* This "version" means we have a salt */ - k->salt = calloc(1, sizeof(*k->salt)); - if (k->salt == NULL) { - ret = ENOMEM; - goto out; - } - k->salt->type = type; - if (u16 != 0) { - k->salt->salt.data = malloc(u16); - if (k->salt->salt.data == NULL) { - ret = ENOMEM; - goto out; - } - k->salt->salt.length = u16; - krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); - } - fix_salt(context, entry, entry->keys.len - 1); - } else { - /* - * Whatever this "version" might be, we skip it - * - * XXX A krb5.conf parameter requesting that we log - * about strangeness like this, or return an error - * from here, might be nice. - */ - krb5_storage_seek(sp, u16, SEEK_CUR); - } - } - } else { + entry->kvno = key_kvno; + continue; + } + + if (entry->kvno == key_kvno) { /* - * XXX For now we skip older kvnos, but we should extract - * them... + * Note that if key_kvno == 0 and target_kvno == 0 then we + * end up adding those keys here. Yeah, kvno 0 is very + * special for us, but just in case, we keep such keys. */ - for (j = 0; j < version; j++) { - /* enctype */ - CHECK(ret = krb5_ret_uint16(sp, &u16)); - /* encrypted key (or plaintext salt) */ - CHECK(ret = krb5_ret_uint16(sp, &u16)); - krb5_storage_seek(sp, u16, SEEK_CUR); - } + ret = add_Keys(&entry->keys, &k); + free_Key(&k); + if (ret) + goto out; + entry->kvno = key_kvno; + } else { + ret = hdb_add_history_key(context, entry, key_kvno, &k); + if (ret) + goto out; + free_Key(&k); } } - if (entry->kvno == 0 && kvno != 0) { - ret = HDB_ERR_NOT_FOUND_HERE; + if (target_kvno != 0 && entry->kvno != target_kvno) { + ret = HDB_ERR_KVNO_NOT_FOUND; goto out; } - return 0; - out: + krb5_storage_free(sp); + + return dup_similar_keys(context, entry); + +out: + krb5_storage_free(sp); + if (ret == HEIM_ERR_EOF) /* Better error code than "end of file" */ ret = HEIM_ERR_BAD_HDBENT_ENCODING; + free_hdb_entry(entry); + free_Key(&k); return ret; } @@ -471,6 +669,14 @@ mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) } #endif +#if HAVE_DB1 + +#if defined(HAVE_DB_185_H) +#include <db_185.h> +#elif defined(HAVE_DB_H) +#include <db.h> +#endif + static krb5_error_code mdb_close(krb5_context context, HDB *db) @@ -496,12 +702,24 @@ mdb_lock(krb5_context context, HDB *db, int operation) { DB *d = (DB*)db->hdb_db; int fd = (*d->fd)(d); + krb5_error_code ret; + + if (db->lock_count > 1) { + db->lock_count++; + if (db->lock_type == HDB_WLOCK || db->lock_count == operation) + return 0; + } + if(fd < 0) { krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, "Can't lock database: %s", db->hdb_name); return HDB_ERR_CANT_LOCK_DB; } - return hdb_lock(fd, operation); + ret = hdb_lock(fd, operation); + if (ret) + return ret; + db->lock_count++; + return 0; } static krb5_error_code @@ -509,6 +727,14 @@ mdb_unlock(krb5_context context, HDB *db) { DB *d = (DB*)db->hdb_db; int fd = (*d->fd)(d); + + if (db->lock_count > 1) { + db->lock_count--; + return 0; + } + heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); + db->lock_count--; + if(fd < 0) { krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, "Can't unlock database: %s", db->hdb_name); @@ -551,7 +777,7 @@ mdb_seq(krb5_context context, HDB *db, data.length = value.size; memset(entry, 0, sizeof(*entry)); - if (mdb_value2entry(context, &data, 0, &entry->entry)) + if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry)) return mdb_seq(context, db, flags, entry, R_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { @@ -581,19 +807,25 @@ static krb5_error_code mdb_rename(krb5_context context, HDB *db, const char *new_name) { int ret; - char *old, *new; + char *old = NULL; + char *new = NULL; - asprintf(&old, "%s.db", db->hdb_name); - asprintf(&new, "%s.db", new_name); + if (asprintf(&old, "%s.db", db->hdb_name) < 0) + goto out; + if (asprintf(&new, "%s.db", new_name) < 0) + goto out; ret = rename(old, new); - free(old); - free(new); if(ret) - return errno; + goto out; free(db->hdb_name); db->hdb_name = strdup(new_name); - return 0; + errno = 0; + +out: + free(old); + free(new); + return errno; } static krb5_error_code @@ -684,24 +916,26 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) { krb5_data key, value; - krb5_error_code code; + krb5_error_code ret; - code = mdb_principal2key(context, principal, &key); - if (code) - return code; - code = db->hdb__get(context, db, key, &value); + ret = mdb_principal2key(context, principal, &key); + if (ret) + return ret; + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if(code) - return code; - code = mdb_value2entry(context, &value, kvno, &entry->entry); + if(ret) + return ret; + ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry); krb5_data_free(&value); - if (code) - return code; + if (ret) + return ret; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); - if (code) + ret = hdb_unseal_keys (context, db, &entry->entry); + if (ret) { hdb_free_entry(context, entry); + return ret; + } } return 0; @@ -710,15 +944,83 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, static krb5_error_code mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { - krb5_set_error_message(context, EINVAL, "can't set principal in mdb"); - return EINVAL; + krb5_error_code ret; + krb5_storage *sp = NULL; + krb5_storage *spent = NULL; + krb5_data line = { 0, 0 }; + krb5_data kdb_ent = { 0, 0 }; + krb5_data key = { 0, 0 }; + krb5_data value = { 0, 0 }; + ssize_t sz; + + if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE)) + return 0; + + if ((flags & HDB_F_PRECHECK)) { + ret = mdb_principal2key(context, entry->entry.principal, &key); + if (ret) return ret; + ret = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (ret == 0) + krb5_data_free(&value); + if (ret == HDB_ERR_NOENTRY) + return 0; + return ret ? ret : HDB_ERR_EXISTS; + } + + sp = krb5_storage_emem(); + if (!sp) return ENOMEM; + ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */ + ret = hdb_seal_keys(context, db, &entry->entry); + if (ret) return ret; + ret = entry2mit_string_int(context, sp, &entry->entry); + if (ret) goto out; + sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */ + ret = ENOMEM; + if (sz == -1) goto out; + ret = krb5_storage_to_data(sp, &line); + if (ret) goto out; + + ret = ENOMEM; + spent = krb5_storage_emem(); + if (!spent) goto out; + ret = _hdb_mit_dump2mitdb_entry(context, line.data, spent); + if (ret) goto out; + ret = krb5_storage_to_data(spent, &kdb_ent); + if (ret) goto out; + ret = mdb_principal2key(context, entry->entry.principal, &key); + if (ret) goto out; + ret = mdb__put(context, db, 1, key, kdb_ent); + +out: + if (sp) + krb5_storage_free(sp); + if (spent) + krb5_storage_free(spent); + krb5_data_free(&line); + krb5_data_free(&kdb_ent); + krb5_data_free(&key); + + return ret; } static krb5_error_code -mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) +mdb_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) { krb5_error_code code; krb5_data key; + krb5_data value = { 0, 0 }; + + if ((flags & HDB_F_PRECHECK)) { + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code == 0) { + krb5_data_free(&value); + return 0; + } + return code; + } mdb_principal2key(context, principal, &key); code = db->hdb__del(context, db, key); @@ -730,40 +1032,47 @@ static krb5_error_code mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) { char *fn; + char *actual_fn; krb5_error_code ret; + struct stat st; - asprintf(&fn, "%s.db", db->hdb_name); - if (fn == NULL) { + if (asprintf(&fn, "%s.db", db->hdb_name) < 0) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } - db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); - free(fn); + if (stat(fn, &st) == 0) + actual_fn = fn; + else + actual_fn = db->hdb_name; + db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); if (db->hdb_db == NULL) { switch (errno) { #ifdef EFTYPE case EFTYPE: #endif case EINVAL: - db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); + db->hdb_db = dbopen(actual_fn, flags, mode, DB_HASH, NULL); } } + free(fn); - /* try to open without .db extension */ - if(db->hdb_db == NULL && errno == ENOENT) - db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); - if(db->hdb_db == NULL) { + if (db->hdb_db == NULL) { ret = errno; krb5_set_error_message(context, ret, "dbopen (%s): %s", db->hdb_name, strerror(ret)); return ret; } - if((flags & O_ACCMODE) == O_RDONLY) - ret = hdb_check_db_format(context, db); - else +#if 0 + /* + * Don't do this -- MIT won't be able to handle the + * HDB_DB_FORMAT_ENTRY key. + */ + if ((flags & O_ACCMODE) != O_RDONLY) ret = hdb_init_db(context, db); - if(ret == HDB_ERR_NOENTRY) { +#endif + ret = hdb_check_db_format(context, db); + if (ret == HDB_ERR_NOENTRY) { krb5_clear_error_message(context); return 0; } @@ -778,8 +1087,8 @@ mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) } krb5_error_code -hdb_mdb_create(krb5_context context, HDB **db, - const char *filename) +hdb_mitdb_create(krb5_context context, HDB **db, + const char *filename) { *db = calloc(1, sizeof(**db)); if (*db == NULL) { @@ -816,3 +1125,347 @@ hdb_mdb_create(krb5_context context, HDB **db, } #endif /* HAVE_DB1 */ + +/* +can have any number of princ stanzas. +format is as follows (only \n indicates newlines) +princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) +%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) +%d\t (number of tl_data) +%d\t (number of key data, e.g. how many keys for this user) +%d\t (extra data length) +%s\t (principal name) +%d\t (attributes) +%d\t (max lifetime, seconds) +%d\t (max renewable life, seconds) +%d\t (expiration, seconds since epoch or 2145830400 for never) +%d\t (password expiration, seconds, 0 for never) +%d\t (last successful auth, seconds since epoch) +%d\t (last failed auth, per above) +%d\t (failed auth count) +foreach tl_data 0 to number of tl_data - 1 as above + %d\t%d\t (data type, data length) + foreach tl_data 0 to length-1 + %02x (tl data contents[element n]) + except if tl_data length is 0 + %d (always -1) + \t +foreach key 0 to number of keys - 1 as above + %d\t%d\t (key data version, kvno) + foreach version 0 to key data version - 1 (a key or a salt) + %d\t%d\t(data type for this key, data length for this key) + foreach key data length 0 to length-1 + %02x (key data contents[element n]) + except if key_data length is 0 + %d (always -1) + \t +foreach extra data length 0 to length - 1 + %02x (extra data part) +unless no extra data + %d (always -1) +;\n + +*/ + +#if 0 +/* Why ever did we loop? */ +static char * +nexttoken(char **p) +{ + char *q; + do { + q = strsep(p, " \t"); + } while(q && *q == '\0'); + return q; +} +#endif + +static char * +nexttoken(char **p, size_t len, const char *what) +{ + char *q; + + if (*p == NULL) + return NULL; + + q = *p; + *p += len; + /* Must be followed by a delimiter (right?) */ + if (strsep(p, " \t") != q + len) { + warnx("No tokens left in dump entry while looking for %s", what); + return NULL; + } + if (*q == '\0') + warnx("Empty last token in dump entry while looking for %s", what); + return q; +} + +static size_t +getdata(char **p, unsigned char *buf, size_t len, const char *what) +{ + size_t i; + int v; + char *q = nexttoken(p, 0, what); + if (q == NULL) { + warnx("Failed to find hex-encoded binary data (%s) in dump", what); + return 0; + } + i = 0; + while (*q && i < len) { + if (sscanf(q, "%02x", &v) != 1) + break; + buf[i++] = v; + q += 2; + } + return i; +} + +static int +getint(char **p, const char *what) +{ + int val; + char *q = nexttoken(p, 0, what); + if (!q) { + warnx("Failed to find a signed integer (%s) in dump", what); + return -1; + } + if (sscanf(q, "%d", &val) != 1) + return -1; + return val; +} + +static unsigned int +getuint(char **p, const char *what) +{ + int val; + char *q = nexttoken(p, 0, what); + if (!q) { + warnx("Failed to find an unsigned integer (%s) in dump", what); + return 0; + } + if (sscanf(q, "%u", &val) != 1) + return 0; + return val; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +#define CHECK_UINT(num) \ + if ((num) < 0 || (num) > INT_MAX) return EINVAL +#define CHECK_UINT16(num) \ + if ((num) < 0 || (num) > 1<<15) return EINVAL +#define CHECK_NUM(num, maxv) \ + if ((num) > (maxv)) return EINVAL + +/* + * This utility function converts an MIT dump entry to an MIT on-disk + * encoded entry, which can then be decoded with _hdb_mdb_value2entry(). + * This allows us to have a single decoding function (_hdb_mdb_value2entry), + * which makes the code cleaner (less code duplication), if a bit less + * efficient. It also will allow us to have a function to dump an HDB + * entry in MIT format so we can dump HDB into MIT format for rollback + * purposes. And that will allow us to write to MIT KDBs, again + * somewhat inefficiently, also for migration/rollback purposes. + */ +int +_hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) +{ + krb5_error_code ret = EINVAL; + char *p = line, *q; + char *princ; + ssize_t sz; + size_t i; + size_t princ_len; + unsigned int num_tl_data; + size_t num_key_data; + unsigned int attributes; + int tmp; + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + q = nexttoken(&p, 0, "record type (princ or policy)"); + if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || + strcmp(q, "princ") != 0) { + warnx("Supposed MIT dump entry does not start with 'kdb5_util', " + "'policy', nor 'princ'"); + return -1; + } + if (getint(&p, "constant '38'") != 38) { + warnx("Dump entry does not start with '38<TAB>'"); + return EINVAL; + } +#define KDB_V1_BASE_LENGTH 38 + ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); + if (ret) return ret; + + princ_len = getuint(&p, "principal name length"); + if (princ_len > (1<<15) - 1) { + warnx("Principal name in dump entry too long (%llu)", + (unsigned long long)princ_len); + return EINVAL; + } + num_tl_data = getuint(&p, "number of TL data"); + num_key_data = getuint(&p, "number of key data"); + getint(&p, "5th field, length of 'extra data'"); + princ = nexttoken(&p, (int)princ_len, "principal name"); + if (princ == NULL) { + warnx("Failed to read principal name (expected length %llu)", + (unsigned long long)princ_len); + return -1; + } + + attributes = getuint(&p, "attributes"); + ret = krb5_store_uint32(sp, attributes); + if (ret) return ret; + + tmp = getint(&p, "max life"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p, "max renewable life"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p, "expiration"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p, "pw expiration"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p, "last auth"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p, "last failed auth"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p,"fail auth count"); + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + /* add TL data count */ + CHECK_NUM(num_tl_data, 1023); + ret = krb5_store_uint16(sp, num_tl_data); + if (ret) return ret; + + /* add key count */ + CHECK_NUM(num_key_data, 1023); + ret = krb5_store_uint16(sp, num_key_data); + if (ret) return ret; + + /* add principal unparsed name length and unparsed name */ + princ_len = strlen(princ); + princ_len++; /* must count and write the NUL in the on-disk encoding */ + ret = krb5_store_uint16(sp, princ_len); + if (ret) return ret; + sz = krb5_storage_write(sp, princ, princ_len); + if (sz == -1) return ENOMEM; + + /* scan and write TL data */ + for (i = 0; i < num_tl_data; i++) { + char *reading_what; + int tl_type, tl_length; + unsigned char *buf; + + tl_type = getint(&p, "TL data type"); + tl_length = getint(&p, "data length"); + + if (asprintf(&reading_what, "TL data type %d (length %d)", + tl_type, tl_length) < 0) + return ENOMEM; + + /* + * XXX Leaking reading_what, but only on ENOMEM cases anyways, + * so we don't care. + */ + CHECK_UINT16(tl_type); + ret = krb5_store_uint16(sp, tl_type); + if (ret) return ret; + CHECK_UINT16(tl_length); + ret = krb5_store_uint16(sp, tl_length); + if (ret) return ret; + + if (tl_length) { + buf = malloc(tl_length); + if (!buf) return ENOMEM; + if (getdata(&p, buf, tl_length, reading_what) != tl_length) + return EINVAL; + sz = krb5_storage_write(sp, buf, tl_length); + free(buf); + if (sz == -1) return ENOMEM; + } else { + if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL; + } + free(reading_what); + } + + for (i = 0; i < num_key_data; i++) { + unsigned char *buf; + int key_versions; + int kvno; + int keytype; + int keylen; + size_t k; + + key_versions = getint(&p, "key data 'version'"); + CHECK_UINT16(key_versions); + ret = krb5_store_int16(sp, key_versions); + if (ret) return ret; + + kvno = getint(&p, "kvno"); + CHECK_UINT16(kvno); + ret = krb5_store_int16(sp, kvno); + if (ret) return ret; + + for (k = 0; k < key_versions; k++) { + keytype = getint(&p, "enctype"); + CHECK_UINT16(keytype); + ret = krb5_store_int16(sp, keytype); + if (ret) return ret; + + keylen = getint(&p, "encrypted key length"); + CHECK_UINT16(keylen); + ret = krb5_store_int16(sp, keylen); + if (ret) return ret; + + if (keylen) { + buf = malloc(keylen); + if (!buf) return ENOMEM; + if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) + return EINVAL; + sz = krb5_storage_write(sp, buf, keylen); + free(buf); + if (sz == -1) return ENOMEM; + } else { + if (strcmp(nexttoken(&p, 0, + "'-1' zero-length key/salt field"), + "-1") != 0) { + warnx("Expected '-1' field because key/salt length is 0"); + return -1; + } + } + } + } + /* + * The rest is "extra data", but there's never any and we wouldn't + * know what to do with it. + */ + /* nexttoken(&p, 0, "extra data"); */ + return 0; +} + diff --git a/lib/hdb/hdb-private.h b/lib/hdb/hdb-private.h index 8a748694424f..82681997681f 100644 --- a/lib/hdb/hdb-private.h +++ b/lib/hdb/hdb-private.h @@ -15,7 +15,7 @@ _hdb_fetch_kvno ( hdb_master_key _hdb_find_master_key ( - uint32_t */*mkvno*/, + unsigned int */*mkvno*/, hdb_master_key /*mkey*/); krb5_error_code @@ -24,6 +24,19 @@ _hdb_keytab2hdb_entry ( const krb5_keytab_entry */*ktentry*/, hdb_entry_ex */*entry*/); +krb5_error_code +_hdb_mdb_value2entry ( + krb5_context /*context*/, + krb5_data */*data*/, + krb5_kvno /*target_kvno*/, + hdb_entry */*entry*/); + +int +_hdb_mit_dump2mitdb_entry ( + krb5_context /*context*/, + char */*line*/, + krb5_storage */*sp*/); + int _hdb_mkey_decrypt ( krb5_context /*context*/, @@ -49,9 +62,16 @@ krb5_error_code _hdb_remove ( krb5_context /*context*/, HDB */*db*/, + unsigned /*flags*/, krb5_const_principal /*principal*/); krb5_error_code +_hdb_set_master_key_usage ( + krb5_context /*context*/, + HDB */*db*/, + unsigned int /*key_usage*/); + +krb5_error_code _hdb_store ( krb5_context /*context*/, HDB */*db*/, diff --git a/lib/hdb/hdb-protos.h b/lib/hdb/hdb-protos.h index 44a1bddc7625..76855095beed 100644 --- a/lib/hdb/hdb-protos.h +++ b/lib/hdb/hdb-protos.h @@ -1,6 +1,7 @@ /* This is a generated file */ #ifndef __hdb_protos_h__ #define __hdb_protos_h__ +#ifndef DOXY #include <stdarg.h> @@ -9,11 +10,63 @@ extern "C" { #endif krb5_error_code +entry2mit_string_int ( + krb5_context /*context*/, + krb5_storage */*sp*/, + hdb_entry */*ent*/); + +/** + * This function adds an HDB entry's current keyset to the entry's key + * history. The current keyset is left alone; the caller is responsible + * for freeing it. + * + * @param context Context + * @param entry HDB entry + */ + +krb5_error_code +hdb_add_current_keys_to_history ( + krb5_context /*context*/, + hdb_entry */*entry*/); + +/** + * This function adds a key to an HDB entry's key history. + * + * @param context Context + * @param entry HDB entry + * @param kvno Key version number of the key to add to the history + * @param key The Key to add + */ + +krb5_error_code +hdb_add_history_key ( + krb5_context /*context*/, + hdb_entry */*entry*/, + krb5_kvno /*kvno*/, + Key */*key*/); + +krb5_error_code hdb_add_master_key ( krb5_context /*context*/, krb5_keyblock */*key*/, hdb_master_key */*inout*/); +/** + * This function changes an hdb_entry's kvno, swapping the current key + * set with a historical keyset. If no historical keys are found then + * an error is returned (the caller can still set entry->kvno directly). + * + * @param context krb5_context + * @param new_kvno New kvno for the entry + * @param entry hdb_entry to modify + */ + +krb5_error_code +hdb_change_kvno ( + krb5_context /*context*/, + krb5_kvno /*new_kvno*/, + hdb_entry */*entry*/); + krb5_error_code hdb_check_db_format ( krb5_context /*context*/, @@ -30,6 +83,14 @@ hdb_clear_master_key ( krb5_context /*context*/, HDB */*db*/); +/** + * Create a handle for a Kerberos database + * + * Create a handle for a Kerberos database backend specified by a + * filename. Doesn't create a file if its doesn't exists, you have to + * use O_CREAT to tell the backend to create the file. + */ + krb5_error_code hdb_create ( krb5_context /*context*/, @@ -37,11 +98,25 @@ hdb_create ( const char */*filename*/); krb5_error_code -hdb_db_create ( +hdb_db1_create ( krb5_context /*context*/, HDB **/*db*/, const char */*filename*/); +krb5_error_code +hdb_db3_create ( + krb5_context /*context*/, + HDB **/*db*/, + const char */*filename*/); + +/** + * Return the directory where the hdb database resides. + * + * @param context Kerberos 5 context. + * + * @return string pointing to directory. + */ + const char * hdb_db_dir (krb5_context /*context*/); @@ -85,6 +160,14 @@ hdb_dbinfo_get_realm ( krb5_context /*context*/, struct hdb_dbinfo */*dbp*/); +/** + * Return the default hdb database resides. + * + * @param context Kerberos 5 context. + * + * @return string pointing to directory. + */ + const char * hdb_default_db (krb5_context /*context*/); @@ -92,6 +175,7 @@ krb5_error_code hdb_enctype2key ( krb5_context /*context*/, hdb_entry */*e*/, + const Keys */*keyset*/, krb5_enctype /*enctype*/, Key **/*key*/); @@ -118,6 +202,16 @@ hdb_entry_check_mandatory ( krb5_context /*context*/, const hdb_entry */*ent*/); +krb5_error_code +hdb_entry_clear_kvno_diff_clnt ( + krb5_context /*context*/, + hdb_entry */*entry*/); + +krb5_error_code +hdb_entry_clear_kvno_diff_svc ( + krb5_context /*context*/, + hdb_entry */*entry*/); + int hdb_entry_clear_password ( krb5_context /*context*/, @@ -133,6 +227,12 @@ hdb_entry_get_aliases ( const hdb_entry */*entry*/, const HDB_Ext_Aliases **/*a*/); +unsigned int +hdb_entry_get_kvno_diff_clnt (const hdb_entry */*entry*/); + +unsigned int +hdb_entry_get_kvno_diff_svc (const hdb_entry */*entry*/); + int hdb_entry_get_password ( krb5_context /*context*/, @@ -160,6 +260,18 @@ hdb_entry_get_pw_change_time ( const hdb_entry */*entry*/, time_t */*t*/); +krb5_error_code +hdb_entry_set_kvno_diff_clnt ( + krb5_context /*context*/, + hdb_entry */*entry*/, + unsigned int /*diff*/); + +krb5_error_code +hdb_entry_set_kvno_diff_svc ( + krb5_context /*context*/, + hdb_entry */*entry*/, + unsigned int /*diff*/); + int hdb_entry_set_password ( krb5_context /*context*/, @@ -214,6 +326,8 @@ krb5_error_code hdb_generate_key_set ( krb5_context /*context*/, krb5_principal /*principal*/, + krb5_key_salt_tuple */*ks_tuple*/, + int /*n_ks_tuple*/, Key **/*ret_key_set*/, size_t */*nkeyset*/, int /*no_salt*/); @@ -226,6 +340,16 @@ hdb_generate_key_set_password ( Key **/*keys*/, size_t */*num_keys*/); +krb5_error_code +hdb_generate_key_set_password_with_ks_tuple ( + krb5_context /*context*/, + krb5_principal /*principal*/, + const char */*password*/, + krb5_key_salt_tuple */*ks_tuple*/, + int /*n_ks_tuple*/, + Key **/*keys*/, + size_t */*num_keys*/); + int hdb_get_dbinfo ( krb5_context /*context*/, @@ -248,6 +372,12 @@ hdb_keytab_create ( HDB ** /*db*/, const char */*arg*/); +const Keys * +hdb_kvno2keys ( + krb5_context /*context*/, + const hdb_entry */*e*/, + krb5_kvno /*kvno*/); + krb5_error_code hdb_ldap_create ( krb5_context /*context*/, @@ -277,6 +407,12 @@ hdb_mdb_create ( const char */*filename*/); krb5_error_code +hdb_mitdb_create ( + krb5_context /*context*/, + HDB **/*db*/, + const char */*filename*/); + +krb5_error_code hdb_ndbm_create ( krb5_context /*context*/, HDB **/*db*/, @@ -286,6 +422,7 @@ krb5_error_code hdb_next_enctype2key ( krb5_context /*context*/, const hdb_entry */*e*/, + const Keys */*keyset*/, krb5_enctype /*enctype*/, Key **/*key*/); @@ -310,6 +447,19 @@ hdb_process_master_key ( krb5_enctype /*etype*/, hdb_master_key */*mkey*/); +/** + * This function prunes an HDB entry's keys that are too old to have been used + * to mint still valid tickets (based on the entry's maximum ticket lifetime). + * + * @param context Context + * @param entry HDB entry + */ + +krb5_error_code +hdb_prune_keys ( + krb5_context /*context*/, + hdb_entry */*entry*/); + krb5_error_code hdb_read_master_key ( krb5_context /*context*/, @@ -347,6 +497,13 @@ hdb_seal_keys_mkey ( hdb_master_key /*mkey*/); krb5_error_code +hdb_set_last_modified_by ( + krb5_context /*context*/, + hdb_entry */*entry*/, + krb5_principal /*modby*/, + time_t /*modtime*/); + +krb5_error_code hdb_set_master_key ( krb5_context /*context*/, HDB */*db*/, @@ -358,11 +515,21 @@ hdb_set_master_keyfile ( HDB */*db*/, const char */*keyfile*/); +/** + * Create SQLITE object, and creates the on disk database if its doesn't exists. + * + * @param context A Kerberos 5 context. + * @param db a returned database handle. + * @param filename filename + * + * @return 0 on success, an error code if not + */ + krb5_error_code hdb_sqlite_create ( krb5_context /*context*/, HDB **/*db*/, - const char */*argument*/); + const char */*filename*/); krb5_error_code hdb_unlock (int /*fd*/); @@ -386,6 +553,14 @@ hdb_unseal_keys ( hdb_entry */*ent*/); krb5_error_code +hdb_unseal_keys_kvno ( + krb5_context /*context*/, + HDB */*db*/, + krb5_kvno /*kvno*/, + unsigned /*flags*/, + hdb_entry */*ent*/); + +krb5_error_code hdb_unseal_keys_mkey ( krb5_context /*context*/, hdb_entry */*ent*/, @@ -413,4 +588,5 @@ hdb_write_master_key ( } #endif +#endif /* DOXY */ #endif /* __hdb_protos_h__ */ diff --git a/lib/hdb/hdb-sqlite.c b/lib/hdb/hdb-sqlite.c index e063588874ae..bc176b2bb87e 100644 --- a/lib/hdb/hdb-sqlite.c +++ b/lib/hdb/hdb-sqlite.c @@ -141,15 +141,115 @@ hdb_sqlite_prepare_stmt(krb5_context context, } if (ret != SQLITE_OK) { - krb5_set_error_message(context, EINVAL, + krb5_set_error_message(context, HDB_ERR_UK_RERROR, "Failed to prepare stmt %s: %s", str, sqlite3_errmsg(db)); - return EINVAL; + return HDB_ERR_UK_RERROR; } return 0; } +static krb5_error_code +prep_stmts(krb5_context context, hdb_sqlite_db *hsdb) +{ + int ret; + + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_version, + HDBSQLITE_GET_VERSION); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->fetch, + HDBSQLITE_FETCH); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_ids, + HDBSQLITE_GET_IDS); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_entry, + HDBSQLITE_ADD_ENTRY); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_principal, + HDBSQLITE_ADD_PRINCIPAL); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_alias, + HDBSQLITE_ADD_ALIAS); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->delete_aliases, + HDBSQLITE_DELETE_ALIASES); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->update_entry, + HDBSQLITE_UPDATE_ENTRY); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->remove, + HDBSQLITE_REMOVE); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_all_entries, + HDBSQLITE_GET_ALL_ENTRIES); + return ret; +} + +static void +finalize_stmts(krb5_context context, hdb_sqlite_db *hsdb) +{ + if (hsdb->get_version != NULL) + sqlite3_finalize(hsdb->get_version); + hsdb->get_version = NULL; + + if (hsdb->fetch != NULL) + sqlite3_finalize(hsdb->fetch); + hsdb->fetch = NULL; + + if (hsdb->get_ids != NULL) + sqlite3_finalize(hsdb->get_ids); + hsdb->get_ids = NULL; + + if (hsdb->add_entry != NULL) + sqlite3_finalize(hsdb->add_entry); + hsdb->add_entry = NULL; + + if (hsdb->add_principal != NULL) + sqlite3_finalize(hsdb->add_principal); + hsdb->add_principal = NULL; + + if (hsdb->add_alias != NULL) + sqlite3_finalize(hsdb->add_alias); + hsdb->add_alias = NULL; + + if (hsdb->delete_aliases != NULL) + sqlite3_finalize(hsdb->delete_aliases); + hsdb->delete_aliases = NULL; + + if (hsdb->update_entry != NULL) + sqlite3_finalize(hsdb->update_entry); + hsdb->update_entry = NULL; + + if (hsdb->remove != NULL) + sqlite3_finalize(hsdb->remove); + hsdb->remove = NULL; + + if (hsdb->get_all_entries != NULL) + sqlite3_finalize(hsdb->get_all_entries); + hsdb->get_all_entries = NULL; +} + /** * A wrapper around sqlite3_exec. * @@ -162,17 +262,23 @@ hdb_sqlite_prepare_stmt(krb5_context context, */ static krb5_error_code hdb_sqlite_exec_stmt(krb5_context context, - sqlite3 *database, + hdb_sqlite_db *hsdb, const char *statement, krb5_error_code error_code) { int ret; + int reinit_stmts = 0; + sqlite3 *database = hsdb->db; ret = sqlite3_exec(database, statement, NULL, NULL, NULL); while(((ret == SQLITE_BUSY) || (ret == SQLITE_IOERR_BLOCKED) || (ret == SQLITE_LOCKED))) { + if (reinit_stmts == 0 && ret == SQLITE_BUSY) { + finalize_stmts(context, hsdb); + reinit_stmts = 1; + } krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid()); sleep(1); ret = sqlite3_exec(database, statement, NULL, NULL, NULL); @@ -185,6 +291,28 @@ hdb_sqlite_exec_stmt(krb5_context context, return error_code; } + if (reinit_stmts) + return prep_stmts(context, hsdb); + + return 0; +} + +/** + * + */ + +static krb5_error_code +bind_principal(krb5_context context, krb5_const_principal principal, sqlite3_stmt *stmt, int key) +{ + krb5_error_code ret; + char *str = NULL; + + ret = krb5_unparse_name(context, principal, &str); + if (ret) + return ret; + + sqlite3_bind_text(stmt, key, str, -1, SQLITE_TRANSIENT); + free(str); return 0; } @@ -249,18 +377,15 @@ hdb_sqlite_close_database(krb5_context context, HDB *db) { hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; - sqlite3_finalize(hsdb->get_version); - sqlite3_finalize(hsdb->fetch); - sqlite3_finalize(hsdb->get_ids); - sqlite3_finalize(hsdb->add_entry); - sqlite3_finalize(hsdb->add_principal); - sqlite3_finalize(hsdb->add_alias); - sqlite3_finalize(hsdb->delete_aliases); - sqlite3_finalize(hsdb->update_entry); - sqlite3_finalize(hsdb->remove); - sqlite3_finalize(hsdb->get_all_entries); + finalize_stmts(context, hsdb); - sqlite3_close(hsdb->db); + /* XXX Use sqlite3_close_v2() when we upgrade SQLite3 */ + if (sqlite3_close(hsdb->db) != SQLITE_OK) { + krb5_set_error_message(context, HDB_ERR_UK_SERROR, + "SQLite BEGIN TRANSACTION failed: %s", + sqlite3_errmsg(hsdb->db)); + return HDB_ERR_UK_SERROR; + } return 0; } @@ -293,56 +418,18 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) created_file = 1; - ret = hdb_sqlite_exec_stmt(context, hsdb->db, + ret = hdb_sqlite_exec_stmt(context, hsdb, HDBSQLITE_CREATE_TABLES, - EINVAL); + HDB_ERR_UK_SERROR); if (ret) goto out; - ret = hdb_sqlite_exec_stmt(context, hsdb->db, + ret = hdb_sqlite_exec_stmt(context, hsdb, HDBSQLITE_CREATE_TRIGGERS, - EINVAL); + HDB_ERR_UK_SERROR); if (ret) goto out; } - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->get_version, - HDBSQLITE_GET_VERSION); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->fetch, - HDBSQLITE_FETCH); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->get_ids, - HDBSQLITE_GET_IDS); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->add_entry, - HDBSQLITE_ADD_ENTRY); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->add_principal, - HDBSQLITE_ADD_PRINCIPAL); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->add_alias, - HDBSQLITE_ADD_ALIAS); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->delete_aliases, - HDBSQLITE_DELETE_ALIASES); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->update_entry, - HDBSQLITE_UPDATE_ENTRY); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->remove, - HDBSQLITE_REMOVE); - if (ret) goto out; - ret = hdb_sqlite_prepare_stmt(context, hsdb->db, - &hsdb->get_all_entries, - HDBSQLITE_GET_ALL_ENTRIES); + ret = prep_stmts(context, hsdb); if (ret) goto out; ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version); @@ -353,7 +440,7 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) ret = 0; if(hsdb->version != HDBSQLITE_VERSION) { - ret = EINVAL; + ret = HDB_ERR_UK_SERROR; krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch"); } @@ -366,6 +453,8 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) sqlite3_close(hsdb->db); if (created_file) unlink(hsdb->db_file); + free(hsdb->db_file); + hsdb->db_file = NULL; return ret; } @@ -389,18 +478,30 @@ hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal princi { int sqlite_error; krb5_error_code ret; - char *principal_string; hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); sqlite3_stmt *fetch = hsdb->fetch; krb5_data value; - - ret = krb5_unparse_name(context, principal, &principal_string); - if (ret) { - free(principal_string); - return ret; + krb5_principal enterprise_principal = NULL; + + if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + if (principal->name.name_string.len != 1) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, "malformed principal: " + "enterprise name with %d name components", + principal->name.name_string.len); + return ret; + } + ret = krb5_parse_name(context, principal->name.name_string.val[0], + &enterprise_principal); + if (ret) + return ret; + principal = enterprise_principal; } - sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC); + ret = bind_principal(context, principal, fetch, 1); + krb5_free_principal(context, enterprise_principal); + if (ret) + return ret; sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); if (sqlite_error != SQLITE_ROW) { @@ -408,7 +509,7 @@ hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal princi ret = HDB_ERR_NOENTRY; goto out; } else { - ret = EINVAL; + ret = HDB_ERR_UK_RERROR; krb5_set_error_message(context, ret, "sqlite fetch failed: %d", sqlite_error); @@ -438,7 +539,6 @@ out: sqlite3_clear_bindings(fetch); sqlite3_reset(fetch); - free(principal_string); return ret; } @@ -484,30 +584,25 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, int ret; int i; sqlite_int64 entry_id; - char *principal_string = NULL; - char *alias_string; const HDB_Ext_Aliases *aliases; hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); krb5_data value; sqlite3_stmt *get_ids = hsdb->get_ids; - ret = hdb_sqlite_exec_stmt(context, hsdb->db, - "BEGIN IMMEDIATE TRANSACTION", EINVAL); + krb5_data_zero(&value); + + ret = hdb_sqlite_exec_stmt(context, hsdb, + "BEGIN IMMEDIATE TRANSACTION", + HDB_ERR_UK_SERROR); if(ret != SQLITE_OK) { - ret = EINVAL; + ret = HDB_ERR_UK_SERROR; krb5_set_error_message(context, ret, "SQLite BEGIN TRANSACTION failed: %s", sqlite3_errmsg(hsdb->db)); goto rollback; } - ret = krb5_unparse_name(context, - entry->entry.principal, &principal_string); - if (ret) { - goto rollback; - } - ret = hdb_seal_keys(context, db, &entry->entry); if(ret) { goto rollback; @@ -518,7 +613,10 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, goto rollback; } - sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC); + ret = bind_principal(context, entry->entry.principal, get_ids, 1); + if (ret) + goto rollback; + ret = hdb_sqlite_step(context, hsdb->db, get_ids); if(ret == SQLITE_DONE) { /* No such principal */ @@ -528,16 +626,38 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); sqlite3_clear_bindings(hsdb->add_entry); sqlite3_reset(hsdb->add_entry); - if(ret != SQLITE_DONE) + if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; goto rollback; + } + + ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1); + if (ret) + goto rollback; - sqlite3_bind_text(hsdb->add_principal, 1, - principal_string, -1, SQLITE_STATIC); ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); sqlite3_clear_bindings(hsdb->add_principal); sqlite3_reset(hsdb->add_principal); - if(ret != SQLITE_DONE) + if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; goto rollback; + } + + /* Now let's learn what Entry ID we got for the new principal */ + sqlite3_reset(get_ids); + ret = hdb_sqlite_step(context, hsdb->db, get_ids); + if (ret != SQLITE_ROW) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } entry_id = sqlite3_column_int64(get_ids, 1); @@ -550,18 +670,23 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); - if(ret != SQLITE_DONE) + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; goto rollback; + } sqlite3_bind_blob(hsdb->update_entry, 1, value.data, value.length, SQLITE_STATIC); sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); - if(ret != SQLITE_DONE) + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; goto rollback; + } } else { /* Error! */ + ret = HDB_ERR_UK_SERROR; goto rollback; } @@ -571,51 +696,47 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, for(i = 0; i < aliases->aliases.len; i++) { - ret = krb5_unparse_name(context, &aliases->aliases.val[i], - &alias_string); - if (ret) { - free(alias_string); + ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1); + if (ret) goto rollback; - } - sqlite3_bind_text(hsdb->add_alias, 1, alias_string, - -1, SQLITE_STATIC); sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); - - free(alias_string); - - if(ret != SQLITE_DONE) + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; + goto rollback; + } + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; goto rollback; + } } - ret = 0; - commit: - - free(principal_string); - krb5_data_free(&value); - sqlite3_clear_bindings(get_ids); sqlite3_reset(get_ids); - ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL); + if ((flags & HDB_F_PRECHECK)) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return 0; + } + + ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR); if(ret != SQLITE_OK) - krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s", - ret, sqlite3_errmsg(hsdb->db)); + krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s", + (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db)); - return ret; + return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR; rollback: - + krb5_data_free(&value); + sqlite3_clear_bindings(get_ids); + sqlite3_reset(get_ids); krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", ret, sqlite3_errmsg(hsdb->db)); - free(principal_string); - - ret = hdb_sqlite_exec_stmt(context, hsdb->db, - "ROLLBACK", EINVAL); + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); return ret; } @@ -666,12 +787,12 @@ hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode) static krb5_error_code hdb_sqlite_destroy(krb5_context context, HDB *db) { - int ret; + int ret, ret2; hdb_sqlite_db *hsdb; ret = hdb_clear_master_key(context, db); - hdb_sqlite_close_database(context, db); + ret2 = hdb_sqlite_close_database(context, db); hsdb = (hdb_sqlite_db*)(db->hdb_db); @@ -679,7 +800,7 @@ hdb_sqlite_destroy(krb5_context context, HDB *db) free(db->hdb_db); free(db); - return ret; + return ret ? ret : ret2; } /* @@ -731,8 +852,11 @@ hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, sqlite3_reset(hsdb->get_all_entries); } else { - /* XXX SQLite error. Should be handled in some way. */ - ret = EINVAL; + ret = HDB_ERR_UK_RERROR; + krb5_set_error_message(context, HDB_ERR_UK_RERROR, + "SELECT failed after returning one or " + "more rows: %s", sqlite3_errmsg(hsdb->db)); + } return ret; @@ -764,22 +888,22 @@ hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags, static krb5_error_code hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name) { + krb5_error_code ret, ret2; hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; - int ret; krb5_warnx(context, "hdb_sqlite_rename"); if (strncasecmp(new_name, "sqlite:", 7) == 0) new_name += 7; - hdb_sqlite_close_database(context, db); - - ret = rename(hsdb->db_file, new_name); - free(hsdb->db_file); + ret = hdb_sqlite_close_database(context, db); - hdb_sqlite_make_database(context, db, new_name); + if (rename(hsdb->db_file, new_name) == -1) + return errno; - return ret; + free(hsdb->db_file); + ret2 = hdb_sqlite_make_database(context, db, new_name); + return ret ? ret : ret2; } /* @@ -787,34 +911,62 @@ hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name) */ static krb5_error_code hdb_sqlite_remove(krb5_context context, HDB *db, - krb5_const_principal principal) + unsigned flags, krb5_const_principal principal) { krb5_error_code ret; - char *principal_string; hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); - sqlite3_stmt *remove = hsdb->remove; + sqlite3_stmt *get_ids = hsdb->get_ids; + sqlite3_stmt *rm = hsdb->remove; - ret = krb5_unparse_name(context, principal, &principal_string); - if (ret) { - free(principal_string); + bind_principal(context, principal, rm, 1); + + ret = hdb_sqlite_exec_stmt(context, hsdb, + "BEGIN IMMEDIATE TRANSACTION", + HDB_ERR_UK_SERROR); + if (ret != SQLITE_OK) { + ret = HDB_ERR_UK_SERROR; + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + krb5_set_error_message(context, ret, + "SQLite BEGIN TRANSACTION failed: %s", + sqlite3_errmsg(hsdb->db)); return ret; } - sqlite3_bind_text(remove, 1, principal_string, -1, SQLITE_STATIC); + if ((flags & HDB_F_PRECHECK)) { + ret = bind_principal(context, principal, get_ids, 1); + if (ret) + return ret; + + ret = hdb_sqlite_step(context, hsdb->db, get_ids); + sqlite3_clear_bindings(get_ids); + sqlite3_reset(get_ids); + if (ret == SQLITE_DONE) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return HDB_ERR_NOENTRY; + } + } - ret = hdb_sqlite_step(context, hsdb->db, remove); + ret = hdb_sqlite_step(context, hsdb->db, rm); + sqlite3_clear_bindings(rm); + sqlite3_reset(rm); if (ret != SQLITE_DONE) { - ret = EINVAL; - krb5_set_error_message(context, ret, - "sqlite remove failed: %d", - ret); - } else - ret = 0; + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, "sqlite remove failed: %d", ret); + return ret; + } - sqlite3_clear_bindings(remove); - sqlite3_reset(remove); + if ((flags & HDB_F_PRECHECK)) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return 0; + } - return ret; + ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR); + if (ret != SQLITE_OK) + krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s", + (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db)); + + return 0; } /** @@ -822,13 +974,13 @@ hdb_sqlite_remove(krb5_context context, HDB *db, * * @param context A Kerberos 5 context. * @param db a returned database handle. - * @param argument filename + * @param filename filename * * @return 0 on success, an error code if not */ krb5_error_code -hdb_sqlite_create(krb5_context context, HDB **db, const char *argument) +hdb_sqlite_create(krb5_context context, HDB **db, const char *filename) { krb5_error_code ret; hdb_sqlite_db *hsdb; @@ -837,8 +989,16 @@ hdb_sqlite_create(krb5_context context, HDB **db, const char *argument) if (*db == NULL) return krb5_enomem(context); + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + return krb5_enomem(context); + } + hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb)); if (hsdb == NULL) { + free((*db)->hdb_name); free(*db); *db = NULL; return krb5_enomem(context); @@ -847,7 +1007,7 @@ hdb_sqlite_create(krb5_context context, HDB **db, const char *argument) (*db)->hdb_db = hsdb; /* XXX make_database should make sure everything else is freed on error */ - ret = hdb_sqlite_make_database(context, *db, argument); + ret = hdb_sqlite_make_database(context, *db, filename); if (ret) { free((*db)->hdb_db); free(*db); diff --git a/lib/hdb/hdb.asn1 b/lib/hdb/hdb.asn1 index a72851c9f201..333ccb064196 100644 --- a/lib/hdb/hdb.asn1 +++ b/lib/hdb/hdb.asn1 @@ -46,8 +46,10 @@ HDBFlags ::= BIT STRING { trusted-for-delegation(14), -- Trusted to print forwardabled tickets allow-kerberos4(15), -- Allow Kerberos 4 requests allow-digest(16), -- Allow digest requests - locked-out(17) -- Account is locked out, + locked-out(17), -- Account is locked out, -- authentication will be denied + require-pwchange(18), -- require a passwd change + do-not-store(31) -- Not to be modified and stored in HDB } GENERATION ::= SEQUENCE { @@ -87,6 +89,17 @@ HDB-Ext-Aliases ::= SEQUENCE { aliases[1] SEQUENCE OF Principal -- all names, inc primary } +Keys ::= SEQUENCE OF Key + +hdb_keyset ::= SEQUENCE { + kvno[0] INTEGER (0..4294967295), + keys[1] Keys, + set-time[2] KerberosTime OPTIONAL, -- time this keyset was created/set + ... +} + +HDB-Ext-KeySet ::= SEQUENCE OF hdb_keyset + HDB-extension ::= SEQUENCE { mandatory[0] BOOLEAN, -- kdc MUST understand this extension, @@ -102,6 +115,11 @@ HDB-extension ::= SEQUENCE { aliases[6] HDB-Ext-Aliases, last-pw-change[7] KerberosTime, pkinit-cert[8] HDB-Ext-PKINIT-cert, + hist-keys[9] HDB-Ext-KeySet, + hist-kvno-diff-clnt[10] INTEGER (0..4294967295), + hist-kvno-diff-svc[11] INTEGER (0..4294967295), + policy[12] UTF8String, + principal-id[13] INTEGER(-9223372036854775808..9223372036854775807), ... }, ... @@ -109,16 +127,11 @@ HDB-extension ::= SEQUENCE { HDB-extensions ::= SEQUENCE OF HDB-extension -hdb_keyset ::= SEQUENCE { - kvno[1] INTEGER (0..4294967295), - keys[0] SEQUENCE OF Key -} - hdb_entry ::= SEQUENCE { principal[0] Principal OPTIONAL, -- this is optional only -- for compatibility with libkrb5 kvno[1] INTEGER (0..4294967295), - keys[2] SEQUENCE OF Key, + keys[2] Keys, created-by[3] Event, modified-by[4] Event OPTIONAL, valid-start[5] KerberosTime OPTIONAL, diff --git a/lib/hdb/hdb.c b/lib/hdb/hdb.c index ca05cc4a1785..1cb33df0885c 100644 --- a/lib/hdb/hdb.c +++ b/lib/hdb/hdb.c @@ -64,47 +64,97 @@ const int hdb_interface_version = HDB_INTERFACE_VERSION; static struct hdb_method methods[] = { -#if HAVE_DB1 || HAVE_DB3 - { HDB_INTERFACE_VERSION, "db:", hdb_db_create}, + /* "db:" should be db3 if we have db3, or db1 if we have db1 */ +#if HAVE_DB3 + { HDB_INTERFACE_VERSION, NULL, NULL, "db:", hdb_db3_create}, +#elif HAVE_DB1 + { HDB_INTERFACE_VERSION, NULL, NULL, "db:", hdb_db1_create}, #endif #if HAVE_DB1 - { HDB_INTERFACE_VERSION, "mit-db:", hdb_mdb_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "db1:", hdb_db1_create}, +#endif +#if HAVE_DB3 + { HDB_INTERFACE_VERSION, NULL, NULL, "db3:", hdb_db3_create}, +#endif +#if HAVE_DB1 + { HDB_INTERFACE_VERSION, NULL, NULL, "mit-db:", hdb_mitdb_create}, +#endif +#if HAVE_LMDB + { HDB_INTERFACE_VERSION, NULL, NULL, "mdb:", hdb_mdb_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "lmdb:", hdb_mdb_create}, #endif #if HAVE_NDBM - { HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "ndbm:", hdb_ndbm_create}, #endif - { HDB_INTERFACE_VERSION, "keytab:", hdb_keytab_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "keytab:", hdb_keytab_create}, #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE) - { HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create}, - { HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "ldap:", hdb_ldap_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "ldapi:", hdb_ldapi_create}, +#elif defined(OPENLDAP) + { HDB_INTERFACE_VERSION, NULL, NULL, "ldap:", NULL}, + { HDB_INTERFACE_VERSION, NULL, NULL, "ldapi:", NULL}, #endif #ifdef HAVE_SQLITE3 - { HDB_INTERFACE_VERSION, "sqlite:", hdb_sqlite_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, "sqlite:", hdb_sqlite_create}, #endif - {0, NULL, NULL} + { 0, NULL, NULL, NULL, NULL} }; -#if HAVE_DB1 || HAVE_DB3 -static struct hdb_method dbmetod = - { HDB_INTERFACE_VERSION, "", hdb_db_create }; +/* + * It'd be nice if we could try opening an HDB with each supported + * backend until one works or all fail. It may not be possible for all + * flavors, but where it's possible we should. + */ +#if defined(HAVE_LMDB) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, "", hdb_mdb_create }; +#elif defined(HAVE_DB3) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, "", hdb_db3_create }; +#elif defined(HAVE_DB1) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, "", hdb_db1_create }; #elif defined(HAVE_NDBM) -static struct hdb_method dbmetod = - { HDB_INTERFACE_VERSION, "", hdb_ndbm_create }; +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, "", hdb_ndbm_create }; #endif +const Keys * +hdb_kvno2keys(krb5_context context, + const hdb_entry *e, + krb5_kvno kvno) +{ + HDB_Ext_KeySet *hist_keys; + HDB_extension *extp; + size_t i; + + if (kvno == 0) + return &e->keys; + + extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys); + if (extp == NULL) + return 0; + + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == kvno) + return &hist_keys->val[i].keys; + } + + return NULL; +} krb5_error_code hdb_next_enctype2key(krb5_context context, const hdb_entry *e, + const Keys *keyset, krb5_enctype enctype, Key **key) { + const Keys *keys = keyset ? keyset : &e->keys; Key *k; - for (k = *key ? (*key) + 1 : e->keys.val; - k < e->keys.val + e->keys.len; - k++) - { + for (k = *key ? (*key) + 1 : keys->val; k < keys->val + keys->len; k++) { if(k->key.keytype == enctype){ *key = k; return 0; @@ -119,11 +169,12 @@ hdb_next_enctype2key(krb5_context context, krb5_error_code hdb_enctype2key(krb5_context context, hdb_entry *e, + const Keys *keyset, krb5_enctype enctype, Key **key) { *key = NULL; - return hdb_next_enctype2key(context, e, enctype, key); + return hdb_next_enctype2key(context, e, keyset, enctype, key); } void @@ -168,13 +219,14 @@ hdb_unlock(int fd) void hdb_free_entry(krb5_context context, hdb_entry_ex *ent) { + Key *k; size_t i; if (ent->free_entry) (*ent->free_entry)(context, ent); - for(i = 0; i < ent->entry.keys.len; ++i) { - Key *k = &ent->entry.keys.val[i]; + for(i = 0; i < ent->entry.keys.len; i++) { + k = &ent->entry.keys.val[i]; memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); } @@ -265,100 +317,6 @@ hdb_init_db(krb5_context context, HDB *db) return ret2; } -#ifdef HAVE_DLOPEN - - /* - * Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so, - * looking for the hdb_NAME_create symbol. - */ - -static const struct hdb_method * -find_dynamic_method (krb5_context context, - const char *filename, - const char **rest) -{ - static struct hdb_method method; - struct hdb_so_method *mso; - char *prefix, *path, *symbol; - const char *p; - void *dl; - size_t len; - - p = strchr(filename, ':'); - - /* if no prefix, don't know what module to load, just ignore it */ - if (p == NULL) - return NULL; - - len = p - filename; - *rest = filename + len + 1; - - prefix = malloc(len + 1); - if (prefix == NULL) - krb5_errx(context, 1, "out of memory"); - strlcpy(prefix, filename, len + 1); - - if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1) - krb5_errx(context, 1, "out of memory"); - -#ifndef RTLD_NOW -#define RTLD_NOW 0 -#endif -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif - - dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL); - if (dl == NULL) { - krb5_warnx(context, "error trying to load dynamic module %s: %s\n", - path, dlerror()); - free(prefix); - free(path); - return NULL; - } - - if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1) - krb5_errx(context, 1, "out of memory"); - - mso = (struct hdb_so_method *) dlsym(dl, symbol); - if (mso == NULL) { - krb5_warnx(context, "error finding symbol %s in %s: %s\n", - symbol, path, dlerror()); - dlclose(dl); - free(symbol); - free(prefix); - free(path); - return NULL; - } - free(path); - free(symbol); - - if (mso->version != HDB_INTERFACE_VERSION) { - krb5_warnx(context, - "error wrong version in shared module %s " - "version: %d should have been %d\n", - prefix, mso->version, HDB_INTERFACE_VERSION); - dlclose(dl); - free(prefix); - return NULL; - } - - if (mso->create == NULL) { - krb5_errx(context, 1, - "no entry point function in shared mod %s ", - prefix); - dlclose(dl); - free(prefix); - return NULL; - } - - method.create = mso->create; - method.prefix = prefix; - - return &method; -} -#endif /* HAVE_DLOPEN */ - /* * find the relevant method for `filename', returning a pointer to the * rest in `rest'. @@ -376,19 +334,62 @@ find_method (const char *filename, const char **rest) return h; } } -#if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_NDBM) - if (strncmp(filename, "/", 1) == 0 - || strncmp(filename, "./", 2) == 0 - || strncmp(filename, "../", 3) == 0) +#if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_LMDB) || defined(HAVE_NDBM) + if (strncmp(filename, "/", sizeof("/") - 1) == 0 + || strncmp(filename, "./", sizeof("./") - 1) == 0 + || strncmp(filename, "../", sizeof("../") - 1) == 0 +#ifdef WIN32 + || strncmp(filename, "\\\\", sizeof("\\\\") - 1) + || (isalpha(filename[0]) && filename[1] == ':') +#endif + ) { *rest = filename; - return &dbmetod; + return &default_dbmethod; } #endif return NULL; } +struct cb_s { + const char *residual; + const char *filename; + const struct hdb_method *h; +}; + +static krb5_error_code KRB5_LIB_CALL +callback(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const struct hdb_method *h = (const struct hdb_method *)plug; + struct cb_s *cb_ctx = (struct cb_s *)userctx; + + if (strncmp(cb_ctx->filename, h->prefix, strlen(h->prefix)) == 0) { + cb_ctx->residual = cb_ctx->filename + strlen(h->prefix) + 1; + cb_ctx->h = h; + return 0; + } + return KRB5_PLUGIN_NO_HANDLE; +} + +static char * +make_sym(const char *prefix) +{ + char *s, *sym; + + errno = 0; + if (prefix == NULL || prefix[0] == '\0') + return NULL; + if ((s = strdup(prefix)) == NULL) + return NULL; + if (strchr(s, ':') != NULL) + *strchr(s, ':') = '\0'; + if (asprintf(&sym, "hdb_%s_interface", s) == -1) + sym = NULL; + free(s); + return sym; +} + krb5_error_code hdb_list_builtin(krb5_context context, char **list) { @@ -405,12 +406,35 @@ hdb_list_builtin(krb5_context context, char **list) len += 1; buf = malloc(len); if (buf == NULL) { - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; + return krb5_enomem(context); } buf[0] = '\0'; for (h = methods; h->prefix != NULL; ++h) { + if (h->create == NULL) { + struct cb_s cb_ctx; + char *f; + char *sym; + + /* Try loading the plugin */ + if (asprintf(&f, "%sfoo", h->prefix) == -1) + f = NULL; + if ((sym = make_sym(h->prefix)) == NULL) { + free(buf); + free(f); + return krb5_enomem(context); + } + cb_ctx.filename = f; + cb_ctx.residual = NULL; + cb_ctx.h = NULL; + (void)_krb5_plugin_run_f(context, "krb5", sym, + HDB_INTERFACE_VERSION, 0, &cb_ctx, + callback); + free(f); + free(sym); + if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) + continue; + } if (h != methods) strlcat(buf, ", ", len); strlcat(buf, h->prefix, len); @@ -451,39 +475,25 @@ _hdb_keytab2hdb_entry(krb5_context context, krb5_error_code hdb_create(krb5_context context, HDB **db, const char *filename) { - const struct hdb_method *h; - const char *residual; - krb5_error_code ret; - struct krb5_plugin *list = NULL, *e; + struct cb_s cb_ctx; - if(filename == NULL) + if (filename == NULL) filename = HDB_DEFAULT_DB; - krb5_add_et_list(context, initialize_hdb_error_table_r); - h = find_method (filename, &residual); - - if (h == NULL) { - ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "hdb", &list); - if(ret == 0 && list != NULL) { - for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) { - h = _krb5_plugin_get_symbol(e); - if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0 - && h->interface_version == HDB_INTERFACE_VERSION) { - residual = filename + strlen(h->prefix); - break; - } - } - if (e == NULL) { - h = NULL; - _krb5_plugin_free(list); - } - } - } + cb_ctx.h = find_method (filename, &cb_ctx.residual); + cb_ctx.filename = filename; -#ifdef HAVE_DLOPEN - if (h == NULL) - h = find_dynamic_method (context, filename, &residual); -#endif - if (h == NULL) - krb5_errx(context, 1, "No database support for %s", filename); - return (*h->create)(context, db, residual); + if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) { + char *sym; + + if ((sym = make_sym(filename)) == NULL) + return krb5_enomem(context); + + (void)_krb5_plugin_run_f(context, "krb5", sym, HDB_INTERFACE_VERSION, + 0, &cb_ctx, callback); + + free(sym); + } + if (cb_ctx.h == NULL) + krb5_errx(context, 1, "No database support for %s", cb_ctx.filename); + return (*cb_ctx.h->create)(context, db, cb_ctx.residual); } diff --git a/lib/hdb/hdb.h b/lib/hdb/hdb.h index a1692ce82ca2..892b8e598581 100644 --- a/lib/hdb/hdb.h +++ b/lib/hdb/hdb.h @@ -36,6 +36,8 @@ #ifndef __HDB_H__ #define __HDB_H__ +#include <stdio.h> + #include <krb5.h> #include <hdb_err.h> @@ -58,15 +60,18 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; #define HDB_F_ADMIN_DATA 64 /* want data that kdc don't use */ #define HDB_F_KVNO_SPECIFIED 128 /* we want a particular KVNO */ #define HDB_F_CURRENT_KVNO 256 /* we want the current KVNO */ -/* 512, 1024, 2048 are reserved for kvno operations that is not part of the 1.5 branch */ +#define HDB_F_LIVE_CLNT_KVNOS 512 /* we want all live keys for pre-auth */ +#define HDB_F_LIVE_SVC_KVNOS 1024 /* we want all live keys for tix */ #define HDB_F_ALL_KVNOS 2048 /* we want all the keys, live or not */ #define HDB_F_FOR_AS_REQ 4096 /* fetch is for a AS REQ */ #define HDB_F_FOR_TGS_REQ 8192 /* fetch is for a TGS REQ */ +#define HDB_F_PRECHECK 16384 /* check that the operation would succeed */ /* hdb_capability_flags */ #define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1 #define HDB_CAP_F_HANDLE_PASSWORDS 2 #define HDB_CAP_F_PASSWORD_UPDATE_KEYS 4 +#define HDB_CAP_F_SHARED_DIRECTORY 8 /* auth status values */ #define HDB_AUTH_SUCCESS 0 @@ -99,7 +104,7 @@ typedef struct hdb_entry_ex { * query the backend database when talking about principals. */ -typedef struct HDB{ +typedef struct HDB { void *hdb_db; void *hdb_dbc; /** don't use, only for DB3 */ char *hdb_name; @@ -107,6 +112,8 @@ typedef struct HDB{ hdb_master_key hdb_master_key; int hdb_openp; int hdb_capability_flags; + int lock_count; + int lock_type; /** * Open (or create) the a Kerberos database. * @@ -149,7 +156,7 @@ typedef struct HDB{ * Remove an entry from the database. */ krb5_error_code (*hdb_remove)(krb5_context, struct HDB*, - krb5_const_principal); + unsigned, krb5_const_principal); /** * As part of iteration, fetch one entry */ @@ -181,25 +188,33 @@ typedef struct HDB{ /** * Get an hdb_entry from a classical DB backend * - * If the database is a classical DB (ie BDB, NDBM, GDBM, etc) - * backend, this function will take a principal key (krb5_data) - * and return all data related to principal in the return - * krb5_data. The returned encoded entry is of type hdb_entry or - * hdb_entry_alias. + * This function takes a principal key (krb5_data) and returns all + * data related to principal in the return krb5_data. The returned + * encoded entry is of type hdb_entry or hdb_entry_alias. */ krb5_error_code (*hdb__get)(krb5_context, struct HDB*, krb5_data, krb5_data*); /** * Store an hdb_entry from a classical DB backend * - * Same discussion as in @ref HDB::hdb__get + * This function takes a principal key (krb5_data) and encoded + * hdb_entry or hdb_entry_alias as the data to store. + * + * For a file-based DB, this must synchronize to disk when done. + * This is sub-optimal for kadm5_s_rename_principal(), and for + * kadm5_s_modify_principal() when using principal aliases; to + * improve this so that only one fsync() need be done + * per-transaction will require HDB API extensions. */ krb5_error_code (*hdb__put)(krb5_context, struct HDB*, int, krb5_data, krb5_data); /** * Delete and hdb_entry from a classical DB backend * - * Same discussion as in @ref HDB::hdb__get + * This function takes a principal key (krb5_data) naming the record + * to delete. + * + * Same discussion as in @ref HDB::hdb__put */ krb5_error_code (*hdb__del)(krb5_context, struct HDB*, krb5_data); /** @@ -258,23 +273,31 @@ typedef struct HDB{ krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal); }HDB; -#define HDB_INTERFACE_VERSION 7 +#define HDB_INTERFACE_VERSION 9 -struct hdb_so_method { - int version; +struct hdb_method { + int version; + krb5_error_code (*init)(krb5_context, void **); + void (*fini)(void *); const char *prefix; krb5_error_code (*create)(krb5_context, HDB **, const char *filename); }; +/* dump entry format, for hdb_print_entry() */ +typedef enum hdb_dump_format { + HDB_DUMP_HEIMDAL = 0, + HDB_DUMP_MIT = 1, +} hdb_dump_format_t; + +struct hdb_print_entry_arg { + FILE *out; + hdb_dump_format_t fmt; +}; + typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*, hdb_entry_ex*, void*); extern krb5_kt_ops hdb_kt_ops; - -struct hdb_method { - int interface_version; - const char *prefix; - krb5_error_code (*create)(krb5_context, HDB **, const char *filename); -}; +extern krb5_kt_ops hdb_get_kt_ops; extern const int hdb_interface_version; diff --git a/lib/hdb/hdb.schema b/lib/hdb/hdb.schema index 57303900dcee..f9fb08098ed9 100644 --- a/lib/hdb/hdb.schema +++ b/lib/hdb/hdb.schema @@ -113,6 +113,11 @@ attributetype ( 1.3.6.1.4.1.5322.10.1.12 EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} ) +attributetype ( 1.3.6.1.4.1.5322.10.1.13 + NAME 'krb5ExtendedAttributes' + DESC 'Encoded ASN1 HDB Extension Attributes as an octet string' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 ) + # Object class definitions objectclass ( 1.3.6.1.4.1.5322.10.2.1 @@ -129,7 +134,7 @@ objectclass ( 1.3.6.1.4.1.5322.10.2.2 MUST ( krb5KeyVersionNumber ) MAY ( krb5ValidStart $ krb5ValidEnd $ krb5PasswordEnd $ krb5MaxLife $ krb5MaxRenew $ krb5KDCFlags $ - krb5EncryptionType $ krb5Key ) ) + krb5EncryptionType $ krb5Key $ krb5ExtendedAttributes ) ) objectclass ( 1.3.6.1.4.1.5322.10.2.3 NAME 'krb5Realm' diff --git a/lib/hdb/hdb_err.et b/lib/hdb/hdb_err.et index 2cad4daba414..6a79ffa29c16 100644 --- a/lib/hdb/hdb_err.et +++ b/lib/hdb/hdb_err.et @@ -26,5 +26,8 @@ error_code NO_MKEY, "No correct master key" error_code MANDATORY_OPTION, "Entry contains unknown mandatory extension" error_code NO_WRITE_SUPPORT, "HDB backend doesn't contain write support" error_code NOT_FOUND_HERE, "The secret for this entry is not replicated to this database" +error_code MISUSE, "Incorrect use of the API" +error_code KVNO_NOT_FOUND, "Entry key version number not found" +error_code WRONG_REALM, "The principal exists in another realm." end diff --git a/lib/hdb/hdb_locl.h b/lib/hdb/hdb_locl.h index e896b5802575..fd7b1849daee 100644 --- a/lib/hdb/hdb_locl.h +++ b/lib/hdb/hdb_locl.h @@ -38,6 +38,9 @@ #include <config.h> +#include <assert.h> +#include <heimbase.h> + #include <stdio.h> #include <string.h> #include <stdlib.h> diff --git a/lib/hdb/keys.c b/lib/hdb/keys.c index 3d0b9d7c1b31..96c221ed275e 100644 --- a/lib/hdb/keys.c +++ b/lib/hdb/keys.c @@ -1,6 +1,5 @@ - /* - * Copyright (c) 1997 - 2001, 2003 - 2004 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2011 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,14 +33,29 @@ #include "hdb_locl.h" +struct hx509_certs_data; +struct krb5_pk_identity; +struct krb5_pk_cert; +struct ContentInfo; +struct AlgorithmIdentifier; +struct _krb5_krb_auth_data; +typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx; +struct krb5_dh_moduli; +struct _krb5_key_data; +struct _krb5_encryption_type; +struct _krb5_key_type; +#include <pkinit_asn1.h> +#include <krb5-private.h> +#include <base64.h> + /* * free all the memory used by (len, keys) */ void -hdb_free_keys (krb5_context context, int len, Key *keys) +hdb_free_keys(krb5_context context, int len, Key *keys) { - int i; + size_t i; for (i = 0; i < len; i++) { free(keys[i].mkvno); @@ -68,15 +82,15 @@ hdb_free_keys (krb5_context context, int len, Key *keys) */ static const krb5_enctype des_etypes[] = { - ETYPE_DES_CBC_MD5, - ETYPE_DES_CBC_MD4, - ETYPE_DES_CBC_CRC + KRB5_ENCTYPE_DES_CBC_MD5, + KRB5_ENCTYPE_DES_CBC_MD4, + KRB5_ENCTYPE_DES_CBC_CRC }; static const krb5_enctype all_etypes[] = { - ETYPE_AES256_CTS_HMAC_SHA1_96, - ETYPE_ARCFOUR_HMAC_MD5, - ETYPE_DES3_CBC_SHA1 + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + KRB5_ENCTYPE_DES3_CBC_SHA1, + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 }; static krb5_error_code @@ -114,7 +128,7 @@ parse_key_set(krb5_context context, const char *key, enctypes = des_etypes; num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]); } else if(strcmp(buf[i], "des3") == 0) { - e = ETYPE_DES3_CBC_SHA1; + e = KRB5_ENCTYPE_DES3_CBC_SHA1; enctypes = &e; num_enctypes = 1; } else { @@ -148,29 +162,30 @@ parse_key_set(krb5_context context, const char *key, continue; } - { - /* if there is a final string, use it as the string to - salt with, this is mostly useful with null salt for - v4 compat, and a cell name for afs compat */ - salt->saltvalue.data = strdup(buf[i]); - if (salt->saltvalue.data == NULL) { - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; - } - salt->saltvalue.length = strlen(buf[i]); - } + if (salt->saltvalue.data != NULL) + free(salt->saltvalue.data); + /* if there is a final string, use it as the string to + salt with, this is mostly useful with null salt for + v4 compat, and a cell name for afs compat */ + salt->saltvalue.data = strdup(buf[i]); + if (salt->saltvalue.data == NULL) + return krb5_enomem(context); + salt->saltvalue.length = strlen(buf[i]); } if(enctypes == NULL || salt->salttype == 0) { + krb5_free_salt(context, *salt); krb5_set_error_message(context, EINVAL, "bad value for default_keys `%s'", key); return EINVAL; } /* if no salt was specified make up default salt */ if(salt->saltvalue.data == NULL) { - if(salt->salttype == KRB5_PW_SALT) + if(salt->salttype == KRB5_PW_SALT) { ret = krb5_get_pw_salt(context, principal, salt); - else if(salt->salttype == KRB5_AFS3_SALT) { + if (ret) + return ret; + } else if(salt->salttype == KRB5_AFS3_SALT) { krb5_const_realm realm = krb5_principal_get_realm(context, principal); salt->saltvalue.data = strdup(realm); if(salt->saltvalue.data == NULL) { @@ -196,6 +211,256 @@ parse_key_set(krb5_context context, const char *key, return 0; } +/** + * This function prunes an HDB entry's keys that are too old to have been used + * to mint still valid tickets (based on the entry's maximum ticket lifetime). + * + * @param context Context + * @param entry HDB entry + */ +krb5_error_code +hdb_prune_keys(krb5_context context, hdb_entry *entry) +{ + HDB_extension *ext; + HDB_Ext_KeySet *keys; + size_t nelem; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (ext == NULL) + return 0; + keys = &ext->data.u.hist_keys; + nelem = keys->len; + + /* Optionally drop key history for keys older than now - max_life */ + if (entry->max_life != NULL && nelem > 0 + && krb5_config_get_bool_default(context, NULL, FALSE, + "kadmin", "prune-key-history", NULL)) { + hdb_keyset *elem; + time_t ceiling = time(NULL) - *entry->max_life; + time_t keep_time = 0; + size_t i; + + /* + * Compute most recent key timestamp that predates the current time + * by at least the entry's maximum ticket lifetime. + */ + for (i = 0; i < nelem; ++i) { + elem = &keys->val[i]; + if (elem->set_time && *elem->set_time < ceiling + && (keep_time == 0 || *elem->set_time > keep_time)) + keep_time = *elem->set_time; + } + + /* Drop obsolete entries */ + if (keep_time) { + for (i = 0; i < nelem; /* see below */) { + elem = &keys->val[i]; + if (elem->set_time && *elem->set_time < keep_time) { + remove_HDB_Ext_KeySet(keys, i); + /* + * Removing the i'th element shifts the tail down, continue + * at same index with reduced upper bound. + */ + --nelem; + continue; + } + ++i; + } + } + } + + return 0; +} + +/** + * This function adds an HDB entry's current keyset to the entry's key + * history. The current keyset is left alone; the caller is responsible + * for freeing it. + * + * @param context Context + * @param entry HDB entry + */ +krb5_error_code +hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry) +{ + krb5_boolean replace = FALSE; + krb5_error_code ret; + HDB_extension *ext; + HDB_Ext_KeySet *keys; + hdb_keyset newkeyset; + time_t newtime; + + if (entry->keys.len == 0) + return 0; /* nothing to do */ + + ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (ext == NULL) { + replace = TRUE; + ext = calloc(1, sizeof (*ext)); + if (ext == NULL) + return krb5_enomem(context); + + ext->data.element = choice_HDB_extension_data_hist_keys; + } + keys = &ext->data.u.hist_keys; + + ext->mandatory = FALSE; + + /* + * Copy in newest old keyset + */ + ret = hdb_entry_get_pw_change_time(entry, &newtime); + if (ret) + goto out; + + memset(&newkeyset, 0, sizeof(newkeyset)); + newkeyset.keys = entry->keys; + newkeyset.kvno = entry->kvno; + newkeyset.set_time = &newtime; + + ret = add_HDB_Ext_KeySet(keys, &newkeyset); + if (ret) + goto out; + + if (replace) { + /* hdb_replace_extension() deep-copies ext; what a waste */ + ret = hdb_replace_extension(context, entry, ext); + if (ret) + goto out; + } + + ret = hdb_prune_keys(context, entry); + if (ret) + goto out; + + out: + if (replace && ext) { + free_HDB_extension(ext); + free(ext); + } + return ret; +} + +/** + * This function adds a key to an HDB entry's key history. + * + * @param context Context + * @param entry HDB entry + * @param kvno Key version number of the key to add to the history + * @param key The Key to add + */ +krb5_error_code +hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key) +{ + size_t i; + hdb_keyset keyset; + HDB_Ext_KeySet *hist_keys; + HDB_extension ext; + HDB_extension *extp; + krb5_error_code ret; + + memset(&keyset, 0, sizeof (keyset)); + memset(&ext, 0, sizeof (ext)); + + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) { + ext.data.element = choice_HDB_extension_data_hist_keys; + extp = &ext; + } + + extp->mandatory = FALSE; + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == kvno) { + ret = add_Keys(&hist_keys->val[i].keys, key); + goto out; + } + } + + keyset.kvno = kvno; + ret = add_Keys(&keyset.keys, key); + if (ret) + goto out; + ret = add_HDB_Ext_KeySet(hist_keys, &keyset); + if (ret) + goto out; + if (extp == &ext) { + ret = hdb_replace_extension(context, entry, &ext); + if (ret) + goto out; + } + +out: + free_hdb_keyset(&keyset); + free_HDB_extension(&ext); + return ret; +} + + +/** + * This function changes an hdb_entry's kvno, swapping the current key + * set with a historical keyset. If no historical keys are found then + * an error is returned (the caller can still set entry->kvno directly). + * + * @param context krb5_context + * @param new_kvno New kvno for the entry + * @param entry hdb_entry to modify + */ +krb5_error_code +hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry) +{ + HDB_extension ext; + HDB_extension *extp; + hdb_keyset keyset; + HDB_Ext_KeySet *hist_keys; + size_t i; + int found = 0; + krb5_error_code ret; + + if (entry->kvno == new_kvno) + return 0; + + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) { + memset(&ext, 0, sizeof (ext)); + ext.data.element = choice_HDB_extension_data_hist_keys; + extp = &ext; + } + + memset(&keyset, 0, sizeof (keyset)); + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == new_kvno) { + found = 1; + ret = copy_hdb_keyset(&hist_keys->val[i], &keyset); + if (ret) + goto out; + ret = remove_HDB_Ext_KeySet(hist_keys, i); + if (ret) + goto out; + break; + } + } + + if (!found) + return HDB_ERR_KVNO_NOT_FOUND; + + ret = hdb_add_current_keys_to_history(context, entry); + if (ret) + goto out; + + /* Note: we do nothing with keyset.set_time */ + entry->kvno = new_kvno; + entry->keys = keyset.keys; /* shortcut */ + memset(&keyset.keys, 0, sizeof (keyset.keys)); + +out: + free_hdb_keyset(&keyset); + return ret; +} + + static krb5_error_code add_enctype_to_key_set(Key **key_set, size_t *nkeyset, krb5_enctype enctype, krb5_salt *salt) @@ -243,6 +508,122 @@ add_enctype_to_key_set(Key **key_set, size_t *nkeyset, } +static +krb5_error_code +ks_tuple2str(krb5_context context, int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, char ***ks_tuple_strs) +{ + size_t i; + char **ksnames; + krb5_error_code rc = KRB5_PROG_ETYPE_NOSUPP; + + *ks_tuple_strs = NULL; + if (n_ks_tuple < 1) + return 0; + + if ((ksnames = calloc(n_ks_tuple + 1, sizeof (*ksnames))) == NULL) + return (errno); + + for (i = 0; i < n_ks_tuple; i++) { + char *ename, *sname; + + if (krb5_enctype_to_string(context, ks_tuple[i].ks_enctype, &ename)) + goto out; + if (krb5_salttype_to_string(context, ks_tuple[i].ks_enctype, + ks_tuple[i].ks_salttype, &sname)) { + free(ename); + goto out; + } + + if (asprintf(&ksnames[i], "%s:%s", ename, sname) == -1) { + rc = errno; + free(ename); + free(sname); + goto out; + } + free(ename); + free(sname); + } + + ksnames[i] = NULL; + *ks_tuple_strs = ksnames; + return 0; + +out: + for (i = 0; i < n_ks_tuple; i++) + free(ksnames[i]); + free(ksnames); + return (rc); +} + +/* + * + */ + +static char ** +glob_rules_keys(krb5_context context, krb5_const_principal principal) +{ + const krb5_config_binding *list; + krb5_principal pattern; + krb5_error_code ret; + + list = krb5_config_get_list(context, NULL, "kadmin", + "default_key_rules", NULL); + if (list == NULL) + return NULL; + + while (list) { + if (list->type == krb5_config_string) { + ret = krb5_parse_name(context, list->name, &pattern); + if (ret == 0) { + ret = krb5_principal_match(context, principal, pattern); + krb5_free_principal(context, pattern); + if (ret) { + return krb5_config_get_strings(context, list, + list->name, NULL); + } + } + } + list = list->next; + } + return NULL; +} + +/* + * NIST guidance in Section 5.1 of [SP800-132] requires that a portion + * of the salt of at least 128 bits shall be randomly generated. + */ +static krb5_error_code +add_random_to_salt(krb5_context context, krb5_salt *in, krb5_salt *out) +{ + krb5_error_code ret; + char *p; + unsigned char random[16]; + char *s; + int slen; + + krb5_generate_random_block(random, sizeof(random)); + + slen = rk_base64_encode(random, sizeof(random), &s); + if (slen < 0) + return ENOMEM; + + ret = krb5_data_alloc(&out->saltvalue, slen + in->saltvalue.length); + if (ret) { + free(s); + return ret; + } + + p = out->saltvalue.data; + memcpy(p, s, slen); + memcpy(&p[slen], in->saltvalue.data, in->saltvalue.length); + + out->salttype = in->salttype; + free(s); + + return 0; +} + /* * Generate the `key_set' from the [kadmin]default_keys statement. If * `no_salt' is set, salt is not important (and will not be set) since @@ -251,12 +632,16 @@ add_enctype_to_key_set(Key **key_set, size_t *nkeyset, krb5_error_code hdb_generate_key_set(krb5_context context, krb5_principal principal, + krb5_key_salt_tuple *ks_tuple, int n_ks_tuple, Key **ret_key_set, size_t *nkeyset, int no_salt) { - char **ktypes, **kp; + char **ktypes = NULL; + char **kp; krb5_error_code ret; Key *k, *key_set; size_t i, j; + char **ks_tuple_strs; + char **config_ktypes = NULL; static const char *default_keytypes[] = { "aes256-cts-hmac-sha1-96:pw-salt", "des3-cbc-sha1:pw-salt", @@ -264,16 +649,24 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, NULL }; - ktypes = krb5_config_get_strings(context, NULL, "kadmin", - "default_keys", NULL); + if ((ret = ks_tuple2str(context, n_ks_tuple, ks_tuple, &ks_tuple_strs))) + return ret; + + ktypes = ks_tuple_strs; + if (ktypes == NULL) { + ktypes = glob_rules_keys(context, principal); + } + if (ktypes == NULL) { + config_ktypes = krb5_config_get_strings(context, NULL, "kadmin", + "default_keys", NULL); + ktypes = config_ktypes; + } if (ktypes == NULL) ktypes = (char **)(intptr_t)default_keytypes; *ret_key_set = key_set = NULL; *nkeyset = 0; - ret = 0; - for(kp = ktypes; kp && *kp; kp++) { const char *p; krb5_salt salt; @@ -298,10 +691,14 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, if (ret) { krb5_warn(context, ret, "bad value for default_keys `%s'", *kp); ret = 0; + krb5_free_salt(context, salt); continue; } for (i = 0; i < num_enctypes; i++) { + krb5_salt *saltp = no_salt ? NULL : &salt; + krb5_salt rsalt; + /* find duplicates */ for (j = 0; j < *nkeyset; j++) { @@ -320,14 +717,27 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, } } /* not a duplicate, lets add it */ - if (j == *nkeyset) { + if (j < *nkeyset) + continue; + + memset(&rsalt, 0, sizeof(rsalt)); + + /* prepend salt with randomness if required */ + if (!no_salt && + _krb5_enctype_requires_random_salt(context, enctypes[i])) { + saltp = &rsalt; + ret = add_random_to_salt(context, &salt, &rsalt); + } + + if (ret == 0) ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], - no_salt ? NULL : &salt); - if (ret) { - free(enctypes); - krb5_free_salt(context, salt); - goto out; - } + saltp); + krb5_free_salt(context, rsalt); + + if (ret) { + free(enctypes); + krb5_free_salt(context, salt); + goto out; } } free(enctypes); @@ -337,8 +747,12 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, *ret_key_set = key_set; out: - if (ktypes != (char **)(intptr_t)default_keytypes) - krb5_config_free_strings(ktypes); + if (config_ktypes != NULL) + krb5_config_free_strings(config_ktypes); + + for(kp = ks_tuple_strs; kp && *kp; kp++) + free(*kp); + free(ks_tuple_strs); if (ret) { krb5_warn(context, ret, @@ -358,32 +772,34 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, krb5_error_code -hdb_generate_key_set_password(krb5_context context, - krb5_principal principal, - const char *password, - Key **keys, size_t *num_keys) +hdb_generate_key_set_password_with_ks_tuple(krb5_context context, + krb5_principal principal, + const char *password, + krb5_key_salt_tuple *ks_tuple, + int n_ks_tuple, + Key **keys, size_t *num_keys) { krb5_error_code ret; size_t i; - ret = hdb_generate_key_set(context, principal, + ret = hdb_generate_key_set(context, principal, ks_tuple, n_ks_tuple, keys, num_keys, 0); if (ret) return ret; for (i = 0; i < (*num_keys); i++) { krb5_salt salt; + Key *key = &(*keys)[i]; - salt.salttype = (*keys)[i].salt->type; - salt.saltvalue.length = (*keys)[i].salt->salt.length; - salt.saltvalue.data = (*keys)[i].salt->salt.data; + salt.salttype = key->salt->type; + salt.saltvalue.length = key->salt->salt.length; + salt.saltvalue.data = key->salt->salt.data; ret = krb5_string_to_key_salt (context, - (*keys)[i].key.keytype, + key->key.keytype, password, salt, - &(*keys)[i].key); - + &key->key); if(ret) break; } @@ -394,3 +810,16 @@ hdb_generate_key_set_password(krb5_context context, } return ret; } + + +krb5_error_code +hdb_generate_key_set_password(krb5_context context, + krb5_principal principal, + const char *password, + Key **keys, size_t *num_keys) +{ + + return hdb_generate_key_set_password_with_ks_tuple(context, principal, + password, NULL, 0, + keys, num_keys); +} diff --git a/lib/hdb/keytab.c b/lib/hdb/keytab.c index c72b797dab4d..966c12f89fb0 100644 --- a/lib/hdb/keytab.c +++ b/lib/hdb/keytab.c @@ -65,7 +65,7 @@ hdb_resolve(krb5_context context, const char *name, krb5_keytab id) } db = name; mkey = strstr(name, ":mkey="); - if(mkey == NULL || mkey[5] == '\0') { + if(mkey == NULL || mkey[6] == '\0') { if(*name == '\0') d->dbname = NULL; else { @@ -87,7 +87,7 @@ hdb_resolve(krb5_context context, const char *name, krb5_keytab id) memmove(d->dbname, db, mkey - db); d->dbname[mkey - db] = '\0'; - d->mkey = strdup(mkey + 5); + d->mkey = strdup(mkey + 6); if(d->mkey == NULL) { free(d->dbname); free(d); @@ -420,5 +420,23 @@ krb5_kt_ops hdb_kt_ops = { hdb_next_entry, hdb_end_seq_get, NULL, /* add */ - NULL /* remove */ + NULL, /* remove */ + NULL, + 0 +}; + +krb5_kt_ops hdb_get_kt_ops = { + "HDBGET", + hdb_resolve, + hdb_get_name, + hdb_close, + NULL, + hdb_get_entry, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 }; diff --git a/lib/hdb/libhdb-exports.def b/lib/hdb/libhdb-exports.def index 4a93f7f92ada..67c0e33e0357 100644 --- a/lib/hdb/libhdb-exports.def +++ b/lib/hdb/libhdb-exports.def @@ -1,6 +1,8 @@ EXPORTS encode_hdb_keyset hdb_add_master_key + hdb_add_current_keys_to_history + hdb_change_kvno hdb_check_db_format hdb_clear_extension hdb_clear_master_key @@ -39,22 +41,26 @@ EXPORTS hdb_free_master_key hdb_generate_key_set hdb_generate_key_set_password + hdb_generate_key_set_password_with_ks_tuple hdb_get_dbinfo hdb_init_db hdb_interface_version DATA hdb_key2principal + hdb_kvno2keys hdb_list_builtin hdb_lock hdb_next_enctype2key hdb_principal2key hdb_print_entry hdb_process_master_key + hdb_prune_keys hdb_read_master_key hdb_replace_extension hdb_seal_key hdb_seal_key_mkey hdb_seal_keys hdb_seal_keys_mkey + hdb_set_last_modified_by hdb_set_master_key hdb_set_master_keyfile hdb_unlock @@ -69,6 +75,11 @@ EXPORTS initialize_hdb_error_table_r hdb_kt_ops + hdb_get_kt_ops + +; MIT KDB related entries + _hdb_mdb_value2entry + _hdb_mit_dump2mitdb_entry ; some random bits needed for libkadm HDBFlags2int @@ -76,25 +87,34 @@ EXPORTS copy_Event copy_HDB_extensions copy_Key + copy_Keys copy_Salt decode_HDB_Ext_Aliases decode_HDB_Ext_PKINIT_acl decode_HDB_extension decode_Key + decode_Keys encode_HDB_Ext_Aliases encode_HDB_Ext_PKINIT_acl encode_HDB_extension encode_Key + encode_Keys free_Event free_HDB_Ext_Aliases free_HDB_Ext_PKINIT_acl free_HDB_extension free_HDB_extensions free_Key + free_Keys free_Salt free_hdb_entry + free_hdb_keyset int2HDBFlags length_HDB_Ext_Aliases length_HDB_Ext_PKINIT_acl length_HDB_extension length_Key + length_Keys + add_Keys + add_HDB_Ext_KeySet + remove_Keys diff --git a/lib/hdb/mkey.c b/lib/hdb/mkey.c index 9eb98fca32c0..8265776bf7c8 100644 --- a/lib/hdb/mkey.c +++ b/lib/hdb/mkey.c @@ -40,6 +40,7 @@ struct hdb_master_key_data { krb5_keytab_entry keytab; krb5_crypto crypto; struct hdb_master_key_data *next; + unsigned int key_usage; }; void @@ -68,6 +69,7 @@ hdb_process_master_key(krb5_context context, krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + (*mkey)->key_usage = HDB_KU_MKEY; (*mkey)->keytab.vno = kvno; ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); if(ret) @@ -117,6 +119,7 @@ read_master_keytab(krb5_context context, const char *filename, krb5_keytab_entry entry; hdb_master_key p; + *mkey = NULL; ret = krb5_kt_resolve(context, filename, &id); if(ret) return ret; @@ -124,22 +127,26 @@ read_master_keytab(krb5_context context, const char *filename, ret = krb5_kt_start_seq_get(context, id, &cursor); if(ret) goto out; - *mkey = NULL; while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { p = calloc(1, sizeof(*p)); - if(p == NULL) { - krb5_kt_end_seq_get(context, id, &cursor); + if (p == NULL) { ret = ENOMEM; - goto out; + break; } p->keytab = entry; - ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); p->next = *mkey; *mkey = p; + ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); + if (ret) + break; } krb5_kt_end_seq_get(context, id, &cursor); out: krb5_kt_close(context, id); + if (ret) { + hdb_free_master_key(context, *mkey); + *mkey = NULL; + } return ret; } @@ -362,8 +369,17 @@ hdb_write_master_key(krb5_context context, const char *filename, return ret; } +krb5_error_code +_hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage) +{ + if (db->hdb_master_key_set == 0) + return HDB_ERR_NO_MKEY; + db->hdb_master_key->key_usage = key_usage; + return 0; +} + hdb_master_key -_hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey) +_hdb_find_master_key(unsigned int *mkvno, hdb_master_key mkey) { hdb_master_key ret = NULL; while(mkey) { @@ -479,6 +495,135 @@ hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); } +/* + * Unseal the keys for the given kvno (or all of them) of entry. + * + * If kvno == 0 -> unseal all. + * if kvno != 0 -> unseal the requested kvno and make sure it's the one listed + * as the current keyset for the entry (swapping it with a + * historical keyset if need be). + */ +krb5_error_code +hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, + unsigned flags, hdb_entry *ent) +{ + krb5_error_code ret = HDB_ERR_NOENTRY; + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys; + Key *tmp_val; + time_t tmp_set_time; + unsigned int tmp_len; + unsigned int kvno_diff = 0; + krb5_kvno tmp_kvno; + size_t i, k; + int exclude_dead = 0; + KerberosTime now = 0; + + if (kvno == 0) + ret = 0; + + if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) { + exclude_dead = 1; + now = time(NULL); + if (HDB_F_LIVE_CLNT_KVNOS) + kvno_diff = hdb_entry_get_kvno_diff_clnt(ent); + else + kvno_diff = hdb_entry_get_kvno_diff_svc(ent); + } + + ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (ext == NULL || (&ext->data.u.hist_keys)->len == 0) + return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); + + /* For swapping; see below */ + tmp_len = ent->keys.len; + tmp_val = ent->keys.val; + tmp_kvno = ent->kvno; + (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time); + + hist_keys = &ext->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + if (kvno != 0 && hist_keys->val[i].kvno != kvno) + continue; + + if (exclude_dead && + ((ent->max_life != NULL && + hist_keys->val[i].set_time != NULL && + (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) || + (hist_keys->val[i].kvno < kvno && + (kvno - hist_keys->val[i].kvno) > kvno_diff))) + /* + * The KDC may want to to check for this keyset's set_time + * is within the TGS principal's max_life, say. But we stop + * here. + */ + continue; + + /* Either the keys we want, or all the keys */ + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + ret = hdb_unseal_key_mkey(context, + &hist_keys->val[i].keys.val[k], + db->hdb_master_key); + /* + * If kvno == 0 we might not want to bail here! E.g., if we + * no longer have the right master key, so just ignore this. + * + * We could filter out keys that we can't decrypt here + * because of HDB_ERR_NO_MKEY. However, it seems safest to + * filter them out only where necessary, say, in kadm5. + */ + if (ret && kvno != 0) + return ret; + if (ret && ret != HDB_ERR_NO_MKEY) + return (ret); + } + + if (kvno == 0) + continue; + + /* + * What follows is a bit of a hack. + * + * This is the keyset we're being asked for, but it's not the + * current keyset. So we add the current keyset to the history, + * leave the one we were asked for in the history, and pretend + * the one we were asked for is also the current keyset. + * + * This is a bit of a defensive hack in case an entry fetched + * this way ever gets modified then stored: if the keyset is not + * changed we can detect this and put things back, else we won't + * drop any keysets from history by accident. + * + * Note too that we only ever get called with a non-zero kvno + * either in the KDC or in cases where we aren't changing the + * HDB entry anyways, which is why this is just a defensive + * hack. We also don't fetch specific kvnos in the dump case, + * so there's no danger that we'll dump this entry and load it + * again, repeatedly causing the history to grow boundelessly. + */ + + /* Swap key sets */ + ent->kvno = hist_keys->val[i].kvno; + ent->keys.val = hist_keys->val[i].keys.val; + ent->keys.len = hist_keys->val[i].keys.len; + if (hist_keys->val[i].set_time != NULL) + /* Sloppy, but the callers we expect won't care */ + (void) hdb_entry_set_pw_change_time(context, ent, + *hist_keys->val[i].set_time); + hist_keys->val[i].kvno = tmp_kvno; + hist_keys->val[i].keys.val = tmp_val; + hist_keys->val[i].keys.len = tmp_len; + if (hist_keys->val[i].set_time != NULL) + /* Sloppy, but the callers we expect won't care */ + *hist_keys->val[i].set_time = tmp_set_time; + + return 0; + } + + return (ret); +} + krb5_error_code hdb_unseal_key(krb5_context context, HDB *db, Key *k) { @@ -526,14 +671,31 @@ hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) krb5_error_code hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) { - size_t i; - for(i = 0; i < ent->keys.len; i++){ - krb5_error_code ret; + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys; + size_t i, k; + krb5_error_code ret; + for(i = 0; i < ent->keys.len; i++){ ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); if (ret) return ret; } + + ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (ext == NULL) + return 0; + hist_keys = &ext->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k], + mkey); + if (ret) + return ret; + } + } + return 0; } @@ -556,9 +718,9 @@ hdb_seal_key(krb5_context context, HDB *db, Key *k) } krb5_error_code -hdb_set_master_key (krb5_context context, - HDB *db, - krb5_keyblock *key) +hdb_set_master_key(krb5_context context, + HDB *db, + krb5_keyblock *key) { krb5_error_code ret; hdb_master_key mkey; @@ -571,6 +733,7 @@ hdb_set_master_key (krb5_context context, des_set_random_generator_seed(key.keyvalue.data); #endif db->hdb_master_key_set = 1; + db->hdb_master_key->key_usage = HDB_KU_MKEY; return 0; } diff --git a/lib/hdb/print.c b/lib/hdb/print.c index 697d32d2909c..0d1e2855217d 100644 --- a/lib/hdb/print.c +++ b/lib/hdb/print.c @@ -57,44 +57,57 @@ generation number */ -static krb5_error_code +/* + * These utility functions return the number of bytes written or -1, and + * they set an error in the context. + */ +static ssize_t append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...) { - krb5_error_code ret; + ssize_t sz; char *s; + int rc; va_list ap; va_start(ap, fmt); - vasprintf(&s, fmt, ap); + rc = vasprintf(&s, fmt, ap); va_end(ap); - if(s == NULL) { + if(rc < 0) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; + return -1; } - ret = krb5_storage_write(sp, s, strlen(s)); + sz = krb5_storage_write(sp, s, strlen(s)); free(s); - return ret; + return sz; } static krb5_error_code -append_hex(krb5_context context, krb5_storage *sp, krb5_data *data) +append_hex(krb5_context context, krb5_storage *sp, + int always_encode, int lower, krb5_data *data) { + ssize_t sz; int printable = 1; size_t i; char *p; p = data->data; - for(i = 0; i < data->length; i++) - if(!isalnum((unsigned char)p[i]) && p[i] != '.'){ - printable = 0; - break; - } - if(printable) + if (!always_encode) { + for (i = 0; i < data->length; i++) { + if (!isalnum((unsigned char)p[i]) && p[i] != '.'){ + printable = 0; + break; + } + } + } + if (printable && !always_encode) return append_string(context, sp, "\"%.*s\"", data->length, data->data); - hex_encode(data->data, data->length, &p); - append_string(context, sp, "%s", p); + sz = hex_encode(data->data, data->length, &p); + if (sz == -1) return sz; + if (lower) + strlwr(p); + sz = append_string(context, sp, "%s", p); free(p); - return 0; + return sz; } static char * @@ -105,22 +118,99 @@ time2str(time_t t) return buf; } -static krb5_error_code +static ssize_t append_event(krb5_context context, krb5_storage *sp, Event *ev) { - char *pr = NULL; krb5_error_code ret; + ssize_t sz; + char *pr = NULL; if(ev == NULL) return append_string(context, sp, "- "); if (ev->principal != NULL) { ret = krb5_unparse_name(context, ev->principal, &pr); - if(ret) - return ret; + if (ret) return -1; /* krb5_unparse_name() sets error info */ } - ret = append_string(context, sp, "%s:%s ", - time2str(ev->time), pr ? pr : "UNKNOWN"); + sz = append_string(context, sp, "%s:%s ", time2str(ev->time), + pr ? pr : "UNKNOWN"); free(pr); - return ret; + return sz; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +static ssize_t +append_mit_key(krb5_context context, krb5_storage *sp, + krb5_const_principal princ, + unsigned int kvno, Key *key) +{ + krb5_error_code ret; + krb5_salt k5salt; + ssize_t sz; + size_t key_versions = key->salt ? 2 : 1; + size_t decrypted_key_length; + char buf[2]; + krb5_data keylenbytes; + unsigned int salttype; + + sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno, + key->key.keytype, key->key.keyvalue.length + 2); + if (sz == -1) return sz; + ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length); + if (ret) return -1; /* XXX we lose the error code */ + buf[0] = decrypted_key_length & 0xff; + buf[1] = (decrypted_key_length & 0xff00) >> 8; + keylenbytes.data = buf; + keylenbytes.length = sizeof (buf); + sz = append_hex(context, sp, 1, 1, &keylenbytes); + if (sz == -1) return sz; + sz = append_hex(context, sp, 1, 1, &key->key.keyvalue); + if (!key->salt) + return sz; + + /* Map salt to MIT KDB style */ + switch (key->salt->type) { + case KRB5_PADATA_PW_SALT: + + /* + * Compute normal salt and then see whether it matches the stored one + */ + ret = krb5_get_pw_salt(context, princ, &k5salt); + if (ret) return -1; + if (k5salt.saltvalue.length == key->salt->salt.length && + memcmp(k5salt.saltvalue.data, key->salt->salt.data, + k5salt.saltvalue.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */ + else if (key->salt->salt.length == strlen(princ->realm) && + memcmp(key->salt->salt.data, princ->realm, + key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */ + else if (key->salt->salt.length == + k5salt.saltvalue.length - strlen(princ->realm) && + memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm), + key->salt->salt.data, key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */ + else + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* hope for best */ + + break; + + case KRB5_PADATA_AFS3_SALT: + salttype = KRB5_KDB_SALTTYPE_AFS3; + break; + + default: + return -1; + } + + sz = append_string(context, sp, "\t%u\t%u\t", salttype, + key->salt->salt.length); + if (sz == -1) return sz; + return append_hex(context, sp, 1, 1, &key->salt->salt); } static krb5_error_code @@ -149,12 +239,12 @@ entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) append_string(context, sp, "::%d:", ent->keys.val[i].key.keytype); /* --- keydata */ - append_hex(context, sp, &ent->keys.val[i].key.keyvalue); + append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue); append_string(context, sp, ":"); /* --- salt */ if(ent->keys.val[i].salt){ append_string(context, sp, "%u/", ent->keys.val[i].salt->type); - append_hex(context, sp, &ent->keys.val[i].salt->salt); + append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt); }else append_string(context, sp, "-"); } @@ -234,25 +324,224 @@ entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) } else append_string(context, sp, "-"); + return 0; +} + +#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 +#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 +#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 +#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 +#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 +#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 +#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 +#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 +#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 +#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 +#define KRB5_KDB_DISALLOW_SVR 0x00001000 +#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 +#define KRB5_KDB_SUPPORT_DESMD5 0x00004000 +#define KRB5_KDB_NEW_PRINC 0x00008000 + +static int +flags_to_attr(HDBFlags flags) +{ + int a = 0; + + if (!flags.postdate) + a |= KRB5_KDB_DISALLOW_POSTDATED; + if (!flags.forwardable) + a |= KRB5_KDB_DISALLOW_FORWARDABLE; + if (flags.initial) + a |= KRB5_KDB_DISALLOW_TGT_BASED; + if (!flags.renewable) + a |= KRB5_KDB_DISALLOW_RENEWABLE; + if (!flags.proxiable) + a |= KRB5_KDB_DISALLOW_PROXIABLE; + if (flags.invalid) + a |= KRB5_KDB_DISALLOW_ALL_TIX; + if (flags.require_preauth) + a |= KRB5_KDB_REQUIRES_PRE_AUTH; + if (flags.require_hwauth) + a |= KRB5_KDB_REQUIRES_HW_AUTH; + if (!flags.server) + a |= KRB5_KDB_DISALLOW_SVR; + if (flags.change_pw) + a |= KRB5_KDB_PWCHANGE_SERVICE; + return a; +} + +krb5_error_code +entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) +{ + krb5_error_code ret; + ssize_t sz; + size_t i, k; + size_t num_tl_data = 0; + size_t num_key_data = 0; + char *p; + HDB_Ext_KeySet *hist_keys = NULL; + HDB_extension *extp; + time_t last_pw_chg = 0; + time_t exp = 0; + time_t pwexp = 0; + unsigned int max_life = 0; + unsigned int max_renew = 0; + + if (ent->modified_by) + num_tl_data++; + + ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg); + if (ret) return ret; + if (last_pw_chg) + num_tl_data++; + + extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (extp) + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < ent->keys.len;i++) { + if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5) + continue; + num_key_data++; + } + if (hist_keys) { + for (i = 0; i < hist_keys->len; i++) { + /* + * MIT uses the highest kvno as the current kvno instead of + * tracking kvno separately, so we can't dump keysets with kvno + * higher than the entry's kvno. + */ + if (hist_keys->val[i].kvno >= ent->kvno) + continue; + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + num_key_data++; + } + } + } + ret = krb5_unparse_name(context, ent->principal, &p); + if (ret) return ret; + sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d", + strlen(p), num_tl_data, num_key_data, p, + flags_to_attr(ent->flags)); + free(p); + if (sz == -1) return ENOMEM; + + if (ent->max_life) + max_life = *ent->max_life; + if (ent->max_renew) + max_renew = *ent->max_renew; + if (ent->valid_end) + exp = *ent->valid_end; + if (ent->pw_end) + pwexp = *ent->pw_end; + + sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0", + max_life, max_renew, exp, pwexp); + if (sz == -1) return ENOMEM; + + /* Dump TL data we know: last pw chg and modified_by */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 + if (last_pw_chg) { + krb5_data d; + time_t val; + unsigned char *ptr; + + ptr = (unsigned char *)&last_pw_chg; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (last_pw_chg); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_LAST_PWD_CHANGE, d.length); + if (sz == -1) return ENOMEM; + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) return ENOMEM; + } + if (ent->modified_by) { + krb5_data d; + unsigned int val; + size_t plen; + unsigned char *ptr; + char *modby_p; + + ptr = (unsigned char *)&ent->modified_by->time; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (ent->modified_by->time); + ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p); + if (ret) return ret; + plen = strlen(modby_p); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_MOD_PRINC, + d.length + plen + 1 /* NULL counted */); + if (sz == -1) return ENOMEM; + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) { + free(modby_p); + return ENOMEM; + } + d.data = modby_p; + d.length = plen + 1; + sz = append_hex(context, sp, 1, 1, &d); + free(modby_p); + if (sz == -1) return ENOMEM; + } + /* + * Dump keys (remembering to not include any with kvno higher than + * the entry's because MIT doesn't track entry kvno separately from + * the entry's keys -- max kvno is it) + */ + for (i = 0; i < ent->keys.len; i++) { + if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5) + continue; + sz = append_mit_key(context, sp, ent->principal, ent->kvno, + &ent->keys.val[i]); + if (sz == -1) return ENOMEM; + } + for (i = 0; hist_keys && i < ent->kvno; i++) { + size_t m; + + /* dump historical keys */ + for (k = 0; k < hist_keys->len; k++) { + if (hist_keys->val[k].kvno != ent->kvno - i) + continue; + for (m = 0; m < hist_keys->val[k].keys.len; m++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + sz = append_mit_key(context, sp, ent->principal, + hist_keys->val[k].kvno, + &hist_keys->val[k].keys.val[m]); + if (sz == -1) return ENOMEM; + } + } + } + sz = append_string(context, sp, "\t-1;"); /* "extra data" */ + if (sz == -1) return ENOMEM; return 0; } krb5_error_code -hdb_entry2string (krb5_context context, hdb_entry *ent, char **str) +hdb_entry2string(krb5_context context, hdb_entry *ent, char **str) { krb5_error_code ret; krb5_data data; krb5_storage *sp; sp = krb5_storage_emem(); - if(sp == NULL) { + if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } ret = entry2string_int(context, sp, ent); - if(ret) { + if (ret) { krb5_storage_free(sp); return ret; } @@ -267,22 +556,31 @@ hdb_entry2string (krb5_context context, hdb_entry *ent, char **str) /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */ krb5_error_code -hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, void *data) +hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, + void *data) { + struct hdb_print_entry_arg *parg = data; krb5_error_code ret; krb5_storage *sp; - FILE *f = data; - - fflush(f); - sp = krb5_storage_from_fd(fileno(f)); - if(sp == NULL) { + fflush(parg->out); + sp = krb5_storage_from_fd(fileno(parg->out)); + if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } - ret = entry2string_int(context, sp, &entry->entry); - if(ret) { + switch (parg->fmt) { + case HDB_DUMP_HEIMDAL: + ret = entry2string_int(context, sp, &entry->entry); + break; + case HDB_DUMP_MIT: + ret = entry2mit_string_int(context, sp, &entry->entry); + break; + default: + heim_abort("Only two dump formats supported: Heimdal and MIT"); + } + if (ret) { krb5_storage_free(sp); return ret; } diff --git a/lib/hdb/test_dbinfo.c b/lib/hdb/test_dbinfo.c index efe50afb6a2b..b94b75bb3746 100644 --- a/lib/hdb/test_dbinfo.c +++ b/lib/hdb/test_dbinfo.c @@ -38,8 +38,8 @@ static int help_flag; static int version_flag; struct getargs args[] = { - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); diff --git a/lib/hdb/test_hdbkeys.c b/lib/hdb/test_hdbkeys.c index 1c3216d143a6..7cf4629b6ce0 100644 --- a/lib/hdb/test_hdbkeys.c +++ b/lib/hdb/test_hdbkeys.c @@ -40,9 +40,9 @@ static int version_flag; static int kvno_integer = 1; struct getargs args[] = { - { "kvno", 'd', arg_integer, &kvno_integer }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "kvno", 'd', arg_integer, &kvno_integer, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -88,6 +88,10 @@ main(int argc, char **argv) memset(&keyset, 0, sizeof(keyset)); keyset.kvno = kvno_integer; + keyset.set_time = malloc(sizeof (*keyset.set_time)); + if (keyset.set_time == NULL) + errx(1, "couldn't allocate set_time field of keyset"); + *keyset.set_time = time(NULL); ret = hdb_generate_key_set_password(context, principal, password_str, &keyset.keys.val, &len); @@ -108,7 +112,7 @@ main(int argc, char **argv) krb5_free_context(context); - ret = base64_encode(data, length, &str); + ret = rk_base64_encode(data, length, &str); if (ret < 0) errx(1, "base64_encode"); diff --git a/lib/hdb/test_hdbplugin.c b/lib/hdb/test_hdbplugin.c new file mode 100644 index 000000000000..4ebceb8da072 --- /dev/null +++ b/lib/hdb/test_hdbplugin.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013 Jeffrey Clark + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +struct hdb_called { + int create; + int init; + int fini; +}; +struct hdb_called testresult; + +static krb5_error_code +hdb_test_create(krb5_context context, struct HDB **db, const char *arg) +{ + testresult.create = 1; + return 0; +} + +static krb5_error_code +hdb_test_init(krb5_context context, void **ctx) +{ + *ctx = NULL; + testresult.init = 1; + return 0; +} + +static void hdb_test_fini(void *ctx) +{ + testresult.fini = 1; +} + +struct hdb_method hdb_test = +{ +#ifdef WIN32 + /* Not c99 */ + HDB_INTERFACE_VERSION, + hdb_test_init, + hdb_test_fini, + "test", + hdb_test_create +#else + .version = HDB_INTERFACE_VERSION, + .init = hdb_test_init, + .fini = hdb_test_fini, + .prefix = "test", + .create = hdb_test_create +#endif +}; + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + HDB *db; + + setprogname(argv[0]); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_contex"); + + ret = krb5_plugin_register(context, + PLUGIN_TYPE_DATA, "hdb_test_interface", + &hdb_test); + if(ret) { + krb5_err(context, 1, ret, "krb5_plugin_register"); + } + + ret = hdb_create(context, &db, "test:test&1234"); + if(ret) { + krb5_err(context, 1, ret, "hdb_create"); + } + + krb5_free_context(context); + return 0; +} diff --git a/lib/hdb/test_mkey.c b/lib/hdb/test_mkey.c index 11032d078bee..97399c6b56af 100644 --- a/lib/hdb/test_mkey.c +++ b/lib/hdb/test_mkey.c @@ -8,9 +8,9 @@ static int help_flag; static int version_flag; struct getargs args[] = { - { "mkey-file", 0, arg_string, &mkey_file }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "mkey-file", 0, arg_string, &mkey_file, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); diff --git a/lib/hdb/version-script.map b/lib/hdb/version-script.map index 50a36cec0aa9..579a2efe7c41 100644 --- a/lib/hdb/version-script.map +++ b/lib/hdb/version-script.map @@ -4,6 +4,8 @@ HEIMDAL_HDB_1.0 { global: encode_hdb_keyset; hdb_add_master_key; + hdb_add_current_keys_to_history; + hdb_change_kvno; hdb_check_db_format; hdb_clear_extension; hdb_clear_master_key; @@ -42,21 +44,25 @@ HEIMDAL_HDB_1.0 { hdb_free_master_key; hdb_generate_key_set; hdb_generate_key_set_password; + hdb_generate_key_set_password_with_ks_tuple; hdb_get_dbinfo; hdb_init_db; hdb_key2principal; + hdb_kvno2keys; hdb_list_builtin; hdb_lock; hdb_next_enctype2key; hdb_principal2key; hdb_print_entry; hdb_process_master_key; + hdb_prune_keys; hdb_read_master_key; hdb_replace_extension; hdb_seal_key; hdb_seal_key_mkey; hdb_seal_keys; hdb_seal_keys_mkey; + hdb_set_last_modified_by; hdb_set_master_key; hdb_set_master_keyfile; hdb_unlock; @@ -71,36 +77,52 @@ HEIMDAL_HDB_1.0 { hdb_interface_version; initialize_hdb_error_table_r; + # MIT KDB related entries + _hdb_mdb_value2entry; + _hdb_mit_dump2mitdb_entry; + hdb_kt_ops; + hdb_get_kt_ops; # some random bits needed for libkadm - HDBFlags2int; + add_HDB_Ext_KeySet; + add_Keys; asn1_HDBFlags_units; copy_Event; copy_HDB_extensions; copy_Key; + copy_Keys; copy_Salt; decode_HDB_Ext_Aliases; - decode_HDB_Ext_PKINIT_acl; decode_HDB_extension; + decode_HDB_Ext_PKINIT_acl; decode_Key; + decode_Keys; encode_HDB_Ext_Aliases; - encode_HDB_Ext_PKINIT_acl; encode_HDB_extension; + encode_HDB_Ext_PKINIT_acl; encode_Key; + encode_Keys; free_Event; + free_hdb_entry; free_HDB_Ext_Aliases; - free_HDB_Ext_PKINIT_acl; free_HDB_extension; free_HDB_extensions; + free_HDB_Ext_PKINIT_acl; + free_hdb_keyset; free_Key; + free_Keys; free_Salt; - free_hdb_entry; + HDBFlags2int; int2HDBFlags; length_HDB_Ext_Aliases; - length_HDB_Ext_PKINIT_acl; length_HDB_extension; + length_HDB_Ext_PKINIT_acl; length_Key; + length_Keys; + remove_Keys; + add_Keys; + add_HDB_Ext_KeySet; local: *; |