aboutsummaryrefslogtreecommitdiff
path: root/lib/hdb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hdb')
-rw-r--r--lib/hdb/Makefile.am79
-rw-r--r--lib/hdb/Makefile.in1467
-rw-r--r--lib/hdb/NTMakefile18
-rw-r--r--lib/hdb/common.c1718
-rw-r--r--lib/hdb/db.c25
-rw-r--r--lib/hdb/db3.c25
-rw-r--r--lib/hdb/dbinfo.c18
-rw-r--r--lib/hdb/ext.c304
-rw-r--r--lib/hdb/hdb-keytab.c27
-rw-r--r--lib/hdb/hdb-ldap.c390
-rw-r--r--lib/hdb/hdb-mdb.c549
-rw-r--r--lib/hdb/hdb-mitdb.c118
-rw-r--r--lib/hdb/hdb-private.h81
-rw-r--r--lib/hdb/hdb-protos.h592
-rw-r--r--lib/hdb/hdb-sqlite.c66
-rw-r--r--lib/hdb/hdb.asn1115
-rw-r--r--lib/hdb/hdb.c547
-rw-r--r--lib/hdb/hdb.h130
-rw-r--r--lib/hdb/hdb.opt9
-rw-r--r--lib/hdb/keys.c208
-rw-r--r--lib/hdb/keytab.c60
-rw-r--r--lib/hdb/libhdb-exports.def106
-rw-r--r--lib/hdb/ndbm.c64
-rw-r--r--lib/hdb/print.c20
-rw-r--r--lib/hdb/test_concurrency.c506
-rw-r--r--lib/hdb/test_dbinfo.c61
-rw-r--r--lib/hdb/test_hdbkeys.c2
-rw-r--r--lib/hdb/test_hdbplugin.c107
-rw-r--r--lib/hdb/test_namespace.c941
-rw-r--r--lib/hdb/version-script.map68
30 files changed, 5210 insertions, 3211 deletions
diff --git a/lib/hdb/Makefile.am b/lib/hdb/Makefile.am
index 448b0242f3e7..4a5599532436 100644
--- a/lib/hdb/Makefile.am
+++ b/lib/hdb/Makefile.am
@@ -2,43 +2,55 @@
include $(top_srcdir)/Makefile.am.common
+WFLAGS += $(WFLAGS_ENUM_CONV)
+
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)
AM_CPPFLAGS += $(INCLUDE_libintl)
+AM_CPPFLAGS += -DHDB_DEFAULT_DB_TYPE=\"$(db_type):\"
if HAVE_DBHEADER
AM_CPPFLAGS += -I$(DBHEADER)
endif
BUILT_SOURCES = \
- $(gen_files_hdb:.x=.c) \
+ $(gen_files_hdb) \
hdb_err.c \
- hdb_err.h
+ hdb_err.h \
+ $(srcdir)/hdb-protos.h \
+ $(srcdir)/hdb-private.h
gen_files_hdb = \
- asn1_Salt.x \
- asn1_Key.x \
- asn1_Event.x \
- asn1_HDBFlags.x \
- asn1_GENERATION.x \
- asn1_HDB_Ext_PKINIT_acl.x \
- asn1_HDB_Ext_PKINIT_cert.x \
- asn1_HDB_Ext_PKINIT_hash.x \
- asn1_HDB_Ext_Constrained_delegation_acl.x \
- 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_Keys.x
+ asn1_Event.c \
+ asn1_GENERATION.c \
+ asn1_HDB_EncTypeList.c \
+ asn1_HDB_Ext_Aliases.c \
+ asn1_HDB_Ext_Constrained_delegation_acl.c \
+ asn1_HDB_Ext_KeyRotation.c \
+ asn1_HDB_Ext_KeySet.c \
+ asn1_HDB_Ext_Lan_Manager_OWF.c \
+ asn1_HDB_Ext_Password.c \
+ asn1_HDB_Ext_PKINIT_acl.c \
+ asn1_HDB_Ext_PKINIT_cert.c \
+ asn1_HDB_Ext_PKINIT_hash.c \
+ asn1_HDB_EntryOrAlias.c \
+ asn1_HDB_entry_alias.c \
+ asn1_HDB_entry.c \
+ asn1_HDB_extension.c \
+ asn1_HDB_extensions.c \
+ asn1_HDB_keyset.c \
+ asn1_HDBFlags.c \
+ asn1_Key.c \
+ asn1_KeyRotation.c \
+ asn1_KeyRotationFlags.c \
+ asn1_Keys.c \
+ asn1_Salt.c
CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \
- hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.[cx]
+ hdb_asn1{,-priv}.h hdb_asn1_files hdb_asn1-template.c \
+ hdb_asn1_syms.c hdb_asn1_oids.c hdb_asn1.json \
+ testhdb-*
LDADD = libhdb.la \
../krb5/libkrb5.la \
@@ -72,7 +84,9 @@ if versionscript
libhdb_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map
endif
-noinst_PROGRAMS = test_dbinfo test_hdbkeys test_mkey test_hdbplugin
+# test_hdbkeys and test_mkey are not tests -- they are manual test utils
+noinst_PROGRAMS = test_dbinfo test_hdbkeys test_mkey test_namespace test_concurrency
+TESTS = test_dbinfo test_namespace test_concurrency
dist_libhdb_la_SOURCES = \
common.c \
@@ -118,26 +132,27 @@ 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)
+ALL_OBJECTS += $(test_namespace_OBJECTS)
+ALL_OBJECTS += $(test_concurrency_OBJECTS)
$(ALL_OBJECTS): $(HDB_PROTOS) hdb_asn1.h hdb_asn1-priv.h hdb_err.h
+test_namespace_LDADD = $(LDADD) $(test_hdbkeys_LIBS) $(LIB_heimbase)
+
$(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: $(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
+$(gen_files_hdb) hdb_asn1.h hdb_asn1-priv.h: hdb_asn1_files
+ for genfile in '$(gen_files_hdb)'; do \
+ $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \
+ done
hdb_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/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)
+ $(ASN1_COMPILE) --option-file=$(srcdir)/hdb.opt $(srcdir)/hdb.asn1 hdb_asn1
+ @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat hdb_asn1_files)
# to help stupid solaris make
diff --git a/lib/hdb/Makefile.in b/lib/hdb/Makefile.in
deleted file mode 100644
index ab4074f09808..000000000000
--- a/lib/hdb/Makefile.in
+++ /dev/null
@@ -1,1467 +0,0 @@
-# Makefile.in generated by automake 1.16.5 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2021 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.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-# $Id$
-
-# $Id$
-
-# $Id$
-
-
-
-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@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-@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_hdbplugin$(EXEEXT)
-subdir = lib/hdb
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \
- $(top_srcdir)/cf/auth-modules.m4 \
- $(top_srcdir)/cf/broken-glob.m4 \
- $(top_srcdir)/cf/broken-realloc.m4 \
- $(top_srcdir)/cf/broken-snprintf.m4 $(top_srcdir)/cf/broken.m4 \
- $(top_srcdir)/cf/broken2.m4 $(top_srcdir)/cf/c-attribute.m4 \
- $(top_srcdir)/cf/capabilities.m4 \
- $(top_srcdir)/cf/check-compile-et.m4 \
- $(top_srcdir)/cf/check-getpwnam_r-posix.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/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 \
- $(top_srcdir)/cf/find-func-no-libs2.m4 \
- $(top_srcdir)/cf/find-func.m4 \
- $(top_srcdir)/cf/find-if-not-broken.m4 \
- $(top_srcdir)/cf/framework-security.m4 \
- $(top_srcdir)/cf/have-struct-field.m4 \
- $(top_srcdir)/cf/have-type.m4 $(top_srcdir)/cf/irix.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 \
- $(top_srcdir)/cf/largefile.m4 $(top_srcdir)/cf/libtool.m4 \
- $(top_srcdir)/cf/ltoptions.m4 $(top_srcdir)/cf/ltsugar.m4 \
- $(top_srcdir)/cf/ltversion.m4 $(top_srcdir)/cf/lt~obsolete.m4 \
- $(top_srcdir)/cf/mips-abi.m4 $(top_srcdir)/cf/misc.m4 \
- $(top_srcdir)/cf/need-proto.m4 $(top_srcdir)/cf/osfc2.m4 \
- $(top_srcdir)/cf/otp.m4 $(top_srcdir)/cf/pkg.m4 \
- $(top_srcdir)/cf/proto-compat.m4 $(top_srcdir)/cf/pthreads.m4 \
- $(top_srcdir)/cf/resolv.m4 $(top_srcdir)/cf/retsigtype.m4 \
- $(top_srcdir)/cf/roken-frag.m4 \
- $(top_srcdir)/cf/socket-wrapper.m4 $(top_srcdir)/cf/sunos.m4 \
- $(top_srcdir)/cf/telnet.m4 $(top_srcdir)/cf/test-package.m4 \
- $(top_srcdir)/cf/version-script.m4 $(top_srcdir)/cf/wflags.m4 \
- $(top_srcdir)/cf/win32.m4 $(top_srcdir)/cf/with-all.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 =
-CONFIG_CLEAN_VPATH_FILES =
-PROGRAMS = $(noinst_PROGRAMS)
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
- $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
- *) f=$$p;; \
- esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
- srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
- for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
- for p in $$list; do echo "$$p $$p"; done | \
- sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
- $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
- if (++n[$$2] == $(am__install_max)) \
- { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
- END { for (dir in files) print dir, files[dir] }'
-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)
-am__DEPENDENCIES_1 =
-@OPENLDAP_MODULE_TRUE@hdb_ldap_la_DEPENDENCIES = \
-@OPENLDAP_MODULE_TRUE@ $(am__DEPENDENCIES_1) libhdb.la
-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)
-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-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 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 \
- asn1_HDBFlags.lo asn1_GENERATION.lo asn1_HDB_Ext_PKINIT_acl.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_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) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libhdb_la_LDFLAGS) $(LDFLAGS) -o $@
-test_dbinfo_SOURCES = test_dbinfo.c
-test_dbinfo_OBJECTS = test_dbinfo.$(OBJEXT)
-test_dbinfo_LDADD = $(LDADD)
-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 ../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 ../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__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/asn1_Event.Plo \
- ./$(DEPDIR)/asn1_GENERATION.Plo ./$(DEPDIR)/asn1_HDBFlags.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_Aliases.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_Constrained_delegation_acl.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_KeySet.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_Lan_Manager_OWF.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_acl.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_cert.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_hash.Plo \
- ./$(DEPDIR)/asn1_HDB_Ext_Password.Plo \
- ./$(DEPDIR)/asn1_HDB_extension.Plo \
- ./$(DEPDIR)/asn1_HDB_extensions.Plo ./$(DEPDIR)/asn1_Key.Plo \
- ./$(DEPDIR)/asn1_Keys.Plo ./$(DEPDIR)/asn1_Salt.Plo \
- ./$(DEPDIR)/asn1_hdb_entry.Plo \
- ./$(DEPDIR)/asn1_hdb_entry_alias.Plo \
- ./$(DEPDIR)/asn1_hdb_keyset.Plo ./$(DEPDIR)/common.Plo \
- ./$(DEPDIR)/db.Plo ./$(DEPDIR)/db3.Plo ./$(DEPDIR)/dbinfo.Plo \
- ./$(DEPDIR)/ext.Plo ./$(DEPDIR)/hdb-keytab.Plo \
- ./$(DEPDIR)/hdb-ldap.Plo ./$(DEPDIR)/hdb-mdb.Plo \
- ./$(DEPDIR)/hdb-mitdb.Plo ./$(DEPDIR)/hdb-sqlite.Plo \
- ./$(DEPDIR)/hdb.Plo ./$(DEPDIR)/hdb_err.Plo \
- ./$(DEPDIR)/keys.Plo ./$(DEPDIR)/keytab.Plo \
- ./$(DEPDIR)/mkey.Plo ./$(DEPDIR)/ndbm.Plo \
- ./$(DEPDIR)/print.Plo ./$(DEPDIR)/test_dbinfo.Po \
- ./$(DEPDIR)/test_hdbkeys.Po ./$(DEPDIR)/test_hdbplugin.Po \
- ./$(DEPDIR)/test_mkey.Po
-am__mv = mv -f
-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) $(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_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_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)`
-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@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CANONICAL_HOST = @CANONICAL_HOST@
-CAPNG_CFLAGS = @CAPNG_CFLAGS@
-CAPNG_LIBS = @CAPNG_LIBS@
-CATMAN = @CATMAN@
-CATMANEXT = @CATMANEXT@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CLANG_FORMAT = @CLANG_FORMAT@
-COMPILE_ET = @COMPILE_ET@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CSCOPE = @CSCOPE@
-CTAGS = @CTAGS@
-CYGPATH_W = @CYGPATH_W@
-DB1LIB = @DB1LIB@
-DB3LIB = @DB3LIB@
-DBHEADER = @DBHEADER@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DIR_com_err = @DIR_com_err@
-DIR_hdbdir = @DIR_hdbdir@
-DIR_roken = @DIR_roken@
-DLLTOOL = @DLLTOOL@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-ENABLE_AFS_STRING_TO_KEY = @ENABLE_AFS_STRING_TO_KEY@
-ETAGS = @ETAGS@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FILECMD = @FILECMD@
-GCD_MIG = @GCD_MIG@
-GREP = @GREP@
-GROFF = @GROFF@
-INCLUDES_roken = @INCLUDES_roken@
-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@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LDFLAGS_VERSION_SCRIPT = @LDFLAGS_VERSION_SCRIPT@
-LEX = @LEX@
-LEXLIB = @LEXLIB@
-LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
-LIBADD_roken = @LIBADD_roken@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIB_AUTH_SUBDIRS = @LIB_AUTH_SUBDIRS@
-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@
-LIB_crypt = @LIB_crypt@
-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@
-LIB_door_create = @LIB_door_create@
-LIB_freeaddrinfo = @LIB_freeaddrinfo@
-LIB_gai_strerror = @LIB_gai_strerror@
-LIB_getaddrinfo = @LIB_getaddrinfo@
-LIB_gethostbyname = @LIB_gethostbyname@
-LIB_gethostbyname2 = @LIB_gethostbyname2@
-LIB_getnameinfo = @LIB_getnameinfo@
-LIB_getpwnam_r = @LIB_getpwnam_r@
-LIB_getsockopt = @LIB_getsockopt@
-LIB_hcrypto = @LIB_hcrypto@
-LIB_hcrypto_a = @LIB_hcrypto_a@
-LIB_hcrypto_appl = @LIB_hcrypto_appl@
-LIB_hcrypto_so = @LIB_hcrypto_so@
-LIB_hstrerror = @LIB_hstrerror@
-LIB_kdb = @LIB_kdb@
-LIB_libedit = @LIB_libedit@
-LIB_libintl = @LIB_libintl@
-LIB_loadquery = @LIB_loadquery@
-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@
-LIB_res_ndestroy = @LIB_res_ndestroy@
-LIB_res_nsearch = @LIB_res_nsearch@
-LIB_res_search = @LIB_res_search@
-LIB_roken = @LIB_roken@
-LIB_security = @LIB_security@
-LIB_setsockopt = @LIB_setsockopt@
-LIB_socket = @LIB_socket@
-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@
-NROFF = @NROFF@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-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@
-PTHREAD_LIBADD = @PTHREAD_LIBADD@
-PYTHON = @PYTHON@
-PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
-PYTHON_PLATFORM = @PYTHON_PLATFORM@
-PYTHON_PREFIX = @PYTHON_PREFIX@
-PYTHON_VERSION = @PYTHON_VERSION@
-RANLIB = @RANLIB@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SLC = @SLC@
-SLC_DEP = @SLC_DEP@
-STRIP = @STRIP@
-VERSION = @VERSION@
-VERSIONING = @VERSIONING@
-WFLAGS = @WFLAGS@
-WFLAGS_LITE = @WFLAGS_LITE@
-YACC = @YACC@
-YFLAGS = @YFLAGS@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-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@
-dpagaix_ldflags = @dpagaix_ldflags@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-pkgpyexecdir = @pkgpyexecdir@
-pkgpythondir = @pkgpythondir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-pyexecdir = @pyexecdir@
-pythondir = @pythondir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-subdirs = @subdirs@
-sysconfdir = @sysconfdir@
-target_alias = @target_alias@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-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_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@
-INCLUDE_krb4 = @INCLUDE_krb4@
-LIB_krb4 = @LIB_krb4@
-libexec_heimdaldir = $(libexecdir)/heimdal
-NROFF_MAN = groff -mandoc -Tascii
-@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)/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 \
- hdb_err.h
-
-gen_files_hdb = \
- asn1_Salt.x \
- asn1_Key.x \
- asn1_Event.x \
- asn1_HDBFlags.x \
- asn1_GENERATION.x \
- asn1_HDB_Ext_PKINIT_acl.x \
- asn1_HDB_Ext_PKINIT_cert.x \
- asn1_HDB_Ext_PKINIT_hash.x \
- asn1_HDB_Ext_Constrained_delegation_acl.x \
- 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_Keys.x
-
-CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \
- hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.[cx]
-
-LDADD = libhdb.la \
- ../krb5/libkrb5.la \
- ../asn1/libasn1.la \
- $(LIB_hcrypto) \
- $(LIB_roken) \
- $(LIB_openldap) \
- $(LIB_libintl) \
- $(LIB_ldopen)
-
-@OPENLDAP_MODULE_TRUE@ldap_so = hdb_ldap.la
-@OPENLDAP_MODULE_TRUE@hdb_ldap_la_SOURCES = hdb-ldap.c
-@OPENLDAP_MODULE_TRUE@hdb_ldap_la_LDFLAGS = -module -avoid-version
-@OPENLDAP_MODULE_TRUE@hdb_ldap_la_LIBADD = $(LIB_openldap) libhdb.la
-@OPENLDAP_MODULE_FALSE@ldap = hdb-ldap.c
-@OPENLDAP_MODULE_FALSE@ldap_lib = $(LIB_openldap)
-lib_LTLIBRARIES = libhdb.la $(ldap_so)
-libhdb_la_LDFLAGS = -version-info 11:0:2 $(am__append_2)
-dist_libhdb_la_SOURCES = \
- common.c \
- db.c \
- db3.c \
- ext.c \
- $(ldap) \
- 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
-
-nodist_libhdb_la_SOURCES = $(BUILT_SOURCES)
-libhdb_la_DEPENDENCIES = version-script.map
-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 \
- ../asn1/libasn1.la \
- $(LIB_sqlite3) \
- $(LIBADD_roken) \
- $(ldap_lib) \
- $(LIB_dlopen) \
- $(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 \
- libhdb-exports.def \
- hdb.asn1 \
- hdb_err.et \
- hdb.schema \
- version-script.map \
- data-mkey.mit.des3.le \
- data-mkey.mit.des3.be
-
-all: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) all-am
-
-.SUFFIXES:
-.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 \
- *$$dep*) \
- ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
- && { if test -f $@; then exit 0; else break; fi; }; \
- exit 1;; \
- esac; \
- done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/hdb/Makefile'; \
- $(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --foreign lib/hdb/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- @case '$?' in \
- *config.status*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
- *) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
- 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
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-clean-noinstPROGRAMS:
- @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
- echo " rm -f" $$list; \
- rm -f $$list || exit $$?; \
- test -n "$(EXEEXT)" || exit 0; \
- list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f" $$list; \
- rm -f $$list
-
-install-libLTLIBRARIES: $(lib_LTLIBRARIES)
- @$(NORMAL_INSTALL)
- @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
- list2=; for p in $$list; do \
- if test -f $$p; then \
- list2="$$list2 $$p"; \
- 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)"; \
- }
-
-uninstall-libLTLIBRARIES:
- @$(NORMAL_UNINSTALL)
- @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
- for p in $$list; do \
- $(am__strip_dir) \
- echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
- $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
- done
-
-clean-libLTLIBRARIES:
- -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
- @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)
-
-test_dbinfo$(EXEEXT): $(test_dbinfo_OBJECTS) $(test_dbinfo_DEPENDENCIES) $(EXTRA_test_dbinfo_DEPENDENCIES)
- @rm -f test_dbinfo$(EXEEXT)
- $(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)
- $(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)
- $(AM_V_CCLD)$(LINK) $(test_mkey_OBJECTS) $(test_mkey_LDADD) $(LIBS)
-
-mostlyclean-compile:
- -rm -f *.$(OBJEXT)
-
-distclean-compile:
- -rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Event.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_GENERATION.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDBFlags.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Aliases.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Constrained_delegation_acl.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_KeySet.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Lan_Manager_OWF.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_PKINIT_acl.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_PKINIT_cert.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_PKINIT_hash.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_Ext_Password.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_extension.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_HDB_extensions.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Key.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Keys.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_Salt.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_hdb_entry.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_hdb_entry_alias.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1_hdb_keyset.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db3.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbinfo.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-keytab.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-ldap.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-mdb.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-mitdb.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb-sqlite.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdb_err.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keytab.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkey.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ndbm.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dbinfo.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hdbkeys.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hdbplugin.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mkey.Po@am__quote@ # am--include-marker
-
-$(am__depfiles_remade):
- @$(MKDIR_P) $(@D)
- @echo '# dummy' >$@-t && $(am__mv) $@-t $@
-
-am--depfiles: $(am__depfiles_remade)
-
-.c.o:
-@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@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
-
-.c.obj:
-@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@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
-
-.c.lo:
-@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@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
-
-mostlyclean-libtool:
- -rm -f *.lo
-
-clean-libtool:
- -rm -rf .libs _libs
-install-includeHEADERS: $(include_HEADERS)
- @$(NORMAL_INSTALL)
- @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"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
- $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
- done
-
-uninstall-includeHEADERS:
- @$(NORMAL_UNINSTALL)
- @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
-install-nodist_includeHEADERS: $(nodist_include_HEADERS)
- @$(NORMAL_INSTALL)
- @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"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
- $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
- done
-
-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|^.*/||'`; \
- 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`; \
- $(am__define_uniq_tagged_files); \
- shift; \
- if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
- test -n "$$unique" || unique=$$empty_fix; \
- if test $$# -gt 0; then \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- "$$@" $$unique; \
- else \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- $$unique; \
- fi; \
- fi
-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
-
-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
-distdir: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) distdir-am
-
-distdir-am: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- list='$(DISTFILES)'; \
- dist_files=`for file in $$list; do echo $$file; done | \
- sed -e "s|^$$srcdirstrip/||;t" \
- -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
- case $$dist_files in \
- */*) $(MKDIR_P) `echo "$$dist_files" | \
- sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
- sort -u` ;; \
- esac; \
- for file in $$dist_files; do \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- if test -d $$d/$$file; then \
- dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test -d "$(distdir)/$$file"; then \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
- else \
- test -f "$(distdir)/$$file" \
- || cp -p $$d/$$file "$(distdir)/$$file" \
- || exit 1; \
- fi; \
- done
- $(MAKE) $(AM_MAKEFLAGS) \
- top_distdir="$(top_distdir)" distdir="$(distdir)" \
- dist-hook
-check-am: all-am
- $(MAKE) $(AM_MAKEFLAGS) check-local
-check: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) check-am
-all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS) all-local
-installdirs:
- for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includedir)"; do \
- test -z "$$dir" || $(MKDIR_P) "$$dir"; \
- done
-install: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) install-am
-install-exec: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
- 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:
- -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
- @echo "This command is intended for maintainers to use"
- @echo "it deletes files that may require special tools to rebuild."
- -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-clean: clean-am
-
-clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
- clean-noinstPROGRAMS mostlyclean-am
-
-distclean: distclean-am
- -rm -f ./$(DEPDIR)/asn1_Event.Plo
- -rm -f ./$(DEPDIR)/asn1_GENERATION.Plo
- -rm -f ./$(DEPDIR)/asn1_HDBFlags.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Aliases.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Constrained_delegation_acl.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_KeySet.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Lan_Manager_OWF.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_acl.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_cert.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_hash.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Password.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_extension.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_extensions.Plo
- -rm -f ./$(DEPDIR)/asn1_Key.Plo
- -rm -f ./$(DEPDIR)/asn1_Keys.Plo
- -rm -f ./$(DEPDIR)/asn1_Salt.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_entry.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_entry_alias.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_keyset.Plo
- -rm -f ./$(DEPDIR)/common.Plo
- -rm -f ./$(DEPDIR)/db.Plo
- -rm -f ./$(DEPDIR)/db3.Plo
- -rm -f ./$(DEPDIR)/dbinfo.Plo
- -rm -f ./$(DEPDIR)/ext.Plo
- -rm -f ./$(DEPDIR)/hdb-keytab.Plo
- -rm -f ./$(DEPDIR)/hdb-ldap.Plo
- -rm -f ./$(DEPDIR)/hdb-mdb.Plo
- -rm -f ./$(DEPDIR)/hdb-mitdb.Plo
- -rm -f ./$(DEPDIR)/hdb-sqlite.Plo
- -rm -f ./$(DEPDIR)/hdb.Plo
- -rm -f ./$(DEPDIR)/hdb_err.Plo
- -rm -f ./$(DEPDIR)/keys.Plo
- -rm -f ./$(DEPDIR)/keytab.Plo
- -rm -f ./$(DEPDIR)/mkey.Plo
- -rm -f ./$(DEPDIR)/ndbm.Plo
- -rm -f ./$(DEPDIR)/print.Plo
- -rm -f ./$(DEPDIR)/test_dbinfo.Po
- -rm -f ./$(DEPDIR)/test_hdbkeys.Po
- -rm -f ./$(DEPDIR)/test_hdbplugin.Po
- -rm -f ./$(DEPDIR)/test_mkey.Po
- -rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
- distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-includeHEADERS install-nodist_includeHEADERS
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) install-data-hook
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am: install-exec-local install-libLTLIBRARIES
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
- -rm -f ./$(DEPDIR)/asn1_Event.Plo
- -rm -f ./$(DEPDIR)/asn1_GENERATION.Plo
- -rm -f ./$(DEPDIR)/asn1_HDBFlags.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Aliases.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Constrained_delegation_acl.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_KeySet.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Lan_Manager_OWF.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_acl.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_cert.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_PKINIT_hash.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_Ext_Password.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_extension.Plo
- -rm -f ./$(DEPDIR)/asn1_HDB_extensions.Plo
- -rm -f ./$(DEPDIR)/asn1_Key.Plo
- -rm -f ./$(DEPDIR)/asn1_Keys.Plo
- -rm -f ./$(DEPDIR)/asn1_Salt.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_entry.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_entry_alias.Plo
- -rm -f ./$(DEPDIR)/asn1_hdb_keyset.Plo
- -rm -f ./$(DEPDIR)/common.Plo
- -rm -f ./$(DEPDIR)/db.Plo
- -rm -f ./$(DEPDIR)/db3.Plo
- -rm -f ./$(DEPDIR)/dbinfo.Plo
- -rm -f ./$(DEPDIR)/ext.Plo
- -rm -f ./$(DEPDIR)/hdb-keytab.Plo
- -rm -f ./$(DEPDIR)/hdb-ldap.Plo
- -rm -f ./$(DEPDIR)/hdb-mdb.Plo
- -rm -f ./$(DEPDIR)/hdb-mitdb.Plo
- -rm -f ./$(DEPDIR)/hdb-sqlite.Plo
- -rm -f ./$(DEPDIR)/hdb.Plo
- -rm -f ./$(DEPDIR)/hdb_err.Plo
- -rm -f ./$(DEPDIR)/keys.Plo
- -rm -f ./$(DEPDIR)/keytab.Plo
- -rm -f ./$(DEPDIR)/mkey.Plo
- -rm -f ./$(DEPDIR)/ndbm.Plo
- -rm -f ./$(DEPDIR)/print.Plo
- -rm -f ./$(DEPDIR)/test_dbinfo.Po
- -rm -f ./$(DEPDIR)/test_hdbkeys.Po
- -rm -f ./$(DEPDIR)/test_hdbplugin.Po
- -rm -f ./$(DEPDIR)/test_mkey.Po
- -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
- uninstall-nodist_includeHEADERS
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) uninstall-hook
-.MAKE: all check check-am install install-am install-data-am \
- install-exec install-strip uninstall-am
-
-.PHONY: CTAGS GTAGS TAGS all all-am all-local am--depfiles 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 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
-
-install-exec-local: 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
-
-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"; \
- else file="$$f"; fi; \
- if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \
- : ; else \
- echo " $(CP) $$file $(buildinclude)/$$f"; \
- $(CP) $$file $(buildinclude)/$$f || true; \
- fi ; \
- done ; \
- foo='$(nobase_include_HEADERS)'; \
- for f in $$foo; do \
- if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \
- else file="$$f"; fi; \
- $(mkdir_p) $(buildinclude)/`dirname $$f` ; \
- if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \
- : ; else \
- echo " $(CP) $$file $(buildinclude)/$$f"; \
- $(CP) $$file $(buildinclude)/$$f; \
- fi ; \
- done
-
-all-local: install-build-headers
-
-check-local::
- @if test '$(CHECK_LOCAL)' = "no-check-local"; then \
- foo=''; elif test '$(CHECK_LOCAL)'; then \
- foo='$(CHECK_LOCAL)'; else \
- foo='$(PROGRAMS)'; fi; \
- if test "$$foo"; then \
- failed=0; all=0; \
- for i in $$foo; do \
- all=`expr $$all + 1`; \
- if (./$$i --version && ./$$i --help) > /dev/null 2>&1; then \
- echo "PASS: $$i"; \
- else \
- echo "FAIL: $$i"; \
- failed=`expr $$failed + 1`; \
- fi; \
- done; \
- if test "$$failed" -eq 0; then \
- banner="All $$all tests passed"; \
- else \
- banner="$$failed of $$all tests failed"; \
- fi; \
- dashes=`echo "$$banner" | sed s/./=/g`; \
- echo "$$dashes"; \
- echo "$$banner"; \
- echo "$$dashes"; \
- test "$$failed" -eq 0 || exit 1; \
- fi
-
-# It's useful for debugging to format generated sources. The default for all
-# clang-format styles is to sort includes, but in many cases in-tree we really
-# don't want to do that.
-.x.c:
- @if [ -z "$(CLANG_FORMAT)" ]; then \
- cmp -s $< $@ 2> /dev/null || cp $< $@; \
- else \
- cp $< $@.tmp.c; \
- $(CLANG_FORMAT) -style='{BasedOnStyle: Chromium, SortIncludes: false}' -i $@.tmp.c; \
- cmp -s $@.tmp.c $@ 2> /dev/null || mv $@.tmp.c $@; \
- fi
-
-.hx.h:
- @cmp -s $< $@ 2> /dev/null || cp $< $@;
-#NROFF_MAN = nroff -man
-.1.cat1:
- $(NROFF_MAN) $< > $@
-.3.cat3:
- $(NROFF_MAN) $< > $@
-.5.cat5:
- $(NROFF_MAN) $< > $@
-.7.cat7:
- $(NROFF_MAN) $< > $@
-.8.cat8:
- $(NROFF_MAN) $< > $@
-
-dist-cat1-mans:
- @foo='$(man1_MANS)'; \
- bar='$(man_MANS)'; \
- for i in $$bar; do \
- case $$i in \
- *.1) foo="$$foo $$i";; \
- esac; done ;\
- for i in $$foo; do \
- x=`echo $$i | sed 's/\.[^.]*$$/.cat1/'`; \
- echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
- $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
- done
-
-dist-cat3-mans:
- @foo='$(man3_MANS)'; \
- bar='$(man_MANS)'; \
- for i in $$bar; do \
- case $$i in \
- *.3) foo="$$foo $$i";; \
- esac; done ;\
- for i in $$foo; do \
- x=`echo $$i | sed 's/\.[^.]*$$/.cat3/'`; \
- echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
- $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
- done
-
-dist-cat5-mans:
- @foo='$(man5_MANS)'; \
- bar='$(man_MANS)'; \
- for i in $$bar; do \
- case $$i in \
- *.5) foo="$$foo $$i";; \
- esac; done ;\
- for i in $$foo; do \
- x=`echo $$i | sed 's/\.[^.]*$$/.cat5/'`; \
- echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
- $(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)'; \
- for i in $$bar; do \
- case $$i in \
- *.8) foo="$$foo $$i";; \
- esac; done ;\
- for i in $$foo; do \
- x=`echo $$i | sed 's/\.[^.]*$$/.cat8/'`; \
- echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
- $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
- done
-
-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) $(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) $(man7_MANS) $(man8_MANS)
-
-install-data-hook: install-cat-mans
-uninstall-hook: uninstall-cat-mans
-
-.et.h:
- $(COMPILE_ET) $<
-.et.c:
- $(COMPILE_ET) $<
-
-#
-# Useful target for debugging
-#
-
-check-valgrind:
- tobjdir=`cd $(top_builddir) && pwd` ; \
- tsrcdir=`cd $(top_srcdir) && pwd` ; \
- env TESTS_ENVIRONMENT="$${tsrcdir}/cf/maybe-valgrind.sh -s $${tsrcdir} -o $${tobjdir}" make check
-
-#
-# Target to please samba build farm, builds distfiles in-tree.
-# Will break when automake changes...
-#
-
-distdir-in-tree: $(DISTFILES) $(INFO_DEPS)
- list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
- if test "$$subdir" != .; then \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) distdir-in-tree) ; \
- fi ; \
- done
-
-$(ALL_OBJECTS): $(HDB_PROTOS) hdb_asn1.h hdb_asn1-priv.h hdb_err.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: $(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) --sequence=HDB-Ext-KeySet --sequence=Keys $(srcdir)/hdb.asn1 hdb_asn1
-
-# to help stupid solaris make
-
-hdb_err.h: hdb_err.et
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/lib/hdb/NTMakefile b/lib/hdb/NTMakefile
index 01671b07805c..f4801f7c54e9 100644
--- a/lib/hdb/NTMakefile
+++ b/lib/hdb/NTMakefile
@@ -31,17 +31,15 @@
RELDIR=lib\hdb
-!include ../../windows/NTMakefile.w32
+intcflags=-DASN1_LIB
-gen_files_hdb = $(OBJ)\asn1_hdb_asn1.x
+!include ../../windows/NTMakefile.w32
-$(gen_files_hdb) $(OBJ)\hdb_asn1.hx $(OBJ)\hdb_asn1-priv.hx: $(BINDIR)\asn1_compile.exe hdb.asn1
+$(OBJ)\asn1_hdb_asn1.c $(OBJ)\hdb_asn1.h $(OBJ)\hdb_asn1-priv.h: $(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 --one-code-file --option-file=$(SRCDIR)\hdb.opt $(SRCDIR)\hdb.asn1 hdb_asn1
cd $(SRCDIR)
-$(gen_files_hdb:.x=.c): $$(@R).x
-
!ifdef OPENLDAP_MODULE
ldap_dll = $(BINDIR)\hdb_ldap.dll
@@ -98,7 +96,7 @@ libhdb_OBJs = \
$(OBJ)\mkey.obj \
$(OBJ)\ndbm.obj \
$(OBJ)\print.obj \
- $(gen_files_hdb:.x=.obj) \
+ $(OBJ)\asn1_hdb_asn1.obj \
$(OBJ)\hdb_err.obj
$(OBJ)\hdb_err.c $(OBJ)\hdb_err.h: hdb_err.et
@@ -150,7 +148,7 @@ clean::
test:: test-binaries test-run
-test-binaries: $(OBJ)\test_dbinfo.exe $(OBJ)\test_hdbkeys.exe $(OBJ)\test_hdbplugin.exe
+test-binaries: $(OBJ)\test_dbinfo.exe $(OBJ)\test_hdbkeys.exe $(OBJ)\test_namespace.exe
$(OBJ)\test_dbinfo.exe: $(OBJ)\test_dbinfo.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS)
$(EXECONLINK)
@@ -160,7 +158,7 @@ $(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)
+$(OBJ)\test_namespace.exe: $(OBJ)\test_namespace.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBHEIMBASE) $(LIBROKEN) $(LIBVERS)
$(EXECONLINK)
$(EXEPREP_NODIST)
@@ -168,7 +166,7 @@ test-run:
cd $(OBJ)
-test_dbinfo.exe
-test_hdbkeys.exe
- -test_hdbplugin.exe
+ -test_namespace.exe
cd $(SRCDIR)
!ifdef OPENLDAP_INC
diff --git a/lib/hdb/common.c b/lib/hdb/common.c
index 2c8bb9f305e0..1c947b3cfc54 100644
--- a/lib/hdb/common.c
+++ b/lib/hdb/common.c
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*/
+#include "krb5_locl.h"
#include "hdb_locl.h"
int
@@ -64,7 +65,7 @@ hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
size_t len = 0;
int ret;
- ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret);
+ ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret);
if (ret == 0 && value->length != len)
krb5_abortx(context, "internal asn.1 encoder error");
return ret;
@@ -73,7 +74,7 @@ hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
int
hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
{
- return decode_hdb_entry(value->data, value->length, ent, NULL);
+ return decode_HDB_entry(value->data, value->length, ent, NULL);
}
int
@@ -84,7 +85,7 @@ hdb_entry_alias2value(krb5_context context,
size_t len = 0;
int ret;
- ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length,
+ ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length,
alias, &len, ret);
if (ret == 0 && value->length != len)
krb5_abortx(context, "internal asn.1 encoder error");
@@ -95,17 +96,69 @@ int
hdb_value2entry_alias(krb5_context context, krb5_data *value,
hdb_entry_alias *ent)
{
- return decode_hdb_entry_alias(value->data, value->length, ent, NULL);
+ return decode_HDB_entry_alias(value->data, value->length, ent, NULL);
}
-krb5_error_code
-_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
- unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
+/*
+ * Some old databases may not have stored the salt with each key, which will
+ * break clients when aliases or canonicalization are used. Generate a
+ * default salt based on the real principal name in the entry to handle
+ * this case.
+ */
+static krb5_error_code
+add_default_salts(krb5_context context, HDB *db, hdb_entry *entry)
{
+ krb5_error_code ret;
+ size_t i;
+ krb5_salt pwsalt;
+
+ ret = krb5_get_pw_salt(context, entry->principal, &pwsalt);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < entry->keys.len; i++) {
+ Key *key = &entry->keys.val[i];
+
+ if (key->salt != NULL ||
+ _krb5_enctype_requires_random_salt(context, key->key.keytype))
+ continue;
+
+ key->salt = calloc(1, sizeof(*key->salt));
+ if (key->salt == NULL) {
+ ret = krb5_enomem(context);
+ break;
+ }
+
+ key->salt->type = KRB5_PADATA_PW_SALT;
+
+ ret = krb5_data_copy(&key->salt->salt,
+ pwsalt.saltvalue.data,
+ pwsalt.saltvalue.length);
+ if (ret)
+ break;
+ }
+
+ krb5_free_salt(context, pwsalt);
+
+ return ret;
+}
+
+static krb5_error_code
+fetch_entry_or_alias(krb5_context context,
+ HDB *db,
+ krb5_const_principal principal,
+ unsigned flags,
+ hdb_entry *entry)
+{
+ HDB_EntryOrAlias eoa;
krb5_principal enterprise_principal = NULL;
krb5_data key, value;
krb5_error_code ret;
+ value.length = 0;
+ value.data = 0;
+ key = value;
+
if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
if (principal->name.name_string.len != 1) {
ret = KRB5_PARSE_MALFORMED;
@@ -121,59 +174,131 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
principal = enterprise_principal;
}
- hdb_principal2key(context, principal, &key);
- if (enterprise_principal)
- krb5_free_principal(context, enterprise_principal);
- ret = db->hdb__get(context, db, key, &value);
- krb5_data_free(&key);
- 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 (ret == ASN1_BAD_ID) {
- hdb_entry_alias alias;
-
- ret = hdb_value2entry_alias(context, &value, &alias);
- if (ret) {
+ ret = hdb_principal2key(context, principal, &key);
+ if (ret == 0)
+ ret = db->hdb__get(context, db, key, &value);
+ if (ret == 0)
+ ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
+ if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) {
+ *entry = eoa.u.entry;
+ entry->aliased = 0;
+ } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) {
+ krb5_data_free(&key);
+ ret = hdb_principal2key(context, eoa.u.alias.principal, &key);
+ if (ret == 0) {
krb5_data_free(&value);
- return ret;
+ ret = db->hdb__get(context, db, key, &value);
}
- hdb_principal2key(context, alias.principal, &key);
- krb5_data_free(&value);
- free_hdb_entry_alias(&alias);
+ if (ret == 0)
+ /* No alias chaining */
+ ret = hdb_value2entry(context, &value, entry);
+ krb5_free_principal(context, eoa.u.alias.principal);
+ entry->aliased = 1;
+ } else if (ret == 0)
+ ret = ENOTSUP;
+ if (ret == 0 && enterprise_principal) {
+ /*
+ * Whilst Windows does not canonicalize enterprise principal names if
+ * the canonicalize flag is unset, the original specification in
+ * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
+ */
+ entry->flags.force_canonicalize = 1;
+ }
- ret = db->hdb__get(context, db, key, &value);
- krb5_data_free(&key);
- if (ret)
- return ret;
- ret = hdb_value2entry(context, &value, &entry->entry);
- if (ret) {
- krb5_data_free(&value);
- return ret;
- }
+#if 0
+ /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
+ if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
+ (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) {
+
+ /* `principal' was alias but canon not req'd */
+ free_HDB_entry(entry);
+ ret = HDB_ERR_NOENTRY;
}
+#endif
+
+ krb5_free_principal(context, enterprise_principal);
krb5_data_free(&value);
+ krb5_data_free(&key);
+ principal = enterprise_principal = NULL;
+ return ret;
+}
+
+/*
+ * We have only one type of aliases in our HDB entries, but we really need two:
+ * hard and soft.
+ *
+ * Hard aliases should be treated as if they were distinct principals with the
+ * same keys.
+ *
+ * Soft aliases should be treated as configuration to issue referrals, and they
+ * can only result in referrals to other realms.
+ *
+ * Rather than add a type of aliases, we'll use a convention where the form of
+ * the target of the alias indicates whether the alias is hard or soft.
+ *
+ * TODO We could also use an attribute of the aliased entry.
+ */
+static int
+is_soft_alias_p(krb5_context context,
+ krb5_const_principal principal,
+ unsigned int flags,
+ hdb_entry *h)
+{
+ /* Target is a WELLKNOWN/REFERRALS/TARGET/... -> soft alias */
+ if (krb5_principal_get_num_comp(context, h->principal) >= 3 &&
+ strcmp(krb5_principal_get_comp_string(context, h->principal, 0),
+ KRB5_WELLKNOWN_NAME) == 0 &&
+ strcmp(krb5_principal_get_comp_string(context, h->principal, 1),
+ "REFERRALS") == 0 &&
+ strcmp(krb5_principal_get_comp_string(context, h->principal, 2),
+ "TARGET") == 0)
+ return 1;
+
+ /*
+ * Pre-8.0 we had only soft aliases for a while, and one site used aliases
+ * of referrals-targetNN@TARGET-REALM.
+ */
+ if (krb5_principal_get_num_comp(context, h->principal) == 1 &&
+ strncmp("referrals-target",
+ krb5_principal_get_comp_string(context, h->principal, 0),
+ sizeof("referrals-target") - 1) == 0)
+ return 1;
+
+ /* All other cases are hard aliases */
+ return 0;
+}
+
+krb5_error_code
+_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
+ unsigned flags, krb5_kvno kvno, hdb_entry *entry)
+{
+ krb5_error_code ret;
+ int soft_aliased = 0;
+ int same_realm;
+
+ ret = fetch_entry_or_alias(context, db, principal, flags, entry);
+ if (ret)
+ return ret;
+
if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
/* Decrypt the current keys */
- ret = hdb_unseal_keys(context, db, &entry->entry);
+ ret = hdb_unseal_keys(context, db, entry);
if (ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
return ret;
}
/* Decrypt the key history too */
- ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry);
+ ret = hdb_unseal_keys_kvno(context, db, 0, flags, entry);
if (ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
return ret;
}
} else if ((flags & HDB_F_DECRYPT)) {
- if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) {
+ if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->kvno) {
/* Decrypt the current keys */
- ret = hdb_unseal_keys(context, db, &entry->entry);
+ ret = hdb_unseal_keys(context, db, entry);
if (ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
return ret;
}
} else {
@@ -183,15 +308,75 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
* 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);
+ ret = hdb_unseal_keys_kvno(context, db, kvno, flags, entry);
if (ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
return ret;
}
}
}
+ if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) {
+ /*
+ * Generate default salt for any principals missing one; note such
+ * principals could include those for which a random (non-password)
+ * key was generated, but given the salt will be ignored by a keytab
+ * client it doesn't hurt to include the default salt.
+ */
+ ret = add_default_salts(context, db, entry);
+ if (ret) {
+ hdb_free_entry(context, db, entry);
+ return ret;
+ }
+ }
- return 0;
+ if (!entry->aliased)
+ return 0;
+
+ soft_aliased = is_soft_alias_p(context, principal, flags, entry);
+
+ /* Never return HDB_ERR_WRONG_REALM to kadm5 or other non-KDC callers */
+ if ((flags & HDB_F_ADMIN_DATA))
+ return 0;
+
+ same_realm = krb5_realm_compare(context, principal, entry->principal);
+
+ if (entry->aliased && !soft_aliased) {
+ /*
+ * This is a hard alias. We'll make the entry's name be the same as
+ * the alias.
+ *
+ * Except, we allow for disabling this for same-realm aliases, mainly
+ * for our tests.
+ */
+ if (same_realm &&
+ krb5_config_get_bool_default(context, NULL, FALSE, "hdb",
+ "same_realm_aliases_are_soft", NULL))
+ return 0;
+
+ /* EPNs are always soft */
+ if (principal->name.name_type != KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ krb5_free_principal(context, entry->principal);
+ ret = krb5_copy_principal(context, principal, &entry->principal);
+ if (ret) {
+ hdb_free_entry(context, db, entry);
+ return ret;
+ }
+ }
+ return 0;
+ }
+
+ /* Same realm -> not a referral, therefore this is a hard alias */
+ if (same_realm) {
+ if (soft_aliased) {
+ /* Soft alias to the same realm?! No. */
+ hdb_free_entry(context, db, entry);
+ return HDB_ERR_NOENTRY;
+ }
+ return 0;
+ }
+
+ /* Not same realm && not hard alias */
+ return HDB_ERR_WRONG_REALM;
}
static krb5_error_code
@@ -216,7 +401,7 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
code = hdb_entry_get_aliases(&oldentry, &aliases);
if (code || aliases == NULL) {
- free_hdb_entry(&oldentry);
+ free_HDB_entry(&oldentry);
return code;
}
for (i = 0; i < aliases->aliases.len; i++) {
@@ -226,32 +411,34 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
if (code == 0) {
code = db->hdb__del(context, db, akey);
krb5_data_free(&akey);
+ if (code == HDB_ERR_NOENTRY)
+ code = 0;
}
if (code) {
- free_hdb_entry(&oldentry);
+ free_HDB_entry(&oldentry);
return code;
}
}
- free_hdb_entry(&oldentry);
+ free_HDB_entry(&oldentry);
return 0;
}
static krb5_error_code
hdb_add_aliases(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry)
+ unsigned flags, hdb_entry *entry)
{
const HDB_Ext_Aliases *aliases;
krb5_error_code code;
krb5_data key, value;
size_t i;
- code = hdb_entry_get_aliases(&entry->entry, &aliases);
+ code = hdb_entry_get_aliases(entry, &aliases);
if (code || aliases == NULL)
return code;
for (i = 0; i < aliases->aliases.len; i++) {
hdb_entry_alias entryalias;
- entryalias.principal = entry->entry.principal;
+ entryalias.principal = entry->principal;
code = hdb_entry_alias2value(context, &entryalias, &value);
if (code)
@@ -261,6 +448,12 @@ hdb_add_aliases(krb5_context context, HDB *db,
if (code == 0) {
code = db->hdb__put(context, db, flags, key, value);
krb5_data_free(&key);
+ if (code == HDB_ERR_EXISTS)
+ /*
+ * Assuming hdb_check_aliases() was called, this must be a
+ * duplicate in the alias list.
+ */
+ code = 0;
}
krb5_data_free(&value);
if (code)
@@ -269,57 +462,116 @@ hdb_add_aliases(krb5_context context, HDB *db,
return 0;
}
+/* Check if new aliases are already used for other entries */
static krb5_error_code
-hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
+hdb_check_aliases(krb5_context context, HDB *db, hdb_entry *entry)
{
- const HDB_Ext_Aliases *aliases;
- int code;
+ const HDB_Ext_Aliases *aliases = NULL;
+ HDB_EntryOrAlias eoa;
+ krb5_data akey, value;
size_t i;
+ int ret;
- /* check if new aliases already is used */
+ memset(&eoa, 0, sizeof(eoa));
+ krb5_data_zero(&value);
+ akey = value;
- code = hdb_entry_get_aliases(&entry->entry, &aliases);
- if (code)
- return code;
+ ret = hdb_entry_get_aliases(entry, &aliases);
+ for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) {
+ ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
+ if (ret == 0)
+ ret = db->hdb__get(context, db, akey, &value);
+ if (ret == 0)
+ ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
+ if (ret == 0 && eoa.element != choice_HDB_EntryOrAlias_entry &&
+ eoa.element != choice_HDB_EntryOrAlias_alias)
+ ret = ENOTSUP;
+ if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry)
+ /* New alias names an existing non-alias entry in the HDB */
+ ret = HDB_ERR_EXISTS;
+ if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias &&
+ !krb5_principal_compare(context, eoa.u.alias.principal,
+ entry->principal))
+ /* New alias names an existing alias of a different entry */
+ ret = HDB_ERR_EXISTS;
+ if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */
+ /* New alias is a name that doesn't exist in the HDB */
+ ret = 0;
- for (i = 0; aliases && i < aliases->aliases.len; i++) {
- hdb_entry_alias alias;
- krb5_data akey, value;
+ free_HDB_EntryOrAlias(&eoa);
+ krb5_data_free(&value);
+ krb5_data_free(&akey);
+ }
+ return ret;
+}
- 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)
- return code;
+/*
+ * Many HDB entries don't have `etypes' setup. Historically we use the
+ * enctypes of the selected keyset as the entry's supported enctypes, but that
+ * is problematic. By doing this at store time and, if need be, at fetch time,
+ * we can make sure to stop deriving supported etypes from keys in the long
+ * run. We also need kadm5/kadmin support for etypes. We'll use this function
+ * there to derive etypes when using a kadm5_principal_ent_t that lacks the new
+ * TL data for etypes.
+ */
+krb5_error_code
+hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys)
+{
+ krb5_error_code ret = 0;
+ size_t i, k, netypes;
+ HDB_extension *ext;
- code = hdb_value2entry_alias(context, &value, &alias);
- krb5_data_free(&value);
+ if (!base_keys &&
+ (ext = hdb_find_extension(e, choice_HDB_extension_data_hist_keys)))
+ base_keys = &ext->data.u.hist_keys;
- if (code == ASN1_BAD_ID)
- return HDB_ERR_EXISTS;
- else if (code)
- return code;
+ netypes = e->keys.len;
+ if (netypes == 0 && base_keys) {
+ /* There's no way that base_keys->val[i].keys.len == 0, but hey */
+ for (i = 0; netypes == 0 && i < base_keys->len; i++)
+ netypes = base_keys->val[i].keys.len;
+ }
+
+ if (netypes == 0)
+ return 0;
- code = krb5_principal_compare(context, alias.principal,
- entry->entry.principal);
- free_hdb_entry_alias(&alias);
- if (code == 0)
- return HDB_ERR_EXISTS;
+ if (e->etypes != NULL) {
+ free(e->etypes->val);
+ e->etypes->len = 0;
+ e->etypes->val = 0;
+ } else if ((e->etypes = calloc(1, sizeof(e->etypes[0]))) == NULL) {
+ ret = krb5_enomem(context);
+ }
+ if (ret == 0 &&
+ (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret) {
+ free(e->etypes);
+ e->etypes = 0;
+ return ret;
+ }
+ e->etypes->len = netypes;
+ for (i = 0; i < e->keys.len && i < netypes; i++)
+ e->etypes->val[i] = e->keys.val[i].key.keytype;
+ if (!base_keys || i)
+ return 0;
+ for (k = 0; i == 0 && k < base_keys->len; k++) {
+ if (!base_keys->val[k].keys.len)
+ continue;
+ for (; i < base_keys->val[k].keys.len; i++)
+ e->etypes->val[i] = base_keys->val[k].keys.val[i].key.keytype;
}
return 0;
}
krb5_error_code
-_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
krb5_data key, value;
int code;
- if (entry->entry.flags.do_not_store)
+ if (entry->flags.do_not_store ||
+ entry->flags.force_canonicalize)
return HDB_ERR_MISUSE;
/* check if new aliases already is used */
code = hdb_check_aliases(context, db, entry);
@@ -330,7 +582,7 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
return 0;
if ((flags & HDB_F_PRECHECK)) {
- code = hdb_principal2key(context, entry->entry.principal, &key);
+ code = hdb_principal2key(context, entry->principal, &key);
if (code)
return code;
code = db->hdb__get(context, db, key, &value);
@@ -342,25 +594,31 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
return code ? code : HDB_ERR_EXISTS;
}
- if(entry->entry.generation == NULL) {
+ if ((entry->etypes == NULL || entry->etypes->len == 0) &&
+ (code = hdb_derive_etypes(context, entry, NULL)))
+ return code;
+
+ if (entry->generation == NULL) {
struct timeval t;
- entry->entry.generation = malloc(sizeof(*entry->entry.generation));
- if(entry->entry.generation == NULL) {
+ entry->generation = malloc(sizeof(*entry->generation));
+ if(entry->generation == NULL) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
gettimeofday(&t, NULL);
- entry->entry.generation->time = t.tv_sec;
- entry->entry.generation->usec = t.tv_usec;
- entry->entry.generation->gen = 0;
+ entry->generation->time = t.tv_sec;
+ entry->generation->usec = t.tv_usec;
+ entry->generation->gen = 0;
} else
- entry->entry.generation->gen++;
+ entry->generation->gen++;
- code = hdb_seal_keys(context, db, &entry->entry);
+ code = hdb_seal_keys(context, db, entry);
if (code)
return code;
- hdb_principal2key(context, entry->entry.principal, &key);
+ code = hdb_principal2key(context, entry->principal, &key);
+ if (code)
+ return code;
/* remove aliases */
code = hdb_remove_aliases(context, db, &key);
@@ -368,8 +626,9 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
krb5_data_free(&key);
return code;
}
- hdb_entry2value(context, &entry->entry, &value);
- code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
+ code = hdb_entry2value(context, entry, &value);
+ if (code == 0)
+ code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
krb5_data_free(&value);
krb5_data_free(&key);
if (code)
@@ -385,35 +644,1264 @@ _hdb_remove(krb5_context context, HDB *db,
unsigned flags, krb5_const_principal principal)
{
krb5_data key, value;
+ HDB_EntryOrAlias eoa;
+ int is_alias = -1;
int code;
- hdb_principal2key(context, principal, &key);
+ /*
+ * We only allow deletion of entries by canonical name. To remove an
+ * alias use kadm5_modify_principal().
+ *
+ * We need to determine if this is an alias. We decode as a
+ * HDB_EntryOrAlias, which is expensive -- we could decode as a
+ * HDB_entry_alias instead and assume it's an entry if decoding fails...
+ */
+
+ code = hdb_principal2key(context, principal, &key);
+ if (code == 0)
+ code = db->hdb__get(context, db, key, &value);
+ if (code == 0) {
+ code = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL);
+ krb5_data_free(&value);
+ }
+ if (code == 0) {
+ is_alias = eoa.element == choice_HDB_EntryOrAlias_entry ? 0 : 1;
+ free_HDB_EntryOrAlias(&eoa);
+ }
if ((flags & HDB_F_PRECHECK)) {
+ if (code == 0 && is_alias)
+ krb5_set_error_message(context, code = HDB_ERR_NOENTRY,
+ "Cannot delete alias of principal");
+ krb5_data_free(&key);
+ return code;
+ }
+
+ if (code == 0)
+ code = hdb_remove_aliases(context, db, &key);
+ if (code == 0)
+ code = db->hdb__del(context, db, key);
+ krb5_data_free(&key);
+ return code;
+}
+
+/* PRF+(K_base, pad, keylen(etype)) */
+static krb5_error_code
+derive_Key1(krb5_context context,
+ krb5_data *pad,
+ EncryptionKey *base,
+ krb5int32 etype,
+ EncryptionKey *nk)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto = NULL;
+ krb5_data out;
+ size_t len;
+
+ out.data = 0;
+ out.length = 0;
+
+ ret = krb5_enctype_keysize(context, base->keytype, &len);
+ if (ret == 0)
+ ret = krb5_crypto_init(context, base, 0, &crypto);
+ if (ret == 0)
+ ret = krb5_crypto_prfplus(context, crypto, pad, len, &out);
+ if (crypto)
+ krb5_crypto_destroy(context, crypto);
+ if (ret == 0)
+ ret = krb5_random_to_key(context, etype, out.data, out.length, nk);
+ krb5_data_free(&out);
+ return ret;
+}
+
+/* PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) */
+/* XXX Make it PRF+(PRF+(K_base, princ, keylen(K_base.etype)), and lift it, kvno, keylen(etype)) */
+static krb5_error_code
+derive_Key(krb5_context context,
+ const char *princ,
+ krb5uint32 kvno,
+ EncryptionKey *base,
+ krb5int32 etype,
+ Key *nk)
+{
+ krb5_error_code ret = 0;
+ EncryptionKey intermediate;
+ krb5_data pad;
+
+ nk->salt = NULL;
+ nk->mkvno = NULL;
+ nk->key.keytype = 0;
+ nk->key.keyvalue.data = 0;
+ nk->key.keyvalue.length = 0;
+
+ intermediate.keytype = 0;
+ intermediate.keyvalue.data = 0;
+ intermediate.keyvalue.length = 0;
+ if (princ) {
+ /* Derive intermediate key for the given principal */
+ /* XXX Lift to optimize? */
+ pad.data = (void *)(uintptr_t)princ;
+ pad.length = strlen(princ);
+ ret = derive_Key1(context, &pad, base, etype, &intermediate);
+ if (ret == 0)
+ base = &intermediate;
+ } /* else `base' is already an intermediate key for the desired princ */
+
+ /* Derive final key for `kvno' from intermediate key */
+ kvno = htonl(kvno);
+ pad.data = &kvno;
+ pad.length = sizeof(kvno);
+ if (ret == 0)
+ ret = derive_Key1(context, &pad, base, etype, &nk->key);
+ free_EncryptionKey(&intermediate);
+ return ret;
+}
+
+/*
+ * PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) for one
+ * enctype.
+ */
+static krb5_error_code
+derive_Keys(krb5_context context,
+ const char *princ,
+ krb5uint32 kvno,
+ krb5int32 etype,
+ const Keys *base,
+ Keys *dk)
+
+{
+ krb5_error_code ret = 0;
+ size_t i;
+ Key nk;
+
+ dk->len = 0;
+ dk->val = 0;
+
+ /*
+ * The enctypes of the base keys is the list of enctypes to derive keys
+ * for. Still, we derive all keys from the first base key.
+ */
+ for (i = 0; ret == 0 && i < base->len; i++) {
+ if (etype != KRB5_ENCTYPE_NULL && etype != base->val[i].key.keytype)
+ continue;
+ ret = derive_Key(context, princ, kvno, &base->val[0].key,
+ base->val[i].key.keytype, &nk);
+ if (ret)
+ break;
+ ret = add_Keys(dk, &nk);
+ free_Key(&nk);
/*
- * 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.
+ * FIXME We need to finish kdc/kadm5/kadmin support for the `etypes' so
+ * we can reduce the number of keys in keytabs to just those in current
+ * use and only of *one* enctype.
+ *
+ * What we could do is derive *one* key and for the others output a
+ * one-byte key of the intended enctype (which will never work).
+ *
+ * We'll never need any keys but the first one...
*/
- code = db->hdb__get(context, db, key, &value);
- krb5_data_free(&key);
- if (code == 0) {
- krb5_data_free(&value);
+ }
+
+ if (ret)
+ free_Keys(dk);
+ return ret;
+}
+
+/* Helper for derive_keys_for_kr() */
+static krb5_error_code
+derive_keyset(krb5_context context,
+ const Keys *base_keys,
+ const char *princ,
+ krb5int32 etype,
+ krb5uint32 kvno,
+ KerberosTime set_time, /* "now" */
+ hdb_keyset *dks)
+{
+ dks->kvno = kvno;
+ dks->keys.val = 0;
+ dks->set_time = malloc(sizeof(*(dks->set_time)));
+ if (dks->set_time == NULL)
+ return krb5_enomem(context);
+ *dks->set_time = set_time;
+ return derive_Keys(context, princ, kvno, etype, base_keys, &dks->keys);
+}
+
+/* Possibly derive and install in `h' a keyset identified by `t' */
+static krb5_error_code
+derive_keys_for_kr(krb5_context context,
+ hdb_entry *h,
+ HDB_Ext_KeySet *base_keys,
+ int is_current_keyset,
+ int rotation_period_offset,
+ const char *princ,
+ krb5int32 etype,
+ krb5uint32 kvno_wanted,
+ KerberosTime t,
+ struct KeyRotation *krp)
+{
+ krb5_error_code ret;
+ hdb_keyset dks;
+ KerberosTime set_time, n;
+ krb5uint32 kvno;
+ size_t i;
+
+ if (rotation_period_offset < -1 || rotation_period_offset > 1)
+ return EINVAL; /* wat */
+
+ /*
+ * Compute `kvno' and `set_time' given `t' and `krp'.
+ *
+ * There be signed 32-bit time_t dragons here.
+ *
+ * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more
+ * tolerant of signed 32-bit time_t here near 2038. Of course, we have
+ * signed 32-bit time_t dragons elsewhere.
+ *
+ * We don't need to check for n == 0 && rotation_period_offset < 0 because
+ * only derive_keys_for_current_kr() calls us with non-zero rotation period
+ * offsets, and it will never call us in that case.
+ */
+ if (t - krp->epoch < 0)
+ return 0; /* This KR is not relevant yet */
+ n = (t - krp->epoch) / krp->period;
+ n += rotation_period_offset;
+ set_time = krp->epoch + krp->period * n;
+ kvno = krp->base_kvno + n;
+
+ /*
+ * Since this principal is virtual, or has virtual keys, we're going to
+ * derive a "password expiration time" for it in order to help httpkadmind
+ * and other tools figure out when to request keys again.
+ *
+ * The kadm5 representation of principals does not include the set_time of
+ * keys/keysets, so we can't have httpkadmind derive a Cache-Control from
+ * that without adding yet another "TL data". Since adding TL data is a
+ * huge pain, we'll just use the `pw_end' field of `HDB_entry' to
+ * communicate when this principal's keys will change next.
+ */
+ if (h->pw_end[0] == 0) {
+ KerberosTime used = (t - krp->epoch) % krp->period;
+ KerberosTime left = krp->period - used;
+
+ /*
+ * If `h->pw_end[0]' == 0 then this must be the current period of the
+ * current KR we're deriving keys for. See upstairs.
+ *
+ * If there's more than a quarter of this time period left, then we'll
+ * set `h->pw_end[0]' to one quarter before the end of this time
+ * period. Else we'll set it to 1/4 after (we'll be including the next
+ * set of derived keys, so there's no harm in waiting that long to
+ * refetch).
+ */
+ if (left > krp->period >> 2)
+ h->pw_end[0] = set_time + krp->period - (krp->period >> 2);
+ else
+ h->pw_end[0] = set_time + krp->period + (krp->period >> 2);
+ }
+
+
+ /*
+ * Do not waste cycles computing keys not wanted or needed.
+ * A past kvno is too old if its set_time + rotation period is in the past
+ * by more than half a rotation period, since then no service ticket
+ * encrypted with keys of that kvno can still be extant.
+ *
+ * A future kvno is not coming up soon enough if we're more than a quarter
+ * of the rotation period away from it.
+ *
+ * Recall: the assumption for virtually-keyed principals is that services
+ * fetch their future keys frequently enough that they'll never miss having
+ * the keys they need.
+ */
+ if (!is_current_keyset || rotation_period_offset != 0) {
+ if ((kvno_wanted && kvno != kvno_wanted) ||
+ t - (set_time + krp->period + (krp->period >> 1)) > 0 ||
+ (set_time - t > 0 && (set_time - t) > (krp->period >> 2)))
return 0;
+ }
+
+ for (i = 0; i < base_keys->len; i++) {
+ if (base_keys->val[i].kvno == krp->base_key_kvno)
+ break;
+ }
+ if (i == base_keys->len) {
+ /* Base key not found! */
+ if (kvno_wanted || is_current_keyset) {
+ krb5_set_error_message(context, ret = HDB_ERR_KVNO_NOT_FOUND,
+ "Base key version %u not found for %s",
+ krp->base_key_kvno, princ);
+ return ret;
}
- return code;
+ return 0;
}
- code = hdb_remove_aliases(context, db, &key);
- if (code) {
- krb5_data_free(&key);
- return code;
+ ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno,
+ set_time, &dks);
+ if (ret == 0)
+ ret = hdb_install_keyset(context, h, is_current_keyset, &dks);
+
+ free_HDB_keyset(&dks);
+ return ret;
+}
+
+/* Derive and install current keys, and possibly preceding or next keys */
+static krb5_error_code
+derive_keys_for_current_kr(krb5_context context,
+ hdb_entry *h,
+ HDB_Ext_KeySet *base_keys,
+ const char *princ,
+ unsigned int flags,
+ krb5int32 etype,
+ krb5uint32 kvno_wanted,
+ KerberosTime t,
+ struct KeyRotation *krp,
+ KerberosTime future_epoch)
+{
+ krb5_error_code ret;
+
+ /* derive_keys_for_kr() for current kvno and install as the current keys */
+ ret = derive_keys_for_kr(context, h, base_keys, 1, 0, princ, etype,
+ kvno_wanted, t, krp);
+ if (!(flags & HDB_F_ALL_KVNOS))
+ return ret;
+
+ /* */
+
+
+ /*
+ * derive_keys_for_kr() for prev kvno if still needed -- it can only be
+ * needed if the prev kvno's start time is within this KR's epoch.
+ *
+ * Note that derive_keys_for_kr() can return without doing anything if this
+ * is isn't the current keyset. So these conditions need not be
+ * sufficiently narrow.
+ */
+ if (ret == 0 && t - krp->epoch >= krp->period)
+ ret = derive_keys_for_kr(context, h, base_keys, 0, -1, princ, etype,
+ kvno_wanted, t, krp);
+ /*
+ * derive_keys_for_kr() for next kvno if near enough, but only if it
+ * doesn't start after the next KR's epoch.
+ */
+ if (future_epoch &&
+ t - krp->epoch >= 0 /* We know! Hint to the compiler */) {
+ KerberosTime next_kvno_start, n;
+
+ n = (t - krp->epoch) / krp->period;
+ next_kvno_start = krp->epoch + krp->period * (n + 1);
+ if (future_epoch - next_kvno_start <= 0)
+ return ret;
}
- code = db->hdb__del(context, db, key);
- krb5_data_free(&key);
- return code;
+ if (ret == 0)
+ ret = derive_keys_for_kr(context, h, base_keys, 0, 1, princ, etype,
+ kvno_wanted, t, krp);
+ return ret;
+}
+
+/*
+ * Derive and install all keysets in `h' that `princ' needs at time `now'.
+ *
+ * This mutates the entry `h' to
+ *
+ * a) not have base keys,
+ * b) have keys derived from the base keys according to
+ * c) the key rotation periods for the base principal (possibly the same
+ * principal if it's a concrete principal with virtual keys), and the
+ * requested time, enctype, and kvno (all of which are optional, with zero
+ * implying some default).
+ *
+ * Arguments:
+ *
+ * - `flags' is the flags passed to `hdb_fetch_kvno()'
+ * - `princ' is the name of the principal we'll end up with in `entry'
+ * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete
+ * principal (that might nonetheless have virtual/derived keys)
+ * - `t' is the time such that the derived keys are for kvnos needed at `t'
+ * - `etype' indicates what enctype to derive keys for (0 for all enctypes in
+ * `entry->etypes')
+ * - `kvno' requests a particular kvno, or all if zero
+ *
+ * The caller doesn't know if the principal needs key derivation -- we make
+ * that determination in this function.
+ *
+ * Note that this function is fully deterministic for any given set of
+ * arguments and HDB contents.
+ *
+ * Definitions:
+ *
+ * - A keyset is a set of keys for a single kvno.
+ * - A keyset is relevant IFF:
+ * - it is the keyset for a time period identified by `t' in a
+ * corresponding KR
+ * - it is a keyset for a past time period for which there may be extant,
+ * not-yet-expired tickets that a service may need to decrypt
+ * - it is a keyset for an upcoming time period that a service will need to
+ * fetch before that time period becomes current, that way the service
+ * can have keytab entries for those keys in time for when the KDC starts
+ * encrypting service tickets to those keys
+ *
+ * This function derives the keyset(s) for the current KR first. The idea is
+ * to optimize the order of resulting keytabs so that the most likely keys to
+ * be used come first.
+ *
+ * Invariants:
+ *
+ * - KR metadata is sane because sanity is checked for when storing HDB
+ * entries
+ * - KRs are sorted by epoch in descending order; KR #0's epoch is the most
+ * recent
+ * - KR periods are non-zero (we divide by period)
+ * - kvnos are numerically ordered and correspond to time periods
+ * - within each KR, the kvnos for larger times are larger than (or equal
+ * to) the kvnos of earlier times
+ * - at KR boundaries, the first kvno of the newer boundary is larger than
+ * the kvno of the last time period of the previous KR
+ * - the time `t' must fall into exactly one KR period
+ * - the time `t' must fall into exactly one period within a KR period
+ * - at most two kvnos will be relevant from the KR that `t' falls into
+ * (the current kvno for `t', and possibly either the preceding, or the
+ * next)
+ * - at most one kvno from non-current KRs will be derived: possibly one for a
+ * preceding KR, and possibly one from an upcoming KR
+ *
+ * There can be:
+ *
+ * - no KR extension (not a namespace principal, and no virtual keys)
+ * - 1, 2, or 3 KRs (see above)
+ * - the newest KR may have the `deleted' flag, meaning "does not exist after
+ * this epoch"
+ *
+ * Note that the last time period in any older KR can be partial.
+ *
+ * Timeline diagram:
+ *
+ * .......|--+--+...+--|---+---+---+...+--|----+...
+ * T20 T10 T11 RT12 T1n T01
+ * ^ ^ ^ ^ ^ ^ ^ T00
+ * | | | T22 T2n | | ^
+ * ^ | T21 | | |
+ * princ | | epoch of | epoch of
+ * did | | middle KR | newest epoch
+ * not | | |
+ * exist! | start of Note that T1n
+ * | second kvno is shown as shorter
+ * | in 1st epoch than preceding periods
+ * |
+ * ^
+ * first KR's
+ * epoch, and start
+ * of its first kvno
+ *
+ * Tmn == the start of the Mth KR's Nth time period.
+ * (higher M -> older KR; lower M -> newer KR)
+ * (N is the reverse: lower N -> older time period in KR)
+ * T20 == start of oldest KR -- no keys before this time will be derived.
+ * T2n == last time period in oldest KR
+ * T10 == start of middle KR
+ * T1n == last time period in middle KR
+ * T00 == start of newest KR
+ * T0n == current time period in newest KR for wall clock time
+ */
+static krb5_error_code
+derive_keys(krb5_context context,
+ unsigned flags,
+ krb5_const_principal princ,
+ int h_is_namespace,
+ krb5_timestamp t,
+ krb5int32 etype,
+ krb5uint32 kvno,
+ hdb_entry *h)
+{
+ HDB_Ext_KeyRotation kr;
+ HDB_Ext_KeySet base_keys;
+ krb5_error_code ret = 0;
+ size_t current_kr, future_kr, past_kr, i;
+ char *p = NULL;
+ int valid = 1;
+
+ if (!h_is_namespace && !h->flags.virtual_keys)
+ return 0;
+ h->flags.virtual = 1;
+
+ kr.len = 0;
+ kr.val = 0;
+ if (ret == 0) {
+ const HDB_Ext_KeyRotation *ckr;
+
+ /* Installing keys invalidates `ckr', so we copy it */
+ ret = hdb_entry_get_key_rotation(context, h, &ckr);
+ if (!ckr)
+ return ret;
+ if (ret == 0)
+ ret = copy_HDB_Ext_KeyRotation(ckr, &kr);
+ }
+
+ /* Get the base keys from the entry, and remove them */
+ base_keys.val = 0;
+ base_keys.len = 0;
+ if (ret == 0)
+ ret = _hdb_remove_base_keys(context, h, &base_keys, &kr);
+
+ /* Make sure we have h->etypes */
+ if (ret == 0 && !h->etypes)
+ ret = hdb_derive_etypes(context, h, &base_keys);
+
+ /* Keys not desired? Don't derive them! */
+ if (ret || !(flags & HDB_F_DECRYPT)) {
+ free_HDB_Ext_KeyRotation(&kr);
+ free_HDB_Ext_KeySet(&base_keys);
+ return ret;
+ }
+
+ /* The principal name will be used in key derivation and error messages */
+ if (ret == 0)
+ ret = krb5_unparse_name(context, princ, &p);
+
+ /* Sanity check key rotations, determine current & last kr */
+ if (ret == 0 && kr.len < 1)
+ krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
+ "no key rotation periods for %s", p);
+ if (ret == 0)
+ current_kr = future_kr = past_kr = kr.len;
+ else
+ current_kr = future_kr = past_kr = 1;
+
+ /*
+ * Identify a current, next, and previous KRs if there are any.
+ *
+ * There can be up to three KRs, ordered by epoch, descending, making up a
+ * timeline like:
+ *
+ * ...|---------|--------|------>
+ * ^ | | |
+ * | | | |
+ * | | | Newest KR (kr.val[0])
+ * | | Middle KR (kr.val[1])
+ * | Oldest (last) KR (kr.val[2])
+ * |
+ * Before the begging of time for this namespace
+ *
+ * We step through these from future towards past looking for the best
+ * future, current, and past KRs. The best current KR is one that has its
+ * epoch nearest to `t' but in the past of `t'.
+ *
+ * We validate KRs before storing HDB entries with the KR extension, so we
+ * can assume they are valid here. However, we do some validity checking,
+ * and if they're not valid, we pick the best current KR and ignore the
+ * others.
+ *
+ * In principle there cannot be two future KRs, but this function is
+ * deterministic and takes a time value, so it should not enforce this just
+ * so we can test. Enforcement of such rules should be done at store time.
+ */
+ for (i = 0; ret == 0 && i < kr.len; i++) {
+ /* Minimal validation: order and period */
+ if (i && kr.val[i - 1].epoch - kr.val[i].epoch <= 0) {
+ future_kr = past_kr = kr.len;
+ valid = 0;
+ }
+ if (!kr.val[i].period) {
+ future_kr = past_kr = kr.len;
+ valid = 0;
+ continue;
+ }
+ if (t - kr.val[i].epoch >= 0) {
+ /*
+ * `t' is in the future of this KR's epoch, so it's a candidate for
+ * either current or past KR.
+ */
+ if (current_kr == kr.len)
+ current_kr = i; /* First curr KR candidate; should be best */
+ else if (kr.val[current_kr].epoch - kr.val[i].epoch < 0)
+ current_kr = i; /* Invalid KRs, but better curr KR cand. */
+ else if (valid && past_kr == kr.len)
+ past_kr = i;
+ } else if (valid) {
+ /* This KR is in the future of `t', a candidate for next KR */
+ future_kr = i;
+ }
+ }
+ if (ret == 0 && current_kr == kr.len)
+ /* No current KR -> too soon */
+ krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
+ "Too soon for virtual principal to exist");
+
+ /* Check that the principal has not been marked deleted */
+ if (ret == 0 && current_kr < kr.len && kr.val[current_kr].flags.deleted)
+ krb5_set_error_message(context, ret = HDB_ERR_NOENTRY,
+ "virtual principal %s does not exist "
+ "because last key rotation period "
+ "marks deletion", p);
+
+ /* See `derive_keys_for_kr()' */
+ if (h->pw_end == NULL &&
+ (h->pw_end = calloc(1, sizeof(h->pw_end[0]))) == NULL)
+ ret = krb5_enomem(context);
+
+ /*
+ * Derive and set in `h' its current kvno and current keys.
+ *
+ * This will set h->kvno as well.
+ *
+ * This may set up to TWO keysets for the current key rotation period:
+ * - current keys (h->keys and h->kvno)
+ * - possibly one future
+ * OR
+ * possibly one past keyset in hist_keys for the current_kr
+ */
+ if (ret == 0 && current_kr < kr.len)
+ ret = derive_keys_for_current_kr(context, h, &base_keys, p, flags,
+ etype, kvno, t, &kr.val[current_kr],
+ current_kr ? kr.val[0].epoch : 0);
+
+ /*
+ * Derive and set in `h' its future keys for next KR if it is soon to be
+ * current.
+ *
+ * We want to derive keys for the first kvno of the next (future) KR if
+ * it's sufficiently close to `t', meaning within 1 period of the current
+ * KR, but we want these keys to be available sooner, so 1.5 of the current
+ * period.
+ */
+ if (ret == 0 && future_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
+ ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
+ kr.val[future_kr].epoch, &kr.val[future_kr]);
+
+ /*
+ * Derive and set in `h' its past keys for the previous KR if its last time
+ * period could still have extant, unexpired service tickets encrypted in
+ * its keys.
+ */
+ if (ret == 0 && past_kr < kr.len && (flags & HDB_F_ALL_KVNOS))
+ ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno,
+ kr.val[current_kr].epoch - 1, &kr.val[past_kr]);
+
+ /*
+ * Impose a bound on h->max_life so that [when the KDC is the caller]
+ * the KDC won't issue tickets longer lived than this.
+ */
+ if (ret == 0 && !h->max_life &&
+ (h->max_life = calloc(1, sizeof(h->max_life[0]))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1)
+ *h->max_life = kr.val[current_kr].period >> 1;
+
+ if (ret == 0 && h->pw_end[0] == 0)
+ /* Shouldn't happen */
+ h->pw_end[0] = kr.val[current_kr].epoch +
+ kr.val[current_kr].period *
+ (1 + (t - kr.val[current_kr].epoch) / kr.val[current_kr].period);
+
+ free_HDB_Ext_KeyRotation(&kr);
+ free_HDB_Ext_KeySet(&base_keys);
+ free(p);
+ return ret;
}
+/*
+ * Pick a best kvno for the given principal at the given time.
+ *
+ * Implements the [hdb] new_service_key_delay configuration parameter.
+ *
+ * In order for disparate keytab provisioning systems such as OSKT and our own
+ * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able
+ * to force keys set by the former to not become current keys until users of
+ * the latter have had a chance to fetch those keys into their keytabs. To do
+ * this we have to search the list of keys in the entry looking for the newest
+ * keys older than `now - db->new_service_key_delay'.
+ *
+ * The context is that OSKT's krb5_keytab is very happy to change keys in a way
+ * that requires all members of a cluster to rekey together. If one also
+ * wishes to have cluster members that opt out of this and just fetch current,
+ * past, and future keys periodically, then the keys set by OSKT must not come
+ * into effect until all the opt-out members have had a chance to fetch the new
+ * keys.
+ *
+ * The assumption is that services will fetch new keys periodically, say, every
+ * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the
+ * configuration and new keys set by OSKT will not be used until 8h after they
+ * are set.
+ *
+ * Naturally, this applies only to concrete principals with concrete keys.
+ */
+static krb5_error_code
+pick_kvno(krb5_context context,
+ HDB *db,
+ unsigned flags,
+ krb5_timestamp now,
+ krb5uint32 kvno,
+ hdb_entry *h)
+{
+ HDB_extension *ext;
+ HDB_Ext_KeySet keys;
+ time_t current = 0;
+ time_t best;
+ size_t i;
+
+ /*
+ * If we want a specific kvno, or if the caller doesn't want new keys
+ * delayed, or if there's no new-key delay configured, or we're not
+ * fetching for use as a service principal, then we're out.
+ */
+ if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->flags.virtual ||
+ h->flags.virtual_keys || db->new_service_key_delay <= 0)
+ return 0;
+
+ /* No history -> current keyset is the only one and therefore the best */
+ ext = hdb_find_extension(h, choice_HDB_extension_data_hist_keys);
+ if (!ext)
+ return 0;
+
+ /* Assume the current keyset is the best to start with */
+ (void) hdb_entry_get_pw_change_time(h, &current);
+ if (current == 0 && h->modified_by)
+ current = h->modified_by->time;
+ if (current == 0)
+ current = h->created_by.time;
+
+ /* Current keyset starts out as best */
+ best = current;
+ kvno = h->kvno;
+
+ /* Look for a better keyset in the history */
+ keys = ext->data.u.hist_keys;
+ for (i = 0; i < keys.len; i++) {
+ /* No set_time? Ignore. Too new? Ignore */
+ if (!keys.val[i].set_time ||
+ keys.val[i].set_time[0] + db->new_service_key_delay > now)
+ continue;
+
+ /*
+ * Ignore the keyset with kvno 1 when the entry has better kvnos
+ * because kadmin's `ank -r' command immediately changes the keys.
+ */
+ if (kvno > 1 && keys.val[i].kvno == 1)
+ continue;
+
+ /*
+ * This keyset's set_time older than the previous best? Ignore.
+ * However, if the current best is the entry's current and that one
+ * is too new, then don't ignore this one.
+ */
+ if (keys.val[i].set_time[0] < best &&
+ (best != current || current + db->new_service_key_delay < now))
+ continue;
+
+ /*
+ * If two good enough keysets have the same set_time, take the keyset
+ * with the highest kvno.
+ */
+ if (keys.val[i].set_time[0] == best && keys.val[i].kvno <= kvno)
+ continue;
+
+ /*
+ * This keyset is clearly more current than the previous best keyset
+ * but still old enough to use for encrypting tickets with.
+ */
+ best = keys.val[i].set_time[0];
+ kvno = keys.val[i].kvno;
+ }
+ return hdb_change_kvno(context, kvno, h);
+}
+
+/*
+ * Make a WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname} or
+ * WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname}/${domainname} principal
+ * object, with the service and hostname components take from `wanted', but if
+ * the service name is not in the list `db->virtual_hostbased_princ_svcs[]'
+ * then use "_" (wildcard) instead. This way we can have different attributes
+ * for different services in the same namespaces.
+ *
+ * For example, virtual hostbased service names for the "host" service might
+ * have ok-as-delegate set, but ones for the "HTTP" service might not.
+ */
+static krb5_error_code
+make_namespace_princ(krb5_context context,
+ HDB *db,
+ krb5_const_principal wanted,
+ krb5_principal *namespace)
+{
+ krb5_error_code ret = 0;
+ const char *realm = krb5_principal_get_realm(context, wanted);
+ const char *comp0 = krb5_principal_get_comp_string(context, wanted, 0);
+ const char *comp1 = krb5_principal_get_comp_string(context, wanted, 1);
+ const char *comp2 = krb5_principal_get_comp_string(context, wanted, 2);
+ char * const *svcs = db->virtual_hostbased_princ_svcs;
+ size_t i;
+
+ *namespace = NULL;
+ if (comp0 == NULL || comp1 == NULL)
+ return EINVAL;
+ if (strcmp(comp0, "krbtgt") == 0)
+ return 0;
+
+ for (i = 0; svcs && svcs[i]; i++) {
+ if (strcmp(comp0, svcs[i]) == 0) {
+ comp0 = svcs[i];
+ break;
+ }
+ }
+ if (!svcs || !svcs[i])
+ comp0 = "_";
+
+ /* First go around, need a namespace princ. Make it! */
+ ret = krb5_build_principal(context, namespace, strlen(realm),
+ realm, KRB5_WELLKNOWN_NAME,
+ HDB_WK_NAMESPACE, comp0, NULL);
+ if (ret == 0)
+ ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1);
+ if (ret == 0 && comp2)
+ /* Support domain-based names */
+ ret = krb5_principal_set_comp_string(context, *namespace, 4, comp2);
+ /* Caller frees `*namespace' on error */
+ return ret;
+}
+
+static int
+is_namespace_princ_p(krb5_context context,
+ krb5_const_principal princ)
+{
+ return
+ krb5_principal_get_num_comp(context, princ) >= 4
+ && strcmp(krb5_principal_get_comp_string(context, princ, 0),
+ KRB5_WELLKNOWN_NAME) == 0
+ && strcmp(krb5_principal_get_comp_string(context, princ, 1),
+ HDB_WK_NAMESPACE) == 0;
+}
+
+/* See call site */
+static krb5_error_code
+rewrite_hostname(krb5_context context,
+ krb5_const_principal wanted_princ,
+ krb5_const_principal ns_princ,
+ krb5_const_principal found_ns_princ,
+ char **s)
+{
+ const char *ns_host_part, *wanted_host_part, *found_host_part;
+ const char *p, *r;
+ size_t ns_host_part_len, wanted_host_part_len;
+
+ wanted_host_part = krb5_principal_get_comp_string(context, wanted_princ, 1);
+ wanted_host_part_len = strlen(wanted_host_part);
+ if (wanted_host_part_len > 256) {
+ krb5_set_error_message(context, HDB_ERR_NOENTRY,
+ "Aliases of host-based principals longer than "
+ "256 bytes not supported");
+ return HDB_ERR_NOENTRY;
+ }
+
+ ns_host_part = krb5_principal_get_comp_string(context, ns_princ, 3);
+ ns_host_part_len = strlen(ns_host_part);
+
+ /* Find `ns_host_part' as the tail of `wanted_host_part' */
+ for (r = p = strstr(wanted_host_part, ns_host_part);
+ r && strnlen(r, ns_host_part_len + 1) > ns_host_part_len;
+ p = (r = strstr(r, ns_host_part)) ? r : p)
+ ;
+ if (!p || strnlen(p, ns_host_part_len + 1) != ns_host_part_len)
+ return HDB_ERR_NOENTRY; /* Can't happen */
+ if (p == wanted_host_part || p[-1] != '.')
+ return HDB_ERR_NOENTRY;
+
+ found_host_part =
+ krb5_principal_get_comp_string(context, found_ns_princ, 3);
+ return
+ asprintf(s, "%.*s%s", (int)(p - wanted_host_part), wanted_host_part,
+ found_host_part) < 0 ||
+ *s == NULL ? krb5_enomem(context) : 0;
+}
+
+/*
+ * Fix `h->principal' to match the desired `princ' in the namespace
+ * `nsprinc' (which is either the same as `h->principal' or an alias
+ * of it).
+ */
+static krb5_error_code
+fix_princ_name(krb5_context context,
+ krb5_const_principal princ,
+ krb5_const_principal nsprinc,
+ hdb_entry *h)
+{
+ krb5_error_code ret = 0;
+ char *s = NULL;
+
+ if (!nsprinc)
+ return 0;
+ if (krb5_principal_get_num_comp(context, princ) < 2)
+ return HDB_ERR_NOENTRY;
+
+ /* `nsprinc' must be a namespace principal */
+
+ if (krb5_principal_compare(context, nsprinc, h->principal)) {
+ /*
+ * `h' is the HDB entry for `nsprinc', and `nsprinc' is its canonical
+ * name.
+ *
+ * Set the entry's principal name to the desired name. The keys will
+ * be fixed next (upstairs, but don't forget to!).
+ */
+ free_Principal(h->principal);
+ return copy_Principal(princ, h->principal);
+ }
+
+ if (!is_namespace_princ_p(context, h->principal)) {
+ /*
+ * The alias is a namespace, but the canonical name is not. WAT.
+ *
+ * Well, the KDC will just issue a referral anyways, so we can leave
+ * `h->principal' as is...
+ *
+ * Remove all of `h's keys just in case, and leave
+ * `h->principal' as-is.
+ */
+ free_Keys(&h->keys);
+ (void) hdb_entry_clear_password(context, h);
+ return hdb_clear_extension(context, h,
+ choice_HDB_extension_data_hist_keys);
+ }
+
+ /*
+ * A namespace alias of a namespace entry.
+ *
+ * We'll want to rewrite the original principal accordingly.
+ *
+ * E.g., if the caller wanted host/foo.ns.test.h5l.se and we
+ * found WELLKNOWN/HOSTBASED-NAMESPACE/ns.test.h5l.se is an
+ * alias of WELLKNOWN/HOSTBASED-NAMESPACE/ns.example.org, then
+ * we'll want to treat host/foo.ns.test.h5l.se as an alias of
+ * host/foo.ns.example.org.
+ */
+ if (krb5_principal_get_num_comp(context, h->principal) !=
+ 2 + krb5_principal_get_num_comp(context, princ))
+ ret = HDB_ERR_NOENTRY; /* Only host-based services for now */
+ if (ret == 0)
+ ret = rewrite_hostname(context, princ, nsprinc, h->principal, &s);
+ if (ret == 0) {
+ krb5_free_principal(context, h->principal);
+ h->principal = NULL;
+ ret = krb5_make_principal(context, &h->principal,
+ krb5_principal_get_realm(context, princ),
+ krb5_principal_get_comp_string(context,
+ princ, 0),
+ s,
+ NULL);
+ }
+ free(s);
+ return ret;
+}
+
+/* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */
+static krb5_error_code
+fetch_it(krb5_context context,
+ HDB *db,
+ krb5_const_principal princ,
+ unsigned flags,
+ krb5_timestamp t,
+ krb5int32 etype,
+ krb5uint32 kvno,
+ hdb_entry *ent)
+{
+ krb5_const_principal tmpprinc = princ;
+ krb5_principal nsprinc = NULL;
+ krb5_error_code ret = 0;
+ const char *comp0 = krb5_principal_get_comp_string(context, princ, 0);
+ const char *comp1 = krb5_principal_get_comp_string(context, princ, 1);
+ const char *tmp;
+ size_t mindots = db->virtual_hostbased_princ_ndots;
+ size_t maxdots = db->virtual_hostbased_princ_maxdots;
+ size_t hdots = 0;
+ char *host = NULL;
+ int do_search = 0;
+
+ if (!db->enable_virtual_hostbased_princs)
+ maxdots = mindots = 0;
+ if (db->enable_virtual_hostbased_princs && comp1 &&
+ strcmp("krbtgt", comp0) != 0 && strcmp(KRB5_WELLKNOWN_NAME, comp0) != 0) {
+ char *htmp;
+
+ if ((host = strdup(comp1)) == NULL)
+ return krb5_enomem(context);
+
+ /* Strip out any :port */
+ htmp = strchr(host, ':');
+ if (htmp) {
+ if (strchr(htmp + 1, ':')) {
+ /* Extra ':'s? No virtualization for you! */
+ free(host);
+ host = NULL;
+ htmp = NULL;
+ } else {
+ *htmp = '\0';
+ }
+ }
+ /* Count dots in `host' */
+ for (hdots = 0, htmp = host; htmp && *htmp; htmp++)
+ if (*htmp == '.')
+ hdots++;
+
+ do_search = 1;
+ }
+
+ tmp = host ? host : comp1;
+ for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = nsprinc) {
+ krb5_error_code ret2 = 0;
+
+ /*
+ * We break out of this loop with ret == 0 only if we found the HDB
+ * entry we were looking for or the HDB entry for a matching namespace.
+ *
+ * Otherwise we break out with ret != 0, typically HDB_ERR_NOENTRY.
+ *
+ * First time through we lookup the principal as given.
+ *
+ * Next we lookup a namespace principal, stripping off hostname labels
+ * from the left until we find one or get tired of looking or run out
+ * of labels.
+ */
+ ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent);
+ if (ret == 0 && nsprinc && ent->flags.invalid) {
+ free_HDB_entry(ent);
+ ret = HDB_ERR_NOENTRY;
+ }
+ if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp ||
+ !do_search)
+ break;
+
+ /*
+ * Breadcrumb:
+ *
+ * - if we found a concrete principal, but it's been marked
+ * as now-virtual, then we must keep going
+ *
+ * But this will be coded in the future.
+ *
+ * Maybe we can take attributes from the concrete principal...
+ */
+
+ /*
+ * The namespace's hostname will not have more labels than maxdots + 1.
+ * Thus we truncate immediately down to maxdots + 1 if we haven't yet.
+ *
+ * Example: with maxdots == 3,
+ * foo.bar.baz.app.blah.example -> baz.app.blah.example
+ */
+ while (maxdots && hdots > maxdots && tmp) {
+ tmp = strchr(tmp, '.');
+ /* tmp != NULL because maxdots > 0; we check to quiet linters */
+ if (tmp == NULL) {
+ ret = HDB_ERR_NOENTRY;
+ goto out;
+ }
+ tmp++;
+ hdots--;
+ }
+
+ if (nsprinc == NULL)
+ /* First go around, need a namespace princ. Make it! */
+ ret2 = make_namespace_princ(context, db, tmpprinc, &nsprinc);
+
+ /* Update the hostname component of the namespace principal */
+ if (ret2 == 0)
+ ret2 = krb5_principal_set_comp_string(context, nsprinc, 3, tmp);
+ if (ret2)
+ ret = ret2;
+
+ if (tmp) {
+ /* Strip off left-most label for the next go-around */
+ if ((tmp = strchr(tmp, '.')))
+ tmp++;
+ hdots--;
+ } /* else we'll break out after the next db->hdb_fetch_kvno() call */
+ }
+
+ /*
+ * If unencrypted keys were requested, derive them. There may not be any
+ * key derivation to do, but that's decided in derive_keys().
+ */
+ if (ret == 0 || ret == HDB_ERR_WRONG_REALM) {
+ krb5_error_code save_ret = ret;
+
+ /* Fix the principal name if namespaced */
+ ret = fix_princ_name(context, princ, nsprinc, ent);
+
+ /* Derive keys if namespaced or virtual */
+ if (ret == 0)
+ ret = derive_keys(context, flags, princ, !!nsprinc, t, etype, kvno,
+ ent);
+ /* Pick the best kvno for this principal at the given time */
+ if (ret == 0)
+ ret = pick_kvno(context, db, flags, t, kvno, ent);
+ if (ret == 0)
+ ret = save_ret;
+ }
+
+out:
+ if (ret != 0 && ret != HDB_ERR_WRONG_REALM)
+ hdb_free_entry(context, db, ent);
+ krb5_free_principal(context, nsprinc);
+ free(host);
+ return ret;
+}
+
+/**
+ * Fetch a principal's HDB entry, possibly generating virtual keys from base
+ * keys according to strict key rotation schedules. If a time is given, other
+ * than HDB I/O, this function is pure, thus usable for testing.
+ *
+ * HDB writers should use `db->hdb_fetch_kvno()' to avoid materializing virtual
+ * principals.
+ *
+ * HDB readers should use this function rather than `db->hdb_fetch_kvno()'
+ * unless they only want to see concrete principals and not bother generating
+ * any virtual keys.
+ *
+ * @param context Context
+ * @param db HDB
+ * @param principal Principal name
+ * @param flags Fetch flags
+ * @param t For virtual keys, use this as the point in time (use zero to mean "now")
+ * @param etype Key enctype (use KRB5_ENCTYPE_NULL to mean "preferred")
+ * @param kvno Key version number (use zero to mean "current")
+ * @param h Output HDB entry
+ *
+ * @return Zero or HDB_ERR_WRONG_REALM on success, an error code otherwise.
+ */
+krb5_error_code
+hdb_fetch_kvno(krb5_context context,
+ HDB *db,
+ krb5_const_principal principal,
+ unsigned int flags,
+ krb5_timestamp t,
+ krb5int32 etype,
+ krb5uint32 kvno,
+ hdb_entry *h)
+{
+ krb5_error_code ret;
+ krb5_timestamp now;
+
+ krb5_timeofday(context, &now);
+
+ flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */
+ ret = fetch_it(context, db, principal, flags, t ? t : now, etype, kvno, h);
+ if (ret == 0 && t == 0 && h->flags.virtual &&
+ h->pw_end && h->pw_end[0] < now) {
+ /*
+ * This shouldn't happen!
+ *
+ * Do not allow h->pw_end[0] to be in the past for virtual principals
+ * outside testing. This is just to prevent the AS/TGS from failing.
+ */
+ h->pw_end[0] = now + 3600;
+ }
+ if (ret == HDB_ERR_NOENTRY)
+ krb5_set_error_message(context, ret, "no such entry found in hdb");
+ return ret;
+}
+
+size_t ASN1CALL
+length_hdb_keyset(HDB_keyset *data)
+{
+ return length_HDB_keyset(data);
+}
+
+size_t ASN1CALL
+length_hdb_entry(HDB_entry *data)
+{
+ return length_HDB_entry(data);
+}
+
+size_t ASN1CALL
+length_hdb_entry_alias(HDB_entry_alias *data)
+{
+ return length_HDB_entry_alias(data);
+}
+
+void ASN1CALL
+free_hdb_keyset(HDB_keyset *data)
+{
+ free_HDB_keyset(data);
+}
+
+void ASN1CALL
+free_hdb_entry(HDB_entry *data)
+{
+ free_HDB_entry(data);
+}
+
+void ASN1CALL
+free_hdb_entry_alias(HDB_entry_alias *data)
+{
+ free_HDB_entry_alias(data);
+}
+
+size_t ASN1CALL
+copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to)
+{
+ return copy_HDB_keyset(from, to);
+}
+
+size_t ASN1CALL
+copy_hdb_entry(const HDB_entry *from, HDB_entry *to)
+{
+ return copy_HDB_entry(from, to);
+}
+
+size_t ASN1CALL
+copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to)
+{
+ return copy_HDB_entry_alias(from, to);
+}
+
+int ASN1CALL
+decode_hdb_keyset(const unsigned char *p,
+ size_t len,
+ HDB_keyset *data,
+ size_t *size)
+{
+ return decode_HDB_keyset(p, len, data, size);
+}
+
+int ASN1CALL
+decode_hdb_entry(const unsigned char *p,
+ size_t len,
+ HDB_entry *data,
+ size_t *size)
+{
+ return decode_HDB_entry(p, len, data, size);
+}
+
+int ASN1CALL
+decode_hdb_entry_alias(const unsigned char *p,
+ size_t len,
+ HDB_entry_alias *data,
+ size_t *size)
+{
+ return decode_HDB_entry_alias(p, len, data, size);
+}
+
+int ASN1CALL
+encode_hdb_keyset(unsigned char *p,
+ size_t len,
+ const HDB_keyset *data,
+ size_t *size)
+{
+ return encode_HDB_keyset(p, len, data, size);
+}
+
+int ASN1CALL
+encode_hdb_entry(unsigned char *p,
+ size_t len,
+ const HDB_entry *data,
+ size_t *size)
+{
+ return encode_HDB_entry(p, len, data, size);
+}
+
+int ASN1CALL
+encode_hdb_entry_alias(unsigned char *p,
+ size_t len,
+ const HDB_entry_alias *data,
+ size_t *size)
+{
+ return encode_HDB_entry_alias(p, len, data, size);
+}
diff --git a/lib/hdb/db.c b/lib/hdb/db.c
index 4cee8d0097a1..5fcce7b8e8b3 100644
--- a/lib/hdb/db.c
+++ b/lib/hdb/db.c
@@ -71,7 +71,8 @@ DB_destroy(krb5_context context, HDB *db)
{
krb5_error_code ret;
- ret = hdb_clear_master_key (context, db);
+ ret = hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(db->hdb_name);
free(db);
return ret;
@@ -113,7 +114,7 @@ DB_unlock(krb5_context context, HDB *db)
static krb5_error_code
DB_seq(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry, int flag)
+ unsigned flags, hdb_entry *entry, int flag)
{
DB *d = (DB*)db->hdb_db;
DBT key, value;
@@ -137,21 +138,21 @@ DB_seq(krb5_context context, HDB *db,
data.data = value.data;
data.length = value.size;
memset(entry, 0, sizeof(*entry));
- if (hdb_value2entry(context, &data, &entry->entry))
+ if (hdb_value2entry(context, &data, entry))
return DB_seq(context, db, flags, entry, R_NEXT);
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- code = hdb_unseal_keys (context, db, &entry->entry);
+ code = hdb_unseal_keys (context, db, entry);
if (code)
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
}
- if (code == 0 && entry->entry.principal == NULL) {
- entry->entry.principal = malloc(sizeof(*entry->entry.principal));
- if (entry->entry.principal == NULL) {
+ if (code == 0 && entry->principal == NULL) {
+ entry->principal = malloc(sizeof(*entry->principal));
+ if (entry->principal == NULL) {
code = ENOMEM;
krb5_set_error_message(context, code, "malloc: out of memory");
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
} else {
- hdb_key2principal(context, &key_data, entry->entry.principal);
+ hdb_key2principal(context, &key_data, entry->principal);
}
}
return code;
@@ -159,14 +160,14 @@ DB_seq(krb5_context context, HDB *db,
static krb5_error_code
-DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return DB_seq(context, db, flags, entry, R_FIRST);
}
static krb5_error_code
-DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return DB_seq(context, db, flags, entry, R_NEXT);
}
diff --git a/lib/hdb/db3.c b/lib/hdb/db3.c
index 0d41369d7101..9d0c0a97d9ab 100644
--- a/lib/hdb/db3.c
+++ b/lib/hdb/db3.c
@@ -86,7 +86,8 @@ DB_destroy(krb5_context context, HDB *db)
{
krb5_error_code ret;
- ret = hdb_clear_master_key (context, db);
+ ret = hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(db->hdb_name);
free(db);
return ret;
@@ -135,7 +136,7 @@ DB_unlock(krb5_context context, HDB *db)
static krb5_error_code
DB_seq(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry, int flag)
+ unsigned flags, hdb_entry *entry, int flag)
{
DBT key, value;
DBC *dbcp = db->hdb_dbc;
@@ -155,21 +156,21 @@ DB_seq(krb5_context context, HDB *db,
data.data = value.data;
data.length = value.size;
memset(entry, 0, sizeof(*entry));
- if (hdb_value2entry(context, &data, &entry->entry))
+ if (hdb_value2entry(context, &data, entry))
return DB_seq(context, db, flags, entry, DB_NEXT);
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- code = hdb_unseal_keys (context, db, &entry->entry);
+ code = hdb_unseal_keys (context, db, entry);
if (code)
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
}
- if (entry->entry.principal == NULL) {
- entry->entry.principal = malloc(sizeof(*entry->entry.principal));
- if (entry->entry.principal == NULL) {
- hdb_free_entry (context, entry);
+ if (entry->principal == NULL) {
+ entry->principal = malloc(sizeof(*entry->principal));
+ if (entry->principal == NULL) {
+ hdb_free_entry (context, db, entry);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
} else {
- hdb_key2principal(context, &key_data, entry->entry.principal);
+ hdb_key2principal(context, &key_data, entry->principal);
}
}
return 0;
@@ -177,14 +178,14 @@ DB_seq(krb5_context context, HDB *db,
static krb5_error_code
-DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return DB_seq(context, db, flags, entry, DB_FIRST);
}
static krb5_error_code
-DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return DB_seq(context, db, flags, entry, DB_NEXT);
}
diff --git a/lib/hdb/dbinfo.c b/lib/hdb/dbinfo.c
index e2890255b2ef..60b11f8cd663 100644
--- a/lib/hdb/dbinfo.c
+++ b/lib/hdb/dbinfo.c
@@ -271,5 +271,21 @@ hdb_db_dir(krb5_context context)
const char *
hdb_default_db(krb5_context context)
{
- return HDB_DEFAULT_DB;
+ static char *default_hdb = NULL;
+ struct hdb_dbinfo *dbinfo = NULL;
+ struct hdb_dbinfo *d = NULL;
+ const char *s;
+
+ if (default_hdb)
+ return default_hdb;
+
+ (void) hdb_get_dbinfo(context, &dbinfo);
+ while ((d = hdb_dbinfo_get_next(dbinfo, d)) != NULL) {
+ if ((s = hdb_dbinfo_get_dbname(context, d)) &&
+ (default_hdb = strdup(s)))
+ break;
+ }
+
+ hdb_free_dbinfo(context, &dbinfo);
+ return default_hdb ? default_hdb : HDB_DEFAULT_DB;
}
diff --git a/lib/hdb/ext.c b/lib/hdb/ext.c
index ecefe931b74f..48683ef1607f 100644
--- a/lib/hdb/ext.c
+++ b/lib/hdb/ext.c
@@ -86,7 +86,6 @@ hdb_replace_extension(krb5_context context,
const HDB_extension *ext)
{
HDB_extension *ext2;
- HDB_extension *es;
int ret;
ext2 = NULL;
@@ -157,22 +156,7 @@ hdb_replace_extension(krb5_context context,
return ret;
}
- es = realloc(entry->extensions->val,
- (entry->extensions->len+1)*sizeof(entry->extensions->val[0]));
- if (es == NULL) {
- krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
- return ENOMEM;
- }
- entry->extensions->val = es;
-
- ret = copy_HDB_extension(ext,
- &entry->extensions->val[entry->extensions->len]);
- if (ret == 0)
- entry->extensions->len++;
- else
- krb5_set_error_message(context, ret, "hdb: failed to copy new extension");
-
- return ret;
+ return add_HDB_extensions(entry->extensions, ext);
}
krb5_error_code
@@ -185,14 +169,11 @@ hdb_clear_extension(krb5_context context,
if (entry->extensions == NULL)
return 0;
- for (i = 0; i < entry->extensions->len; i++) {
- if (entry->extensions->val[i].data.element == (unsigned)type) {
- free_HDB_extension(&entry->extensions->val[i]);
- memmove(&entry->extensions->val[i],
- &entry->extensions->val[i + 1],
- sizeof(entry->extensions->val[i]) * (entry->extensions->len - i - 1));
- entry->extensions->len--;
- }
+ for (i = 0; i < entry->extensions->len; ) {
+ if (entry->extensions->val[i].data.element == (unsigned)type)
+ (void) remove_HDB_extensions(entry->extensions, i);
+ else
+ i++;
}
if (entry->extensions->len == 0) {
free(entry->extensions->val);
@@ -247,6 +228,33 @@ hdb_entry_get_pkinit_cert(const hdb_entry *entry, const HDB_Ext_PKINIT_cert **a)
}
krb5_error_code
+hdb_entry_get_krb5_config(const hdb_entry *entry, heim_octet_string *c)
+{
+ const HDB_extension *ext;
+
+ c->data = NULL;
+ c->length = 0;
+ ext = hdb_find_extension(entry, choice_HDB_extension_data_krb5_config);
+ if (ext)
+ *c = ext->data.u.krb5_config;
+ return 0;
+}
+
+krb5_error_code
+hdb_entry_set_krb5_config(krb5_context context,
+ hdb_entry *entry,
+ heim_octet_string *s)
+{
+ HDB_extension ext;
+
+ ext.mandatory = FALSE;
+ ext.data.element = choice_HDB_extension_data_last_pw_change;
+ /* hdb_replace_extension() copies this, so no need to copy it here */
+ ext.data.u.krb5_config = *s;
+ return hdb_replace_extension(context, entry, &ext);
+}
+
+krb5_error_code
hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t)
{
const HDB_extension *ext;
@@ -530,3 +538,249 @@ hdb_set_last_modified_by(krb5_context context, hdb_entry *entry,
return 0;
}
+krb5_error_code
+hdb_entry_get_key_rotation(krb5_context context,
+ const hdb_entry *entry,
+ const HDB_Ext_KeyRotation **kr)
+{
+ HDB_extension *ext =
+ hdb_find_extension(entry, choice_HDB_extension_data_key_rotation);
+
+ *kr = ext ? &ext->data.u.key_rotation : NULL;
+ return 0;
+}
+
+krb5_error_code
+hdb_validate_key_rotation(krb5_context context,
+ const KeyRotation *past_kr,
+ const KeyRotation *new_kr)
+{
+ unsigned int last_kvno;
+
+ if (new_kr->period < 1) {
+ krb5_set_error_message(context, EINVAL,
+ "Key rotation periods must be non-zero "
+ "and positive");
+ return EINVAL;
+ }
+ if (new_kr->base_key_kvno < 1 || new_kr->base_kvno < 1) {
+ krb5_set_error_message(context, EINVAL,
+ "Key version number zero not allowed "
+ "for key rotation");
+ return EINVAL;
+ }
+ if (!past_kr)
+ return 0;
+
+ if (past_kr->base_key_kvno == new_kr->base_key_kvno) {
+ /*
+ * The new base keys can be the same as the old, but must have
+ * different kvnos. (Well, not must must. It's a convention for now.)
+ */
+ krb5_set_error_message(context, EINVAL,
+ "Base key version numbers for KRs must differ");
+ return EINVAL;
+ }
+ if (new_kr->epoch - past_kr->epoch <= 0) {
+ krb5_set_error_message(context, EINVAL,
+ "New key rotation periods must start later "
+ "than existing ones");
+ return EINVAL;
+ }
+
+ last_kvno = 1 + ((new_kr->epoch - past_kr->epoch) / past_kr->period);
+ if (new_kr->base_kvno <= last_kvno) {
+ krb5_set_error_message(context, EINVAL,
+ "New key rotation base kvno must be larger "
+ "the last kvno for the current key "
+ "rotation (%u)", last_kvno);
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int
+kr_eq(const KeyRotation *a, const KeyRotation *b)
+{
+ return !!(
+ a->epoch == b->epoch &&
+ a->period == b->period &&
+ a->base_kvno == b->base_kvno &&
+ a->base_key_kvno == b->base_key_kvno &&
+ KeyRotationFlags2int(a->flags) == KeyRotationFlags2int(b->flags)
+ );
+}
+
+krb5_error_code
+hdb_validate_key_rotations(krb5_context context,
+ const HDB_Ext_KeyRotation *existing,
+ const HDB_Ext_KeyRotation *krs)
+{
+ krb5_error_code ret = 0;
+ size_t added = 0;
+ size_t i;
+
+ if ((!existing || !existing->len) && (!krs || !krs->len))
+ return 0; /* Nothing to do; weird */
+
+ /*
+ * HDB_Ext_KeyRotation has to have 1..3 elements, and this is enforced by
+ * the ASN.1 compiler and the code it generates. Nonetheless we'll check
+ * that there's not zero elements.
+ */
+ if ((!krs || !krs->len)) {
+ /*
+ * NOTE: We can clear this on concrete principals with virtual keys
+ * though. The caller can check for that case.
+ */
+ krb5_set_error_message(context, EINVAL,
+ "Cannot clear key rotation metadata on "
+ "virtual principal namespaces");
+ ret = EINVAL;
+ }
+
+ /* Validate the new KRs by themselves */
+ for (i = 0; ret == 0 && i < krs->len; i++) {
+ ret = hdb_validate_key_rotation(context,
+ i+1 < krs->len ? &krs->val[i+1] : 0,
+ &krs->val[i]);
+ }
+ if (ret || !existing || !existing->len)
+ return ret;
+
+ if (existing->len == krs->len) {
+ /* Check for no change */
+ for (i = 0; i < krs->len; i++)
+ if (!kr_eq(&existing->val[i], &krs->val[i]))
+ break;
+ if (i == krs->len)
+ return 0; /* No change */
+ }
+
+ /*
+ * Check that new KRs make sense in the context of the previous KRs.
+ *
+ * Permitted changes:
+ *
+ * - add one new KR in front
+ * - drop old KRs
+ *
+ * Start by checking if we're adding a KR, then go on to check for dropped
+ * KRs and/or last KR alteration.
+ */
+ if (existing->val[0].epoch == krs->val[0].epoch ||
+ existing->val[0].base_kvno == krs->val[0].base_kvno) {
+ if (!kr_eq(&existing->val[0], &krs->val[0])) {
+ krb5_set_error_message(context, EINVAL,
+ "Key rotation change not sensible");
+ ret = EINVAL;
+ }
+ /* Key rotation *not* added */
+ } else {
+ /* Key rotation added; check it first */
+ ret = hdb_validate_key_rotation(context,
+ &existing->val[0],
+ &krs->val[0]);
+ added = 1;
+ }
+ for (i = 0; ret == 0 && i < existing->len && i + added < krs->len; i++)
+ if (!kr_eq(&existing->val[i], &krs->val[i + added]))
+ krb5_set_error_message(context, ret = EINVAL,
+ "Only last key rotation may be truncated");
+ return ret;
+}
+
+/* XXX We need a function to "revoke" the past */
+
+/**
+ * This function adds a KeyRotation value to an entry, validating the
+ * change. One of `entry' and `krs' must be NULL, and the other non-NULL, and
+ * whichever is given will be altered.
+ *
+ * @param context Context
+ * @param entry An HDB entry
+ * @param krs A key rotation extension for hdb_entry
+ * @param kr A new KeyRotation value
+ *
+ * @return Zero on success, an error otherwise.
+ */
+krb5_error_code
+hdb_entry_add_key_rotation(krb5_context context,
+ hdb_entry *entry,
+ HDB_Ext_KeyRotation *krs,
+ const KeyRotation *kr)
+{
+ krb5_error_code ret;
+ HDB_extension new_ext;
+ HDB_extension *ext = &new_ext;
+ KeyRotation tmp;
+ size_t i, sz;
+
+ if (kr->period < 1) {
+ krb5_set_error_message(context, EINVAL,
+ "Key rotation period cannot be zero");
+ return EINVAL;
+ }
+
+ new_ext.mandatory = TRUE;
+ new_ext.data.element = choice_HDB_extension_data_key_rotation;
+ new_ext.data.u.key_rotation.len = 0;
+ new_ext.data.u.key_rotation.val = 0;
+
+ if (entry && krs)
+ return EINVAL;
+
+ if (entry) {
+ ext = hdb_find_extension(entry, choice_HDB_extension_data_key_rotation);
+ if (!ext)
+ ext = &new_ext;
+ } else {
+ const KeyRotation *prev_kr = &krs->val[0];
+ unsigned int last_kvno = 0;
+
+ if (kr->epoch - prev_kr->epoch <= 0) {
+ krb5_set_error_message(context, EINVAL,
+ "New key rotation periods must start later "
+ "than existing ones");
+ return EINVAL;
+ }
+
+ if (kr->base_kvno <= prev_kr->base_kvno ||
+ kr->base_kvno - prev_kr->base_kvno <=
+ (last_kvno = 1 +
+ ((kr->epoch - prev_kr->epoch) / prev_kr->period))) {
+ krb5_set_error_message(context, EINVAL,
+ "New key rotation base kvno must be larger "
+ "the last kvno for the current key "
+ "rotation (%u)", last_kvno);
+ return EINVAL;
+ }
+ }
+
+ /* First, append */
+ ret = add_HDB_Ext_KeyRotation(&ext->data.u.key_rotation, kr);
+ if (ret)
+ return ret;
+
+ /* Rotate new to front */
+ tmp = ext->data.u.key_rotation.val[ext->data.u.key_rotation.len - 1];
+ sz = sizeof(ext->data.u.key_rotation.val[0]);
+ memmove(&ext->data.u.key_rotation.val[1], &ext->data.u.key_rotation.val[0],
+ (ext->data.u.key_rotation.len - 1) * sz);
+ ext->data.u.key_rotation.val[0] = tmp;
+
+ /* Drop too old entries */
+ for (i = 3; i < ext->data.u.key_rotation.len; i++)
+ free_KeyRotation(&ext->data.u.key_rotation.val[i]);
+ ext->data.u.key_rotation.len =
+ ext->data.u.key_rotation.len > 3 ? 3 : ext->data.u.key_rotation.len;
+
+ if (ext != &new_ext)
+ return 0;
+
+ /* Install new extension */
+ if (ret == 0 && entry)
+ ret = hdb_replace_extension(context, entry, ext);
+ free_HDB_extension(&new_ext);
+ return ret;
+}
diff --git a/lib/hdb/hdb-keytab.c b/lib/hdb/hdb-keytab.c
index ab2afb5d74ba..c9b469cb1a85 100644
--- a/lib/hdb/hdb-keytab.c
+++ b/lib/hdb/hdb-keytab.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -65,7 +65,8 @@ hkt_destroy(krb5_context context, HDB *db)
hdb_keytab k = (hdb_keytab)db->hdb_db;
krb5_error_code ret;
- ret = hdb_clear_master_key (context, db);
+ ret = hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(k->path);
free(k);
@@ -89,14 +90,14 @@ hkt_unlock(krb5_context context, HDB *db)
static krb5_error_code
hkt_firstkey(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry)
+ unsigned flags, hdb_entry *entry)
{
return HDB_ERR_DB_INUSE;
}
static krb5_error_code
hkt_nextkey(krb5_context context, HDB * db, unsigned flags,
- hdb_entry_ex * entry)
+ hdb_entry * entry)
{
return HDB_ERR_DB_INUSE;
}
@@ -118,7 +119,7 @@ hkt_open(krb5_context context, HDB * db, int flags, mode_t mode)
static krb5_error_code
hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
- unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
+ unsigned flags, krb5_kvno kvno, hdb_entry * entry)
{
hdb_keytab k = (hdb_keytab)db->hdb_db;
krb5_error_code ret;
@@ -131,13 +132,13 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
memset(&ktentry, 0, sizeof(ktentry));
- entry->entry.flags.server = 1;
- entry->entry.flags.forwardable = 1;
- entry->entry.flags.renewable = 1;
+ entry->flags.server = 1;
+ entry->flags.forwardable = 1;
+ entry->flags.renewable = 1;
/* Not recorded in the OD backend, make something up */
ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND",
- &entry->entry.created_by.principal);
+ &entry->created_by.principal);
if (ret)
goto out;
@@ -154,7 +155,7 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
goto out;
}
- ret = krb5_copy_principal(context, principal, &entry->entry.principal);
+ ret = krb5_copy_principal(context, principal, &entry->principal);
if (ret)
goto out;
@@ -162,8 +163,8 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
out:
if (ret) {
- free_hdb_entry(&entry->entry);
- memset(&entry->entry, 0, sizeof(entry->entry));
+ free_HDB_entry(entry);
+ memset(entry, 0, sizeof(*entry));
}
krb5_kt_free_entry(context, &ktentry);
@@ -172,7 +173,7 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
static krb5_error_code
hkt_store(krb5_context context, HDB * db, unsigned flags,
- hdb_entry_ex * entry)
+ hdb_entry * entry)
{
return HDB_ERR_DB_INUSE;
}
diff --git a/lib/hdb/hdb-ldap.c b/lib/hdb/hdb-ldap.c
index 2ed7a6ba2596..5cd097f5b6bc 100644
--- a/lib/hdb/hdb-ldap.c
+++ b/lib/hdb/hdb-ldap.c
@@ -47,7 +47,7 @@ static krb5_error_code LDAP_close(krb5_context context, HDB *);
static krb5_error_code
LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
- int flags, hdb_entry_ex * ent);
+ int flags, hdb_entry * ent);
static const char *default_structural_object = "account";
static char *structural_object;
@@ -388,14 +388,14 @@ bervalstrcmp(struct berval *v, const char *str)
static krb5_error_code
-LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
- LDAPMessage * msg, LDAPMod *** pmods)
+LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry * ent,
+ LDAPMessage * msg, LDAPMod *** pmods, krb5_boolean *pis_new_entry)
{
krb5_error_code ret;
- krb5_boolean is_new_entry;
+ krb5_boolean is_new_entry = FALSE;
char *tmp = NULL;
LDAPMod **mods = NULL;
- hdb_entry_ex orig;
+ hdb_entry orig;
unsigned long oflags, nflags;
int i;
@@ -414,8 +414,6 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
if (ret)
goto out;
- is_new_entry = FALSE;
-
vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass");
if (vals) {
int num_objectclasses = ldap_count_values_len(vals);
@@ -454,12 +452,12 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
* orig being intiialized to zero */
memset(&orig, 0, sizeof(orig));
- ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
- if (ret)
- goto out;
-
/* account is the structural object class */
if (is_account == FALSE) {
+ ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
+ if (ret)
+ goto out;
+
ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
structural_object);
is_account = TRUE;
@@ -479,12 +477,12 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
if (is_new_entry ||
- krb5_principal_compare(context, ent->entry.principal, orig.entry.principal)
+ krb5_principal_compare(context, ent->principal, orig.principal)
== FALSE)
{
if (is_heimdal_principal || is_heimdal_entry) {
- ret = krb5_unparse_name(context, ent->entry.principal, &tmp);
+ ret = krb5_unparse_name(context, ent->principal, &tmp);
if (ret)
goto out;
@@ -498,7 +496,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
if (is_account || is_samba_account) {
- ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp);
+ ret = krb5_unparse_name_short(context, ent->principal, &tmp);
if (ret)
goto out;
ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp);
@@ -510,15 +508,15 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
}
- if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) {
+ if (is_heimdal_entry && (ent->kvno != orig.kvno || is_new_entry)) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"krb5KeyVersionNumber",
- ent->entry.kvno);
+ ent->kvno);
if (ret)
goto out;
}
- if (is_heimdal_entry && ent->entry.extensions) {
+ if (is_heimdal_entry && ent->extensions) {
if (!is_new_entry) {
vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes");
if (vals) {
@@ -529,11 +527,11 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
}
- for (i = 0; i < ent->entry.extensions->len; i++) {
+ for (i = 0; i < ent->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);
+ ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->extensions->val[i], &sz, ret);
if (ret)
goto out;
if (size != sz)
@@ -545,42 +543,42 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
}
- if (is_heimdal_entry && ent->entry.valid_start) {
- if (orig.entry.valid_end == NULL
- || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) {
+ if (is_heimdal_entry && ent->valid_start) {
+ if (orig.valid_end == NULL
+ || (*(ent->valid_start) != *(orig.valid_start))) {
ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
"krb5ValidStart",
- ent->entry.valid_start);
+ ent->valid_start);
if (ret)
goto out;
}
}
- if (ent->entry.valid_end) {
- if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) {
+ if (ent->valid_end) {
+ if (orig.valid_end == NULL || (*(ent->valid_end) != *(orig.valid_end))) {
if (is_heimdal_entry) {
ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
"krb5ValidEnd",
- ent->entry.valid_end);
+ ent->valid_end);
if (ret)
goto out;
}
if (is_samba_account) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"sambaKickoffTime",
- *(ent->entry.valid_end));
+ *(ent->valid_end));
if (ret)
goto out;
}
}
}
- if (ent->entry.pw_end) {
- if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) {
+ if (ent->pw_end) {
+ if (orig.pw_end == NULL || (*(ent->pw_end) != *(orig.pw_end))) {
if (is_heimdal_entry) {
ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
"krb5PasswordEnd",
- ent->entry.pw_end);
+ ent->pw_end);
if (ret)
goto out;
}
@@ -588,7 +586,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
if (is_samba_account) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"sambaPwdMustChange",
- *(ent->entry.pw_end));
+ *(ent->pw_end));
if (ret)
goto out;
}
@@ -597,43 +595,43 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
#if 0 /* we we have last_pw_change */
- if (is_samba_account && ent->entry.last_pw_change) {
- if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) {
+ if (is_samba_account && ent->last_pw_change) {
+ if (orig.last_pw_change == NULL || (*(ent->last_pw_change) != *(orig.last_pw_change))) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"sambaPwdLastSet",
- *(ent->entry.last_pw_change));
+ *(ent->last_pw_change));
if (ret)
goto out;
}
}
#endif
- if (is_heimdal_entry && ent->entry.max_life) {
- if (orig.entry.max_life == NULL
- || (*(ent->entry.max_life) != *(orig.entry.max_life))) {
+ if (is_heimdal_entry && ent->max_life) {
+ if (orig.max_life == NULL
+ || (*(ent->max_life) != *(orig.max_life))) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"krb5MaxLife",
- *(ent->entry.max_life));
+ *(ent->max_life));
if (ret)
goto out;
}
}
- if (is_heimdal_entry && ent->entry.max_renew) {
- if (orig.entry.max_renew == NULL
- || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) {
+ if (is_heimdal_entry && ent->max_renew) {
+ if (orig.max_renew == NULL
+ || (*(ent->max_renew) != *(orig.max_renew))) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
"krb5MaxRenew",
- *(ent->entry.max_renew));
+ *(ent->max_renew));
if (ret)
goto out;
}
}
- oflags = HDBFlags2int(orig.entry.flags);
- nflags = HDBFlags2int(ent->entry.flags);
+ oflags = HDBFlags2int(orig.flags);
+ nflags = HDBFlags2int(ent->flags);
if (is_heimdal_entry && oflags != nflags) {
@@ -645,7 +643,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
/* Remove keys if they exists, and then replace keys. */
- if (!is_new_entry && orig.entry.keys.len > 0) {
+ if (!is_new_entry && orig.keys.len > 0) {
vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
if (vals) {
ldap_value_free_len(vals);
@@ -656,21 +654,21 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
}
- for (i = 0; i < ent->entry.keys.len; i++) {
+ for (i = 0; i < ent->keys.len; i++) {
if (is_samba_account
- && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
+ && ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
char *ntHexPassword;
char *nt;
time_t now = time(NULL);
/* the key might have been 'sealed', but samba passwords
are clear in the directory */
- ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]);
+ ret = hdb_unseal_key(context, db, &ent->keys.val[i]);
if (ret)
goto out;
- nt = ent->entry.keys.val[i].key.keyvalue.data;
+ nt = ent->keys.val[i].key.keyvalue.data;
/* store in ntPassword, not krb5key */
ret = hex_encode(nt, 16, &ntHexPassword);
if (ret < 0) {
@@ -703,7 +701,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
unsigned char *buf;
size_t len, buf_size;
- ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret);
+ ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->keys.val[i], &len, ret);
if (ret)
goto out;
if(buf_size != len)
@@ -716,7 +714,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
}
- if (ent->entry.etypes) {
+ if (ent->etypes) {
int add_krb5EncryptionType = 0;
/*
@@ -738,15 +736,15 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
add_krb5EncryptionType = 1;
if (add_krb5EncryptionType) {
- for (i = 0; i < ent->entry.etypes->len; i++) {
+ for (i = 0; i < ent->etypes->len; i++) {
if (is_samba_account &&
- ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
+ ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
{
;
} else if (is_heimdal_entry) {
ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD,
"krb5EncryptionType",
- ent->entry.etypes->val[i]);
+ ent->etypes->val[i]);
if (ret)
goto out;
}
@@ -759,6 +757,8 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
out:
+ *pis_new_entry = is_new_entry;
+
if (ret == 0)
*pmods = mods;
else if (mods != NULL) {
@@ -767,7 +767,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
}
if (msg)
- hdb_free_entry(context, &orig);
+ hdb_free_entry(context, db, &orig);
return ret;
}
@@ -1005,7 +1005,7 @@ LDAP_principal2message(krb5_context context, HDB * db,
*/
static krb5_error_code
LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
- int flags, hdb_entry_ex * ent)
+ int flags, hdb_entry * ent)
{
char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL;
char *samba_acct_flags = NULL;
@@ -1015,18 +1015,18 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
int tmp, tmp_time, i, ret, have_arcfour = 0;
memset(ent, 0, sizeof(*ent));
- ent->entry.flags = int2HDBFlags(0);
+ ent->flags = int2HDBFlags(0);
ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name);
if (ret == 0) {
- ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
+ ret = krb5_parse_name(context, unparsed_name, &ent->principal);
if (ret)
goto out;
} else {
ret = LDAP_get_string_value(db, msg, "uid",
&unparsed_name);
if (ret == 0) {
- ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
+ ret = krb5_parse_name(context, unparsed_name, &ent->principal);
if (ret)
goto out;
} else {
@@ -1042,25 +1042,25 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
&integer);
if (ret)
- ent->entry.kvno = 0;
+ ent->kvno = 0;
else
- ent->entry.kvno = integer;
+ ent->kvno = integer;
}
keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
if (keys != NULL) {
size_t l;
- ent->entry.keys.len = ldap_count_values_len(keys);
- ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key));
- if (ent->entry.keys.val == NULL) {
+ ent->keys.len = ldap_count_values_len(keys);
+ ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key));
+ if (ent->keys.val == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "calloc: out of memory");
goto out;
}
- for (i = 0; i < ent->entry.keys.len; i++) {
+ for (i = 0; i < ent->keys.len; i++) {
decode_Key((unsigned char *) keys[i]->bv_val,
- (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l);
+ (size_t) keys[i]->bv_len, &ent->keys.val[i], &l);
}
ber_bvecfree(keys);
} else {
@@ -1070,8 +1070,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
* be related to a general directory entry without creating
* the keys. Hopefully it's OK.
*/
- ent->entry.keys.len = 0;
- ent->entry.keys.val = NULL;
+ ent->keys.len = 0;
+ ent->keys.val = NULL;
#else
ret = HDB_ERR_NOENTRY;
goto out;
@@ -1082,47 +1082,47 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
if (extensions != NULL) {
size_t l;
- ent->entry.extensions = calloc(1, sizeof(*(ent->entry.extensions)));
- if (ent->entry.extensions == NULL) {
+ ent->extensions = calloc(1, sizeof(*(ent->extensions)));
+ if (ent->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;
+ ent->extensions->len = ldap_count_values_len(extensions);
+ ent->extensions->val = (HDB_extension *) calloc(ent->extensions->len, sizeof(HDB_extension));
+ if (ent->extensions->val == NULL) {
+ ent->extensions->len = 0;
ret = krb5_enomem(context);
goto out;
}
- for (i = 0; i < ent->entry.extensions->len; i++) {
+ for (i = 0; i < ent->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);
+ (size_t) extensions[i]->bv_len, &ent->extensions->val[i], &l);
if (ret)
krb5_set_error_message(context, ret, "decode_HDB_extension failed");
}
ber_bvecfree(extensions);
} else {
- ent->entry.extensions = NULL;
+ ent->extensions = NULL;
}
vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
if (vals != NULL) {
- ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
- if (ent->entry.etypes == NULL) {
+ ent->etypes = malloc(sizeof(*(ent->etypes)));
+ if (ent->etypes == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret,"malloc: out of memory");
goto out;
}
- ent->entry.etypes->len = ldap_count_values_len(vals);
- ent->entry.etypes->val = calloc(ent->entry.etypes->len,
- sizeof(ent->entry.etypes->val[0]));
- if (ent->entry.etypes->val == NULL) {
+ ent->etypes->len = ldap_count_values_len(vals);
+ ent->etypes->val = calloc(ent->etypes->len,
+ sizeof(ent->etypes->val[0]));
+ if (ent->etypes->val == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
- ent->entry.etypes->len = 0;
+ ent->etypes->len = 0;
goto out;
}
- for (i = 0; i < ent->entry.etypes->len; i++) {
+ for (i = 0; i < ent->etypes->len; i++) {
char *buf;
buf = malloc(vals[i]->bv_len + 1);
@@ -1133,14 +1133,14 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
}
memcpy(buf, vals[i]->bv_val, vals[i]->bv_len);
buf[vals[i]->bv_len] = '\0';
- ent->entry.etypes->val[i] = atoi(buf);
+ ent->etypes->val[i] = atoi(buf);
free(buf);
}
ldap_value_free_len(vals);
}
- for (i = 0; i < ent->entry.keys.len; i++) {
- if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
+ for (i = 0; i < ent->keys.len; i++) {
+ if (ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
have_arcfour = 1;
break;
}
@@ -1152,146 +1152,151 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
unsigned *etypes;
Key *ks;
- ks = realloc(ent->entry.keys.val,
- (ent->entry.keys.len + 1) *
- sizeof(ent->entry.keys.val[0]));
+ ks = realloc(ent->keys.val,
+ (ent->keys.len + 1) *
+ sizeof(ent->keys.val[0]));
if (ks == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
- 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);
+ ent->keys.val = ks;
+ memset(&ent->keys.val[ent->keys.len], 0, sizeof(Key));
+ ent->keys.val[ent->keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5;
+ ret = krb5_data_alloc (&ent->keys.val[ent->keys.len].key.keyvalue, 16);
if (ret) {
krb5_set_error_message(context, ret, "malloc: out of memory");
ret = ENOMEM;
goto out;
}
ret = hex_decode(ntPasswordIN,
- ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16);
- ent->entry.keys.len++;
-
- if (ent->entry.etypes == NULL) {
- ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
- if (ent->entry.etypes == NULL) {
+ ent->keys.val[ent->keys.len].key.keyvalue.data, 16);
+ ent->keys.len++;
+ if (ret == -1) {
+ krb5_set_error_message(context, ret = EINVAL,
+ "invalid hex encoding of password");
+ goto out;
+ }
+
+ if (ent->etypes == NULL) {
+ ent->etypes = malloc(sizeof(*(ent->etypes)));
+ if (ent->etypes == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
- ent->entry.etypes->val = NULL;
- ent->entry.etypes->len = 0;
+ ent->etypes->val = NULL;
+ ent->etypes->len = 0;
}
- for (i = 0; i < ent->entry.etypes->len; i++)
- if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
+ for (i = 0; i < ent->etypes->len; i++)
+ if (ent->etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
break;
/* If there is no ARCFOUR enctype, add one */
- if (i == ent->entry.etypes->len) {
- etypes = realloc(ent->entry.etypes->val,
- (ent->entry.etypes->len + 1) *
- sizeof(ent->entry.etypes->val[0]));
+ if (i == ent->etypes->len) {
+ etypes = realloc(ent->etypes->val,
+ (ent->etypes->len + 1) *
+ sizeof(ent->etypes->val[0]));
if (etypes == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
- ent->entry.etypes->val = etypes;
- ent->entry.etypes->val[ent->entry.etypes->len] =
+ ent->etypes->val = etypes;
+ ent->etypes->val[ent->etypes->len] =
ETYPE_ARCFOUR_HMAC_MD5;
- ent->entry.etypes->len++;
+ ent->etypes->len++;
}
}
ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp",
- &ent->entry.created_by.time);
+ &ent->created_by.time);
if (ret)
- ent->entry.created_by.time = time(NULL);
+ ent->created_by.time = time(NULL);
- ent->entry.created_by.principal = NULL;
+ ent->created_by.principal = NULL;
if (flags & HDB_F_ADMIN_DATA) {
ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
if (ret == 0) {
- LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal);
+ LDAP_dn2principal(context, db, dn, &ent->created_by.principal);
free(dn);
}
- ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by));
- if (ent->entry.modified_by == NULL) {
+ ent->modified_by = calloc(1, sizeof(*ent->modified_by));
+ if (ent->modified_by == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
- &ent->entry.modified_by->time);
+ &ent->modified_by->time);
if (ret == 0) {
ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
if (ret == 0) {
- LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal);
+ LDAP_dn2principal(context, db, dn, &ent->modified_by->principal);
free(dn);
} else {
- free(ent->entry.modified_by);
- ent->entry.modified_by = NULL;
+ free(ent->modified_by);
+ ent->modified_by = NULL;
}
}
}
- ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start));
- if (ent->entry.valid_start == NULL) {
+ ent->valid_start = malloc(sizeof(*ent->valid_start));
+ if (ent->valid_start == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
- ent->entry.valid_start);
+ ent->valid_start);
if (ret) {
/* OPTIONAL */
- free(ent->entry.valid_start);
- ent->entry.valid_start = NULL;
+ free(ent->valid_start);
+ ent->valid_start = NULL;
}
- ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
- if (ent->entry.valid_end == NULL) {
+ ent->valid_end = malloc(sizeof(*ent->valid_end));
+ if (ent->valid_end == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
- ent->entry.valid_end);
+ ent->valid_end);
if (ret) {
/* OPTIONAL */
- free(ent->entry.valid_end);
- ent->entry.valid_end = NULL;
+ free(ent->valid_end);
+ ent->valid_end = NULL;
}
ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time);
if (ret == 0) {
- if (ent->entry.valid_end == NULL) {
- ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
- if (ent->entry.valid_end == NULL) {
+ if (ent->valid_end == NULL) {
+ ent->valid_end = malloc(sizeof(*ent->valid_end));
+ if (ent->valid_end == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
}
- *ent->entry.valid_end = tmp_time;
+ *ent->valid_end = tmp_time;
}
- ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
- if (ent->entry.pw_end == NULL) {
+ ent->pw_end = malloc(sizeof(*ent->pw_end));
+ if (ent->pw_end == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
- ent->entry.pw_end);
+ ent->pw_end);
if (ret) {
/* OPTIONAL */
- free(ent->entry.pw_end);
- ent->entry.pw_end = NULL;
+ free(ent->pw_end);
+ ent->pw_end = NULL;
}
ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
@@ -1305,76 +1310,76 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
NULL);
if (delta) {
- if (ent->entry.pw_end == NULL) {
- ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
- if (ent->entry.pw_end == NULL) {
+ if (ent->pw_end == NULL) {
+ ent->pw_end = malloc(sizeof(*ent->pw_end));
+ if (ent->pw_end == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
}
- *ent->entry.pw_end = tmp_time + delta;
+ *ent->pw_end = tmp_time + delta;
}
}
ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time);
if (ret == 0) {
- if (ent->entry.pw_end == NULL) {
- ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
- if (ent->entry.pw_end == NULL) {
+ if (ent->pw_end == NULL) {
+ ent->pw_end = malloc(sizeof(*ent->pw_end));
+ if (ent->pw_end == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
}
- *ent->entry.pw_end = tmp_time;
+ *ent->pw_end = tmp_time;
}
/* OPTIONAL */
ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
if (ret == 0)
- hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time);
+ hdb_entry_set_pw_change_time(context, ent, tmp_time);
{
int max_life;
- ent->entry.max_life = malloc(sizeof(*ent->entry.max_life));
- if (ent->entry.max_life == NULL) {
+ ent->max_life = malloc(sizeof(*ent->max_life));
+ if (ent->max_life == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life);
if (ret) {
- free(ent->entry.max_life);
- ent->entry.max_life = NULL;
+ free(ent->max_life);
+ ent->max_life = NULL;
} else
- *ent->entry.max_life = max_life;
+ *ent->max_life = max_life;
}
{
int max_renew;
- ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew));
- if (ent->entry.max_renew == NULL) {
+ ent->max_renew = malloc(sizeof(*ent->max_renew));
+ if (ent->max_renew == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew);
if (ret) {
- free(ent->entry.max_renew);
- ent->entry.max_renew = NULL;
+ free(ent->max_renew);
+ ent->max_renew = NULL;
} else
- *ent->entry.max_renew = max_renew;
+ *ent->max_renew = max_renew;
}
ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp);
if (ret)
tmp = 0;
- ent->entry.flags = int2HDBFlags(tmp);
+ ent->flags = int2HDBFlags(tmp);
/* Try and find Samba flags to put into the mix */
ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags);
@@ -1406,7 +1411,7 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
/* Allow forwarding */
if (samba_forwardable)
- ent->entry.flags.forwardable = TRUE;
+ ent->flags.forwardable = TRUE;
for (i=0; i < flags_len; i++) {
switch (samba_acct_flags[i]) {
@@ -1418,36 +1423,36 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
/* how to handle no password in kerberos? */
break;
case 'D':
- ent->entry.flags.invalid = TRUE;
+ ent->flags.invalid = TRUE;
break;
case 'H':
break;
case 'T':
/* temp duplicate */
- ent->entry.flags.invalid = TRUE;
+ ent->flags.invalid = TRUE;
break;
case 'U':
- ent->entry.flags.client = TRUE;
+ ent->flags.client = TRUE;
break;
case 'M':
break;
case 'W':
case 'S':
- ent->entry.flags.server = TRUE;
- ent->entry.flags.client = TRUE;
+ ent->flags.server = TRUE;
+ ent->flags.client = TRUE;
break;
case 'L':
- ent->entry.flags.invalid = TRUE;
+ ent->flags.invalid = TRUE;
break;
case 'X':
- if (ent->entry.pw_end) {
- free(ent->entry.pw_end);
- ent->entry.pw_end = NULL;
+ if (ent->pw_end) {
+ free(ent->pw_end);
+ ent->pw_end = NULL;
}
break;
case 'I':
- ent->entry.flags.server = TRUE;
- ent->entry.flags.client = TRUE;
+ ent->flags.server = TRUE;
+ ent->flags.client = TRUE;
break;
}
}
@@ -1462,7 +1467,7 @@ out:
free(ntPasswordIN);
if (ret)
- hdb_free_entry(context, ent);
+ hdb_free_entry(context, db, ent);
return ret;
}
@@ -1491,7 +1496,7 @@ LDAP_unlock(krb5_context context, HDB * db)
}
static krb5_error_code
-LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
+LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry)
{
int msgid, rc, parserc;
krb5_error_code ret;
@@ -1545,9 +1550,9 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
if (ret == 0) {
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- ret = hdb_unseal_keys(context, db, &entry->entry);
+ ret = hdb_unseal_keys(context, db, entry);
if (ret)
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
}
}
@@ -1556,7 +1561,7 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
static krb5_error_code
LDAP_firstkey(krb5_context context, HDB *db, unsigned flags,
- hdb_entry_ex *entry)
+ hdb_entry *entry)
{
krb5_error_code ret;
int msgid;
@@ -1584,7 +1589,7 @@ LDAP_firstkey(krb5_context context, HDB *db, unsigned flags,
static krb5_error_code
LDAP_nextkey(krb5_context context, HDB * db, unsigned flags,
- hdb_entry_ex * entry)
+ hdb_entry * entry)
{
return LDAP_seq(context, db, flags, entry);
}
@@ -1687,7 +1692,7 @@ LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
static krb5_error_code
LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
- unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
+ unsigned flags, krb5_kvno kvno, hdb_entry * entry)
{
LDAPMessage *msg, *e;
krb5_error_code ret;
@@ -1705,9 +1710,9 @@ LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
ret = LDAP_message2entry(context, db, e, flags, entry);
if (ret == 0) {
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- ret = hdb_unseal_keys(context, db, &entry->entry);
+ ret = hdb_unseal_keys(context, db, entry);
if (ret)
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
}
}
@@ -1720,7 +1725,7 @@ LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
#if 0
static krb5_error_code
LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
- unsigned flags, hdb_entry_ex * entry)
+ unsigned flags, hdb_entry * entry)
{
return LDAP_fetch_kvno(context, db, principal,
flags & (~HDB_F_KVNO_SPECIFIED), 0, entry);
@@ -1729,7 +1734,7 @@ LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
static krb5_error_code
LDAP_store(krb5_context context, HDB * db, unsigned flags,
- hdb_entry_ex * entry)
+ hdb_entry * entry)
{
LDAPMod **mods = NULL;
krb5_error_code ret;
@@ -1737,26 +1742,27 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags,
int rc;
LDAPMessage *msg = NULL, *e = NULL;
char *dn = NULL, *name = NULL;
+ krb5_boolean is_new_entry;
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);
+ ret = LDAP_principal2message(context, db, entry->principal, &msg);
if (ret == 0)
e = ldap_first_entry(HDB2LDAP(db), msg);
- ret = krb5_unparse_name(context, entry->entry.principal, &name);
+ ret = krb5_unparse_name(context, entry->principal, &name);
if (ret) {
free(name);
return ret;
}
- ret = hdb_seal_keys(context, db, &entry->entry);
+ ret = hdb_seal_keys(context, db, entry);
if (ret)
goto out;
/* turn new entry into LDAPMod array */
- ret = LDAP_entry2mods(context, db, entry, e, &mods);
+ ret = LDAP_entry2mods(context, db, entry, e, &mods, &is_new_entry);
if (ret)
goto out;
@@ -1767,8 +1773,9 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags,
krb5_set_error_message(context, ret, "asprintf: out of memory");
goto out;
}
- } else if (flags & HDB_F_REPLACE) {
+ } else if ((flags & HDB_F_REPLACE) || (is_new_entry)) {
/* Entry exists, and we're allowed to replace it. */
+ /* Entry may also exist but need to be modified to create a new principal. */
dn = ldap_get_dn(HDB2LDAP(db), e);
} else {
/* Entry exists, but we're not allowed to replace it. Bail. */
@@ -1847,6 +1854,8 @@ LDAP_remove(krb5_context context, HDB *db,
goto out;
}
+ /* HACK: This should check if we need to delete the object or just some attributes */
+
rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL );
if (check_ldap(context, db, rc)) {
ret = HDB_ERR_CANT_LOCK_DB;
@@ -1878,6 +1887,7 @@ LDAP_destroy(krb5_context context, HDB * db)
free(HDB2CREATE(db));
if (HDB2URL(db))
free(HDB2URL(db));
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
if (db->hdb_name)
free(db->hdb_name);
free(db->hdb_db);
@@ -2089,6 +2099,7 @@ struct hdb_method hdb_ldap_interface = {
HDB_INTERFACE_VERSION,
init,
fini,
+ 0 /*is_file_based*/, 0 /*can_taste*/,
"ldap",
hdb_ldap_create
};
@@ -2097,6 +2108,7 @@ struct hdb_method hdb_ldapi_interface = {
HDB_INTERFACE_VERSION,
init,
fini,
+ 0 /*is_file_based*/, 0 /*can_taste*/,
"ldapi",
hdb_ldapi_create
};
diff --git a/lib/hdb/hdb-mdb.c b/lib/hdb/hdb-mdb.c
index 52d9aed7ac1f..dd1f27453d5e 100644
--- a/lib/hdb/hdb-mdb.c
+++ b/lib/hdb/hdb-mdb.c
@@ -42,13 +42,289 @@
#define KILO 1024
+#define E(sym, kret) case sym: ret = kret; ename = #sym; break
+
+/* Note: calls krb5_set_error_message() */
+static krb5_error_code
+mdb2krb5_code(krb5_context context, int code)
+{
+ krb5_error_code ret = 0;
+ const char *ename = "UNKNOWN";
+ const char *estr = mdb_strerror(code);
+
+ switch (code) {
+ case MDB_SUCCESS: return 0;
+ E(MDB_KEYEXIST, HDB_ERR_EXISTS);
+ E(MDB_NOTFOUND, HDB_ERR_NOENTRY);
+ E(MDB_PAGE_NOTFOUND, HDB_ERR_UK_SERROR);
+ E(MDB_CORRUPTED, HDB_ERR_UK_SERROR);
+ E(MDB_PANIC, HDB_ERR_UK_SERROR);
+ E(MDB_VERSION_MISMATCH, HDB_ERR_UK_SERROR);
+ E(MDB_INVALID, HDB_ERR_UK_SERROR);
+ E(MDB_MAP_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_DBS_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_READERS_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_TLS_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_TXN_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_CURSOR_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_PAGE_FULL, HDB_ERR_UK_SERROR);
+ E(MDB_MAP_RESIZED, HDB_ERR_UK_SERROR);
+ E(MDB_INCOMPATIBLE, HDB_ERR_UK_SERROR);
+ E(MDB_BAD_RSLOT, HDB_ERR_UK_SERROR);
+ E(MDB_BAD_TXN, HDB_ERR_UK_SERROR);
+ E(MDB_BAD_VALSIZE, HDB_ERR_UK_SERROR);
+ E(MDB_BAD_DBI, HDB_ERR_UK_SERROR);
+ default:
+ if (code > 0 && code < 100)
+ ret = code;
+ else
+ ret = HDB_ERR_UK_SERROR;
+ break;
+ }
+ if (ret)
+ krb5_set_error_message(context, ret, "MDB error %s (%d): %s",
+ ename, code, estr);
+ return ret;
+}
+
typedef struct mdb_info {
MDB_env *e;
MDB_txn *t;
MDB_dbi d;
MDB_cursor *c;
+ int oflags;
+ mode_t mode;
+ size_t mapsize;
+ unsigned int in_tx:1;
} mdb_info;
+/* See below */
+struct keep_it_open {
+ char *path;
+ MDB_env *env;
+ MDB_dbi d;
+ unsigned int oflags;
+ size_t refs;
+ size_t mapsize;
+ unsigned int valid:1;
+ struct keep_it_open *next;
+} *keep_them_open;
+HEIMDAL_MUTEX keep_them_open_lock = HEIMDAL_MUTEX_INITIALIZER;
+
+/*
+ * On Unix LMDB uses fcntl() byte-range locks, and unlike SQLite3 (which also
+ * uses fcntl() byte-range locks) LMDB takes no precautions to avoid early
+ * first-close()s that cause other threads' locks to get dropped. No, LMDB
+ * requires the caller to take such precautions. For us that means opening one
+ * mdb env per-{HDB, mode} (where mode is read-write or read-only), never
+ * closing it, and sharing it with all threads.
+ *
+ * Sharing an MDB_env * across multiple threads is documented to be safe, and
+ * internally LMDB uses pread(2), pwrite(2), and mmap(2) for I/O, using
+ * read(2)/write(2) only in the DB copy routines that we don't use.
+ *
+ * On WIN32 we don't have to do any of this, however, to avoid ifdef spaghetti,
+ * we share this code on all platforms, even if it isn't strictly needed.
+ *
+ * Also, one must call mdb_open() (aka mdb_dbi_open()) only once per call to
+ * mdb_env_open() and per B-tree. We only use one B-tree in each LMDB: the
+ * main one.
+ *
+ * On success this outputs an `MDB_env *' (the handle for the LMDB) and an
+ * `MDB_dbi' (the handle for the main B-tree in the LMDB).
+ *
+ * ALSO, LMDB requires that we re-open the `MDB_env' when the database grows
+ * larger than the mmap size. We handle this by finding in `keep_them_open'
+ * the env we already have, marking it unusable, and the finding some other
+ * better one or opening a new one and adding it to the list.
+ */
+static krb5_error_code
+my_mdb_env_create_and_open(krb5_context context,
+ mdb_info *mi,
+ const char *path,
+ int mapfull)
+{
+ struct keep_it_open *p, *n;
+ MDB_txn *txn = NULL;
+ unsigned int flags = MDB_NOSUBDIR | MDB_NOTLS;
+ struct stat st;
+ size_t mapsize = 0;
+ int max_readers;
+ int locked = 0;
+ int code = 0;
+
+ mi->oflags &= O_ACCMODE;
+ flags |= (mi->oflags == O_RDONLY) ? MDB_RDONLY : 0;
+
+ mi->e = NULL;
+
+ /*
+ * Allocate a new object, in case we don't already have one in
+ * `keep_them_open'; if we don't need it, we'll free it. This way we do
+ * some of the work of creating one while not holding a lock.
+ */
+ if ((n = calloc(1, sizeof(*n))) == NULL ||
+ (n->path = strdup(path)) == NULL) {
+ free(n);
+ return krb5_enomem(context);
+ }
+ n->oflags = mi->oflags;
+
+ max_readers = krb5_config_get_int_default(context, NULL, 0, "kdc",
+ "hdb-mdb-maxreaders", NULL);
+ mapsize = krb5_config_get_int_default(context, NULL, 0, "kdc", "hdb-mdb-mapsize",
+ NULL);
+ if (mapsize > INT_MAX)
+ mapsize = 0;
+
+ memset(&st, 0, sizeof(st));
+ if (stat(path, &st) == 0 && st.st_size > mapsize * KILO)
+ mapsize += (st.st_size + (st.st_size >> 2)) / KILO;
+ if (mapsize < 100 * 1024)
+ mapsize = 100 * 1024; /* 100MB */
+ if (mapsize < mi->mapsize)
+ mapsize = mi->mapsize;
+ if (mapfull)
+ mapsize += 10 * 1024;
+ if ((code = mdb_env_create(&n->env)) ||
+ (max_readers && (code = mdb_env_set_maxreaders(n->env, max_readers))))
+ goto out;
+
+ /* Look for an existing env */
+ HEIMDAL_MUTEX_lock(&keep_them_open_lock);
+ locked = 1;
+ for (p = keep_them_open; p; p = p->next) {
+ if (strcmp(p->path, path) != 0)
+ continue;
+ if (p->mapsize > mapsize)
+ /* Always increase mapsize */
+ mapsize = p->mapsize + (p->mapsize >> 1);
+ if (!p->valid || p->oflags != mi->oflags)
+ continue;
+ /* Found one; output it and get out */
+ mi->e = p->env;
+ mi->d = p->d;
+ p->refs++;
+ goto out;
+ }
+
+ /* Did not find one, so open and add this one to the list */
+
+ /* Open the LMDB itself */
+ n->refs = 1;
+ n->valid = 1;
+ krb5_debug(context, 5, "Opening HDB LMDB %s with mapsize %llu",
+ path, (unsigned long long)mapsize * KILO);
+ code = mdb_env_set_mapsize(n->env, mapsize * KILO);
+ if (code == 0)
+ code = mdb_env_open(n->env, path, flags, mi->mode);
+ if (code == 0)
+ /* Open a transaction so we can resolve the main B-tree */
+ code = mdb_txn_begin(n->env, NULL, MDB_RDONLY, &txn);
+ if (code == 0)
+ /* Resolve the main B-tree */
+ code = mdb_open(txn, NULL, 0, &n->d);
+ if (code)
+ goto out;
+
+ /* Successfully opened the LMDB; output the two handles */
+ mi->mapsize = n->mapsize = mapsize;
+ mi->e = n->env;
+ mi->d = n->d;
+
+ /* Add this keep_it_open to the front of the list */
+ n->next = keep_them_open;
+ keep_them_open = n;
+ n = NULL;
+
+out:
+ if (locked)
+ HEIMDAL_MUTEX_unlock(&keep_them_open_lock);
+ if (n) {
+ if (n->env)
+ mdb_env_close(n->env);
+ free(n->path);
+ free(n);
+ }
+ (void) mdb_txn_commit(txn); /* Safe when `txn == NULL' */
+ return mdb2krb5_code(context, code);
+}
+
+static void
+my_mdb_env_close(krb5_context context,
+ const char *db_name,
+ MDB_env **envp)
+{
+ struct keep_it_open **prev;
+ struct keep_it_open *p, *old;
+ size_t refs_seen = 0;
+ size_t slen = strlen(db_name);
+ MDB_env *env = *envp;
+
+ if (env == NULL)
+ return;
+
+ HEIMDAL_MUTEX_lock(&keep_them_open_lock);
+ for (p = keep_them_open; p; p = p->next) {
+ /*
+ * We can have multiple open ones and we need to know if this is the
+ * last one, so we can't break out early.
+ */
+ if (p->env == env)
+ refs_seen += (--(p->refs));
+ else if (strncmp(db_name, p->path, slen) == 0 &&
+ strcmp(p->path + slen, ".mdb") == 0)
+ refs_seen += p->refs;
+ }
+ krb5_debug(context, 6, "Closing HDB LMDB %s / %p; refs %llu", db_name, env,
+ (unsigned long long)refs_seen);
+ prev = &keep_them_open;
+ for (p = keep_them_open; !refs_seen && p; ) {
+ /* We're the last close */
+ if (p->refs ||
+ strncmp(db_name, p->path, slen) != 0 ||
+ strcmp(p->path + slen, ".mdb") != 0) {
+
+ /* Not us; this keep_it_open stays */
+ prev = &p->next;
+ p = p->next;
+ continue;
+ }
+
+ /* Close and remove this one */
+ krb5_debug(context, 6, "Closing HDB LMDB %s (mapsize was %llu)",
+ db_name, (unsigned long long)p->mapsize * KILO);
+ old = p;
+ *prev = (p = p->next); /* prev stays */
+ mdb_env_close(old->env);
+ free(old->path);
+ free(old);
+ }
+ HEIMDAL_MUTEX_unlock(&keep_them_open_lock);
+}
+
+/*
+ * This is a wrapper around my_mdb_env_create_and_open(). It may close an
+ * existing MDB_env in mi->e if it's there. If we need to reopen because the
+ * MDB grew too much, then we call this.
+ */
+static krb5_error_code
+my_reopen_mdb(krb5_context context, HDB *db, int mapfull)
+{
+ mdb_info *mi = (mdb_info *)db->hdb_db;
+ char *fn;
+ krb5_error_code ret = 0;
+
+ /* No-op if we don't have an open one */
+ my_mdb_env_close(context, db->hdb_name, &mi->e);
+ if (asprintf(&fn, "%s.mdb", db->hdb_name) == -1)
+ ret = krb5_enomem(context);
+ if (ret == 0)
+ ret = my_mdb_env_create_and_open(context, mi, fn, mapfull);
+ free(fn);
+ return ret;
+}
+
static krb5_error_code
DB_close(krb5_context context, HDB *db)
{
@@ -56,7 +332,7 @@ DB_close(krb5_context context, HDB *db)
mdb_cursor_close(mi->c);
mdb_txn_abort(mi->t);
- mdb_env_close(mi->e);
+ my_mdb_env_close(context, db->hdb_name, &mi->e);
mi->c = 0;
mi->t = 0;
mi->e = 0;
@@ -68,7 +344,8 @@ DB_destroy(krb5_context context, HDB *db)
{
krb5_error_code ret;
- ret = hdb_clear_master_key (context, db);
+ ret = hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(db->hdb_name);
free(db->hdb_db);
free(db);
@@ -106,41 +383,44 @@ DB_unlock(krb5_context context, HDB *db)
static krb5_error_code
DB_seq(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry, int flag)
+ unsigned flags, hdb_entry *entry, int flag)
{
mdb_info *mi = db->hdb_db;
MDB_val key, value;
krb5_data key_data, data;
int code;
+ /*
+ * No need to worry about MDB_MAP_FULL when we're scanning the DB since we
+ * have snapshot semantics, and any DB growth from other transactions
+ * should not affect us.
+ */
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;
+ return mdb2krb5_code(context, 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))
+ if (hdb_value2entry(context, &data, 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);
+ code = hdb_unseal_keys (context, db, entry);
if (code)
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
}
- if (entry->entry.principal == NULL) {
- entry->entry.principal = malloc(sizeof(*entry->entry.principal));
- if (entry->entry.principal == NULL) {
- hdb_free_entry (context, entry);
+ if (entry->principal == NULL) {
+ entry->principal = malloc(sizeof(*entry->principal));
+ if (entry->principal == NULL) {
+ hdb_free_entry (context, db, entry);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
} else {
- hdb_key2principal(context, &key_data, entry->entry.principal);
+ hdb_key2principal(context, &key_data, entry->principal);
}
}
return 0;
@@ -148,29 +428,41 @@ DB_seq(krb5_context context, HDB *db,
static krb5_error_code
-DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
+ krb5_error_code ret = 0;
mdb_info *mi = db->hdb_db;
- int code;
+ int tries = 3;
+ int code = 0;
/* 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);
+ do {
+ if (mi->t)
+ mdb_txn_abort(mi->t);
+ mi->t = NULL;
+ if (code)
+ code = my_reopen_mdb(context, db, 1);
+ if (code == 0)
+ code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &mi->t);
+ if (code == 0)
+ code = mdb_cursor_open(mi->t, mi->d, &mi->c);
+ if (code == 0) {
+ ret = DB_seq(context, db, flags, entry, MDB_FIRST);
+ break;
+ }
+ } while (code == MDB_MAP_FULL && --tries > 0);
+
+ if (code || ret) {
+ mdb_txn_abort(mi->t);
+ mi->t = NULL;
+ }
+ return ret ? ret : mdb2krb5_code(context, code);
}
static krb5_error_code
-DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return DB_seq(context, db, flags, entry, MDB_NEXT);
}
@@ -206,24 +498,34 @@ 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_txn *txn = NULL;
MDB_val k, v;
- int code;
+ int tries = 3;
+ int code = 0;
k.mv_data = key.data;
k.mv_size = key.length;
- code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &txn);
- if (code)
- return code;
+ do {
+ if (txn) {
+ mdb_txn_abort(txn);
+ txn = NULL;
+ }
+ if (code)
+ code = my_reopen_mdb(context, db, 1);
+ if (code == 0)
+ code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &txn);
+ if (code == 0)
+ code = mdb_get(txn, mi->d, &k, &v);
+ if (code == 0)
+ krb5_data_copy(reply, v.mv_data, v.mv_size);
+ } while (code == MDB_MAP_FULL && --tries > 0);
- 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;
+ if (code)
+ mdb_txn_abort(txn);
+ else
+ (void) mdb_txn_commit(txn); /* Empty transaction? -> commit */
+ return mdb2krb5_code(context, code);
}
static krb5_error_code
@@ -231,137 +533,110 @@ 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_txn *txn = NULL;
MDB_val k, v;
- int code;
+ int tries = 3;
+ int code = 0;
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);
- /*
- * No need to call mdb_env_sync(); it's done automatically if MDB_NOSYNC is
- * not set.
- */
- if(code == MDB_KEYEXIST)
- return HDB_ERR_EXISTS;
- return code;
+ do {
+ if (txn) {
+ mdb_txn_abort(txn);
+ txn = NULL;
+ }
+ if (code)
+ code = my_reopen_mdb(context, db, 1);
+ if (code == 0)
+ code = mdb_txn_begin(mi->e, NULL, 0, &txn);
+ if (code == 0)
+ code = mdb_put(txn, mi->d, &k, &v, replace ? 0 : MDB_NOOVERWRITE);
+ if (code == 0) {
+ /*
+ * No need to call mdb_env_sync(); it's done automatically if
+ * MDB_NOSYNC is not set.
+ */
+ code = mdb_txn_commit(txn);
+ txn = NULL;
+ }
+ } while (code == MDB_MAP_FULL && --tries > 0);
+ if (txn)
+ mdb_txn_abort(txn);
+ return mdb2krb5_code(context, 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_txn *txn = NULL;
MDB_val k;
- krb5_error_code code;
+ int tries = 3;
+ int code = 0;
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);
- /*
- * No need to call mdb_env_sync(); it's done automatically if MDB_NOSYNC is
- * not set.
- */
- if(code == MDB_NOTFOUND)
- return HDB_ERR_NOENTRY;
- return code;
+ do {
+ if (txn) {
+ mdb_txn_abort(txn);
+ txn = NULL;
+ }
+ if (code)
+ code = my_reopen_mdb(context, db, 1);
+ if (code == 0)
+ code = mdb_txn_begin(mi->e, NULL, 0, &txn);
+ if (code == 0)
+ code = mdb_del(txn, mi->d, &k, NULL);
+ if (code == 0) {
+ /*
+ * No need to call mdb_env_sync(); it's done automatically if
+ * MDB_NOSYNC is not set.
+ */
+ code = mdb_txn_commit(txn);
+ txn = NULL;
+ }
+ } while (code == MDB_MAP_FULL && --tries > 0);
+
+ if (txn)
+ mdb_txn_abort(txn);
+ return mdb2krb5_code(context, code);
}
static krb5_error_code
-DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
+DB_open(krb5_context context, HDB *db, int oflags, 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);
+ mi->e = NULL;
+ mi->mode = mode;
+ mi->oflags = oflags & O_ACCMODE;
+ ret = my_reopen_mdb(context, db, 0);
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));
+ krb5_prepend_error_message(context, ret, "opening %s:", db->hdb_name);
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)
+ if ((oflags & O_ACCMODE) == O_RDONLY) {
ret = hdb_check_db_format(context, db);
- else
+ /*
+ * Dubious: if the DB is not initialized, shouldn't we tell the
+ * caller??
+ */
+ if (ret == HDB_ERR_NOENTRY)
+ return 0;
+ } else {
+ /* hdb_init_db() calls hdb_check_db_format() */
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 ?
+ (oflags & O_ACCMODE) == O_RDONLY ?
"checking format of" : "initialize",
db->hdb_name);
}
diff --git a/lib/hdb/hdb-mitdb.c b/lib/hdb/hdb-mitdb.c
index 7a9438cbe1ea..ae315cd831d9 100644
--- a/lib/hdb/hdb-mitdb.c
+++ b/lib/hdb/hdb-mitdb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -108,6 +108,7 @@ attr_to_flags(unsigned attr, HDBFlags *flags)
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->require_pwchange = !!(attr & KRB5_KDB_REQUIRES_PWCHANGE);
flags->server = !(attr & KRB5_KDB_DISALLOW_SVR);
flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE);
flags->client = 1; /* XXX */
@@ -554,7 +555,7 @@ _hdb_mdb_value2entry(krb5_context context, krb5_data *data,
goto out;
}
CHECK(ret = krb5_parse_name(context, p, &modby));
- ret = hdb_set_last_modified_by(context, entry, modby, u32);
+ CHECK(ret = hdb_set_last_modified_by(context, entry, modby, u32));
krb5_free_principal(context, modby);
free(p);
break;
@@ -661,7 +662,7 @@ out:
if (ret == HEIM_ERR_EOF)
/* Better error code than "end of file" */
ret = HEIM_ERR_BAD_HDBENT_ENCODING;
- free_hdb_entry(entry);
+ free_HDB_entry(entry);
free_Key(&k);
return ret;
}
@@ -696,7 +697,8 @@ mdb_destroy(krb5_context context, HDB *db)
{
krb5_error_code ret;
- ret = hdb_clear_master_key (context, db);
+ ret = hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(db->hdb_name);
free(db);
return ret;
@@ -763,11 +765,11 @@ mdb_unlock(krb5_context context, HDB *db)
static krb5_error_code
mdb_seq(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry, int flag)
+ unsigned flags, hdb_entry *entry, int flag)
{
DB *d = (DB*)db->hdb_db;
DBT key, value;
- krb5_data key_data, data;
+ krb5_data data;
int code;
code = db->hdb_lock(context, db, HDB_RLOCK);
@@ -788,19 +790,17 @@ mdb_seq(krb5_context context, HDB *db,
return HDB_ERR_NOENTRY;
}
- key_data.data = key.data;
- key_data.length = key.size;
data.data = value.data;
data.length = value.size;
memset(entry, 0, sizeof(*entry));
- if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry))
+ if (_hdb_mdb_value2entry(context, &data, 0, entry))
return mdb_seq(context, db, flags, entry, R_NEXT);
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- code = hdb_unseal_keys (context, db, &entry->entry);
+ code = hdb_unseal_keys (context, db, entry);
if (code)
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
}
return code;
@@ -808,14 +808,14 @@ mdb_seq(krb5_context context, HDB *db,
static krb5_error_code
-mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return mdb_seq(context, db, flags, entry, R_FIRST);
}
static krb5_error_code
-mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
+mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
return mdb_seq(context, db, flags, entry, R_NEXT);
}
@@ -939,7 +939,7 @@ mdb__del(krb5_context context, HDB *db, krb5_data key)
static krb5_error_code
mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
- unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
+ unsigned flags, krb5_kvno kvno, hdb_entry *entry)
{
krb5_data key, value;
krb5_error_code ret;
@@ -951,15 +951,15 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
krb5_data_free(&key);
if(ret)
return ret;
- ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry);
+ ret = _hdb_mdb_value2entry(context, &value, kvno, entry);
krb5_data_free(&value);
if (ret)
return ret;
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- ret = hdb_unseal_keys (context, db, &entry->entry);
+ ret = hdb_unseal_keys (context, db, entry);
if (ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
return ret;
}
}
@@ -968,7 +968,7 @@ 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)
+mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
{
krb5_error_code ret;
krb5_storage *sp = NULL;
@@ -977,13 +977,13 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
krb5_data kdb_ent = { 0, 0 };
krb5_data key = { 0, 0 };
krb5_data value = { 0, 0 };
- ssize_t sz;
+ krb5_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);
+ ret = mdb_principal2key(context, entry->principal, &key);
if (ret) return ret;
ret = db->hdb__get(context, db, key, &value);
krb5_data_free(&key);
@@ -997,13 +997,13 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
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);
+ ret = hdb_seal_keys(context, db, entry);
if (ret) return ret;
- ret = entry2mit_string_int(context, sp, &entry->entry);
+ ret = entry2mit_string_int(context, sp, entry);
if (ret) goto out;
sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */
ret = ENOMEM;
- if (sz == -1) goto out;
+ if (sz != 2) goto out;
ret = krb5_storage_to_data(sp, &line);
if (ret) goto out;
@@ -1014,7 +1014,7 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
if (ret) goto out;
ret = krb5_storage_to_data(spent, &kdb_ent);
if (ret) goto out;
- ret = mdb_principal2key(context, entry->entry.principal, &key);
+ ret = mdb_principal2key(context, entry->principal, &key);
if (ret) goto out;
ret = mdb__put(context, db, 1, key, kdb_ent);
@@ -1038,9 +1038,8 @@ mdb_remove(krb5_context context, HDB *db,
krb5_data key;
krb5_data value = { 0, 0 };
- code = mdb_principal2key(context, principal, &key);
- if (code)
- return code;
+ mdb_principal2key(context, principal, &key);
+
if ((flags & HDB_F_PRECHECK)) {
code = db->hdb__get(context, db, key, &value);
krb5_data_free(&key);
@@ -1252,17 +1251,16 @@ getdata(char **p, unsigned char *buf, size_t len, const char *what)
}
static int
-getint(char **p, const char *what)
+getint(char **p, const char *what, int *val)
{
- int val;
char *q = nexttoken(p, 0, what);
if (!q) {
warnx("Failed to find a signed integer (%s) in dump", what);
- return -1;
+ return 1;
}
- if (sscanf(q, "%d", &val) != 1)
- return -1;
- return val;
+ if (sscanf(q, "%d", val) != 1)
+ return 1;
+ return 0;
}
static unsigned int
@@ -1309,7 +1307,7 @@ _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;
+ krb5_ssize_t sz;
size_t i;
size_t princ_len;
unsigned int num_tl_data;
@@ -1326,7 +1324,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
"'policy', nor 'princ'");
return -1;
}
- if (getint(&p, "constant '38'") != 38) {
+ if (getint(&p, "constant '38'", &tmp) || tmp != 38) {
warnx("Dump entry does not start with '38<TAB>'");
return EINVAL;
}
@@ -1342,7 +1340,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
}
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'");
+ (void) getint(&p, "5th field, length of 'extra data'", &tmp);
princ = nexttoken(&p, (int)princ_len, "principal name");
if (princ == NULL) {
warnx("Failed to read principal name (expected length %llu)",
@@ -1354,38 +1352,31 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
ret = krb5_store_uint32(sp, attributes);
if (ret) return ret;
- tmp = getint(&p, "max life");
- CHECK_UINT(tmp);
+ if (getint(&p, "max life", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p, "max renewable life");
- CHECK_UINT(tmp);
+ if (getint(&p, "max renewable life", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p, "expiration");
- CHECK_UINT(tmp);
+ if (getint(&p, "expiration", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p, "pw expiration");
- CHECK_UINT(tmp);
+ if (getint(&p, "pw expiration", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p, "last auth");
- CHECK_UINT(tmp);
+ if (getint(&p, "last auth", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p, "last failed auth");
- CHECK_UINT(tmp);
+ if (getint(&p, "last failed auth", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
- tmp = getint(&p,"fail auth count");
- CHECK_UINT(tmp);
+ if (getint(&p,"fail auth count", &tmp)) return EINVAL;
ret = krb5_store_uint32(sp, tmp);
if (ret) return ret;
@@ -1405,7 +1396,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
ret = krb5_store_uint16(sp, princ_len);
if (ret) return ret;
sz = krb5_storage_write(sp, princ, princ_len);
- if (sz == -1) return ENOMEM;
+ if (sz != princ_len) return ENOMEM;
/* scan and write TL data */
for (i = 0; i < num_tl_data; i++) {
@@ -1413,8 +1404,9 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
int tl_type, tl_length;
unsigned char *buf;
- tl_type = getint(&p, "TL data type");
- tl_length = getint(&p, "data length");
+ if (getint(&p, "TL data type", &tl_type) ||
+ getint(&p, "data length", &tl_length))
+ return EINVAL;
if (asprintf(&reading_what, "TL data type %d (length %d)",
tl_type, tl_length) < 0)
@@ -1434,11 +1426,13 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
if (tl_length) {
buf = malloc(tl_length);
if (!buf) return ENOMEM;
- if (getdata(&p, buf, tl_length, reading_what) != tl_length)
+ if (getdata(&p, buf, tl_length, reading_what) != tl_length) {
+ free(buf);
return EINVAL;
+ }
sz = krb5_storage_write(sp, buf, tl_length);
free(buf);
- if (sz == -1) return ENOMEM;
+ if (sz != tl_length) return ENOMEM;
} else {
if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL;
}
@@ -1453,23 +1447,23 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
int keylen;
size_t k;
- key_versions = getint(&p, "key data 'version'");
+ if (getint(&p, "key data 'version'", &key_versions)) return EINVAL;
CHECK_UINT16(key_versions);
ret = krb5_store_int16(sp, key_versions);
if (ret) return ret;
- kvno = getint(&p, "kvno");
+ if (getint(&p, "kvno", &kvno)) return EINVAL;
CHECK_UINT16(kvno);
ret = krb5_store_int16(sp, kvno);
if (ret) return ret;
for (k = 0; k < key_versions; k++) {
- keytype = getint(&p, "enctype");
+ if (getint(&p, "enctype", &keytype)) return EINVAL;
CHECK_UINT16(keytype);
ret = krb5_store_int16(sp, keytype);
if (ret) return ret;
- keylen = getint(&p, "encrypted key length");
+ if (getint(&p, "encrypted key length", &keylen)) return EINVAL;
CHECK_UINT16(keylen);
ret = krb5_store_int16(sp, keylen);
if (ret) return ret;
@@ -1477,11 +1471,13 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp)
if (keylen) {
buf = malloc(keylen);
if (!buf) return ENOMEM;
- if (getdata(&p, buf, keylen, "key (or salt) data") != keylen)
+ if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) {
+ free(buf);
return EINVAL;
+ }
sz = krb5_storage_write(sp, buf, keylen);
free(buf);
- if (sz == -1) return ENOMEM;
+ if (sz != keylen) return ENOMEM;
} else {
if (strcmp(nexttoken(&p, 0,
"'-1' zero-length key/salt field"),
diff --git a/lib/hdb/hdb-private.h b/lib/hdb/hdb-private.h
deleted file mode 100644
index 82681997681f..000000000000
--- a/lib/hdb/hdb-private.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This is a generated file */
-#ifndef __hdb_private_h__
-#define __hdb_private_h__
-
-#include <stdarg.h>
-
-krb5_error_code
-_hdb_fetch_kvno (
- krb5_context /*context*/,
- HDB */*db*/,
- krb5_const_principal /*principal*/,
- unsigned /*flags*/,
- krb5_kvno /*kvno*/,
- hdb_entry_ex */*entry*/);
-
-hdb_master_key
-_hdb_find_master_key (
- unsigned int */*mkvno*/,
- hdb_master_key /*mkey*/);
-
-krb5_error_code
-_hdb_keytab2hdb_entry (
- krb5_context /*context*/,
- 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*/,
- hdb_master_key /*key*/,
- krb5_key_usage /*usage*/,
- void */*ptr*/,
- size_t /*size*/,
- krb5_data */*res*/);
-
-int
-_hdb_mkey_encrypt (
- krb5_context /*context*/,
- hdb_master_key /*key*/,
- krb5_key_usage /*usage*/,
- const void */*ptr*/,
- size_t /*size*/,
- krb5_data */*res*/);
-
-int
-_hdb_mkey_version (hdb_master_key /*mkey*/);
-
-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*/,
- unsigned /*flags*/,
- hdb_entry_ex */*entry*/);
-
-#endif /* __hdb_private_h__ */
diff --git a/lib/hdb/hdb-protos.h b/lib/hdb/hdb-protos.h
deleted file mode 100644
index 76855095beed..000000000000
--- a/lib/hdb/hdb-protos.h
+++ /dev/null
@@ -1,592 +0,0 @@
-/* This is a generated file */
-#ifndef __hdb_protos_h__
-#define __hdb_protos_h__
-#ifndef DOXY
-
-#include <stdarg.h>
-
-#ifdef __cplusplus
-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*/,
- HDB */*db*/);
-
-krb5_error_code
-hdb_clear_extension (
- krb5_context /*context*/,
- hdb_entry */*entry*/,
- int /*type*/);
-
-krb5_error_code
-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*/,
- HDB **/*db*/,
- const char */*filename*/);
-
-krb5_error_code
-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*/);
-
-const char *
-hdb_dbinfo_get_acl_file (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-const krb5_config_binding *
-hdb_dbinfo_get_binding (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-const char *
-hdb_dbinfo_get_dbname (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-const char *
-hdb_dbinfo_get_label (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-const char *
-hdb_dbinfo_get_log_file (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-const char *
-hdb_dbinfo_get_mkey_file (
- krb5_context /*context*/,
- struct hdb_dbinfo */*dbp*/);
-
-struct hdb_dbinfo *
-hdb_dbinfo_get_next (
- struct hdb_dbinfo */*dbp*/,
- struct hdb_dbinfo */*dbprevp*/);
-
-const char *
-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*/);
-
-krb5_error_code
-hdb_enctype2key (
- krb5_context /*context*/,
- hdb_entry */*e*/,
- const Keys */*keyset*/,
- krb5_enctype /*enctype*/,
- Key **/*key*/);
-
-krb5_error_code
-hdb_entry2string (
- krb5_context /*context*/,
- hdb_entry */*ent*/,
- char **/*str*/);
-
-int
-hdb_entry2value (
- krb5_context /*context*/,
- const hdb_entry */*ent*/,
- krb5_data */*value*/);
-
-int
-hdb_entry_alias2value (
- krb5_context /*context*/,
- const hdb_entry_alias */*alias*/,
- krb5_data */*value*/);
-
-krb5_error_code
-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*/,
- hdb_entry */*entry*/);
-
-krb5_error_code
-hdb_entry_get_ConstrainedDelegACL (
- const hdb_entry */*entry*/,
- const HDB_Ext_Constrained_delegation_acl **/*a*/);
-
-krb5_error_code
-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*/,
- HDB */*db*/,
- const hdb_entry */*entry*/,
- char **/*p*/);
-
-krb5_error_code
-hdb_entry_get_pkinit_acl (
- const hdb_entry */*entry*/,
- const HDB_Ext_PKINIT_acl **/*a*/);
-
-krb5_error_code
-hdb_entry_get_pkinit_cert (
- const hdb_entry */*entry*/,
- const HDB_Ext_PKINIT_cert **/*a*/);
-
-krb5_error_code
-hdb_entry_get_pkinit_hash (
- const hdb_entry */*entry*/,
- const HDB_Ext_PKINIT_hash **/*a*/);
-
-krb5_error_code
-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*/,
- HDB */*db*/,
- hdb_entry */*entry*/,
- const char */*p*/);
-
-krb5_error_code
-hdb_entry_set_pw_change_time (
- krb5_context /*context*/,
- hdb_entry */*entry*/,
- time_t /*t*/);
-
-HDB_extension *
-hdb_find_extension (
- const hdb_entry */*entry*/,
- int /*type*/);
-
-krb5_error_code
-hdb_foreach (
- krb5_context /*context*/,
- HDB */*db*/,
- unsigned /*flags*/,
- hdb_foreach_func_t /*func*/,
- void */*data*/);
-
-void
-hdb_free_dbinfo (
- krb5_context /*context*/,
- struct hdb_dbinfo **/*dbp*/);
-
-void
-hdb_free_entry (
- krb5_context /*context*/,
- hdb_entry_ex */*ent*/);
-
-void
-hdb_free_key (Key */*key*/);
-
-void
-hdb_free_keys (
- krb5_context /*context*/,
- int /*len*/,
- Key */*keys*/);
-
-void
-hdb_free_master_key (
- krb5_context /*context*/,
- hdb_master_key /*mkey*/);
-
-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*/);
-
-krb5_error_code
-hdb_generate_key_set_password (
- krb5_context /*context*/,
- krb5_principal /*principal*/,
- const char */*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*/,
- struct hdb_dbinfo **/*dbp*/);
-
-krb5_error_code
-hdb_init_db (
- krb5_context /*context*/,
- HDB */*db*/);
-
-int
-hdb_key2principal (
- krb5_context /*context*/,
- krb5_data */*key*/,
- krb5_principal /*p*/);
-
-krb5_error_code
-hdb_keytab_create (
- krb5_context /*context*/,
- 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*/,
- HDB ** /*db*/,
- const char */*arg*/);
-
-krb5_error_code
-hdb_ldapi_create (
- krb5_context /*context*/,
- HDB ** /*db*/,
- const char */*arg*/);
-
-krb5_error_code
-hdb_list_builtin (
- krb5_context /*context*/,
- char **/*list*/);
-
-krb5_error_code
-hdb_lock (
- int /*fd*/,
- int /*operation*/);
-
-krb5_error_code
-hdb_mdb_create (
- krb5_context /*context*/,
- HDB **/*db*/,
- 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*/,
- const char */*filename*/);
-
-krb5_error_code
-hdb_next_enctype2key (
- krb5_context /*context*/,
- const hdb_entry */*e*/,
- const Keys */*keyset*/,
- krb5_enctype /*enctype*/,
- Key **/*key*/);
-
-int
-hdb_principal2key (
- krb5_context /*context*/,
- krb5_const_principal /*p*/,
- krb5_data */*key*/);
-
-krb5_error_code
-hdb_print_entry (
- krb5_context /*context*/,
- HDB */*db*/,
- hdb_entry_ex */*entry*/,
- void */*data*/);
-
-krb5_error_code
-hdb_process_master_key (
- krb5_context /*context*/,
- int /*kvno*/,
- krb5_keyblock */*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*/,
- const char */*filename*/,
- hdb_master_key */*mkey*/);
-
-krb5_error_code
-hdb_replace_extension (
- krb5_context /*context*/,
- hdb_entry */*entry*/,
- const HDB_extension */*ext*/);
-
-krb5_error_code
-hdb_seal_key (
- krb5_context /*context*/,
- HDB */*db*/,
- Key */*k*/);
-
-krb5_error_code
-hdb_seal_key_mkey (
- krb5_context /*context*/,
- Key */*k*/,
- hdb_master_key /*mkey*/);
-
-krb5_error_code
-hdb_seal_keys (
- krb5_context /*context*/,
- HDB */*db*/,
- hdb_entry */*ent*/);
-
-krb5_error_code
-hdb_seal_keys_mkey (
- krb5_context /*context*/,
- hdb_entry */*ent*/,
- 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*/,
- krb5_keyblock */*key*/);
-
-krb5_error_code
-hdb_set_master_keyfile (
- krb5_context /*context*/,
- 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 */*filename*/);
-
-krb5_error_code
-hdb_unlock (int /*fd*/);
-
-krb5_error_code
-hdb_unseal_key (
- krb5_context /*context*/,
- HDB */*db*/,
- Key */*k*/);
-
-krb5_error_code
-hdb_unseal_key_mkey (
- krb5_context /*context*/,
- Key */*k*/,
- hdb_master_key /*mkey*/);
-
-krb5_error_code
-hdb_unseal_keys (
- krb5_context /*context*/,
- HDB */*db*/,
- 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*/,
- hdb_master_key /*mkey*/);
-
-int
-hdb_value2entry (
- krb5_context /*context*/,
- krb5_data */*value*/,
- hdb_entry */*ent*/);
-
-int
-hdb_value2entry_alias (
- krb5_context /*context*/,
- krb5_data */*value*/,
- hdb_entry_alias */*ent*/);
-
-krb5_error_code
-hdb_write_master_key (
- krb5_context /*context*/,
- const char */*filename*/,
- hdb_master_key /*mkey*/);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* DOXY */
-#endif /* __hdb_protos_h__ */
diff --git a/lib/hdb/hdb-sqlite.c b/lib/hdb/hdb-sqlite.c
index d5eb3f184e84..4bb2f8e8553c 100644
--- a/lib/hdb/hdb-sqlite.c
+++ b/lib/hdb/hdb-sqlite.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -41,6 +41,7 @@ typedef struct hdb_sqlite_db {
sqlite3 *db;
char *db_file;
+ sqlite3_stmt *connect;
sqlite3_stmt *get_version;
sqlite3_stmt *fetch;
sqlite3_stmt *get_ids;
@@ -82,6 +83,8 @@ typedef struct hdb_sqlite_db {
" DELETE FROM Principal" \
" WHERE entry = OLD.id;" \
" END"
+#define HDBSQLITE_CONNECT \
+ " PRAGMA journal_mode = WAL"
#define HDBSQLITE_GET_VERSION \
" SELECT number FROM Version"
#define HDBSQLITE_FETCH \
@@ -156,6 +159,11 @@ prep_stmts(krb5_context context, hdb_sqlite_db *hsdb)
int ret;
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
+ &hsdb->connect,
+ HDBSQLITE_CONNECT);
+ if (ret)
+ return ret;
+ ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
&hsdb->get_version,
HDBSQLITE_GET_VERSION);
if (ret)
@@ -209,6 +217,10 @@ prep_stmts(krb5_context context, hdb_sqlite_db *hsdb)
static void
finalize_stmts(krb5_context context, hdb_sqlite_db *hsdb)
{
+ if (hsdb->connect != NULL)
+ sqlite3_finalize(hsdb->connect);
+ hsdb->connect = NULL;
+
if (hsdb->get_version != NULL)
sqlite3_finalize(hsdb->get_version);
hsdb->get_version = NULL;
@@ -316,6 +328,8 @@ bind_principal(krb5_context context, krb5_const_principal principal, sqlite3_stm
return 0;
}
+static int hdb_sqlite_step(krb5_context, sqlite3 *, sqlite3_stmt *);
+
/**
* Opens an sqlite3 database handle to a file, may create the
* database file depending on flags.
@@ -346,7 +360,6 @@ hdb_sqlite_open_database(krb5_context context, HDB *db, int flags)
ret = krb5_enomem(context);
return ret;
}
-
return 0;
}
@@ -436,6 +449,10 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename)
ret = prep_stmts(context, hsdb);
if (ret) goto out;
+ sqlite3_reset(hsdb->connect);
+ (void) hdb_sqlite_step(context, hsdb->db, hsdb->connect);
+ sqlite3_reset(hsdb->connect);
+
ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version);
if(ret == SQLITE_ROW) {
hsdb->version = sqlite3_column_double(hsdb->get_version, 0);
@@ -478,7 +495,7 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename)
*/
static krb5_error_code
hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
- unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
+ unsigned flags, krb5_kvno kvno, hdb_entry *entry)
{
int sqlite_error;
krb5_error_code ret;
@@ -524,14 +541,14 @@ hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal princi
value.length = sqlite3_column_bytes(fetch, 0);
value.data = (void *) sqlite3_column_blob(fetch, 0);
- ret = hdb_value2entry(context, &value, &entry->entry);
+ ret = hdb_value2entry(context, &value, entry);
if(ret)
goto out;
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- ret = hdb_unseal_keys(context, db, &entry->entry);
+ ret = hdb_unseal_keys(context, db, entry);
if(ret) {
- hdb_free_entry(context, entry);
+ hdb_free_entry(context, db, entry);
goto out;
}
}
@@ -583,7 +600,7 @@ hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement)
*/
static krb5_error_code
hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
- hdb_entry_ex *entry)
+ hdb_entry *entry)
{
int ret;
int i;
@@ -607,17 +624,17 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
goto rollback;
}
- ret = hdb_seal_keys(context, db, &entry->entry);
+ ret = hdb_seal_keys(context, db, entry);
if(ret) {
goto rollback;
}
- ret = hdb_entry2value(context, &entry->entry, &value);
+ ret = hdb_entry2value(context, entry, &value);
if(ret) {
goto rollback;
}
- ret = bind_principal(context, entry->entry.principal, get_ids, 1);
+ ret = bind_principal(context, entry->principal, get_ids, 1);
if (ret)
goto rollback;
@@ -639,7 +656,7 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
goto rollback;
}
- ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1);
+ ret = bind_principal(context, entry->principal, hsdb->add_principal, 1);
if (ret)
goto rollback;
@@ -667,8 +684,10 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
} else if(ret == SQLITE_ROW) { /* Found a principal */
- if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
+ if(!(flags & HDB_F_REPLACE)) {
+ ret = HDB_ERR_EXISTS;
goto rollback;
+ }
entry_id = sqlite3_column_int64(get_ids, 1);
@@ -694,7 +713,7 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
goto rollback;
}
- ret = hdb_entry_get_aliases(&entry->entry, &aliases);
+ ret = hdb_entry_get_aliases(entry, &aliases);
if(ret || aliases == NULL)
goto commit;
@@ -800,7 +819,9 @@ hdb_sqlite_destroy(krb5_context context, HDB *db)
hsdb = (hdb_sqlite_db*)(db->hdb_db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(hsdb->db_file);
+ free(db->hdb_name);
free(db->hdb_db);
free(db);
@@ -843,7 +864,7 @@ hdb_sqlite_unlock(krb5_context context, HDB *db)
*/
static krb5_error_code
hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
- hdb_entry_ex *entry)
+ hdb_entry *entry)
{
krb5_error_code ret = 0;
int sqlite_error;
@@ -857,7 +878,7 @@ hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
memset(entry, 0, sizeof(*entry));
- ret = hdb_value2entry(context, &value, &entry->entry);
+ ret = hdb_value2entry(context, &value, entry);
}
else if(sqlite_error == SQLITE_DONE) {
/* No more entries */
@@ -881,7 +902,7 @@ hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
*/
static krb5_error_code
hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
- hdb_entry_ex *entry)
+ hdb_entry *entry)
{
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
krb5_error_code ret;
@@ -931,11 +952,12 @@ hdb_sqlite_remove(krb5_context context, HDB *db,
sqlite3_stmt *get_ids = hsdb->get_ids;
sqlite3_stmt *rm = hsdb->remove;
- bind_principal(context, principal, rm, 1);
+ ret = bind_principal(context, principal, rm, 1);
- ret = hdb_sqlite_exec_stmt(context, hsdb,
- "BEGIN IMMEDIATE TRANSACTION",
- HDB_ERR_UK_SERROR);
+ if (ret == 0)
+ 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);
@@ -1024,13 +1046,13 @@ hdb_sqlite_create(krb5_context context, HDB **db, const char *filename)
if (ret) {
free((*db)->hdb_db);
free(*db);
-
+ *db = NULL;
return ret;
}
(*db)->hdb_master_key_set = 0;
(*db)->hdb_openp = 0;
- (*db)->hdb_capability_flags = 0;
+ (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
(*db)->hdb_open = hdb_sqlite_open;
(*db)->hdb_close = hdb_sqlite_close;
diff --git a/lib/hdb/hdb.asn1 b/lib/hdb/hdb.asn1
index 333ccb064196..49318c811336 100644
--- a/lib/hdb/hdb.asn1
+++ b/lib/hdb/hdb.asn1
@@ -4,7 +4,7 @@ BEGIN
IMPORTS EncryptionKey, KerberosTime, Principal FROM krb5;
-HDB_DB_FORMAT INTEGER ::= 2 -- format of database,
+hdb_db_format INTEGER ::= 2 -- format of database,
-- update when making changes
-- these must have the same value as the pa-* counterparts
@@ -49,6 +49,19 @@ HDBFlags ::= BIT STRING {
locked-out(17), -- Account is locked out,
-- authentication will be denied
require-pwchange(18), -- require a passwd change
+
+ materialize(19), -- store even if within virtual namespace
+ virtual-keys(20), -- entry stored; keys mostly derived
+ virtual(21), -- entry not stored; keys always derived
+ synthetic(22), -- entry not stored; for PKINIT
+ no-auth-data-reqd(23), -- omit PAC from service tickets
+ auth-data-reqd(24), -- include PAC in service tickets
+
+ force-canonicalize(30), -- force the KDC to return the canonical
+ -- principal irrespective of the setting
+ -- of the canonicalize KDC option
+ -- (principals cannot have this flag
+ -- set when stored into the HDB)
do-not-store(31) -- Not to be modified and stored in HDB
}
@@ -91,15 +104,93 @@ HDB-Ext-Aliases ::= SEQUENCE {
Keys ::= SEQUENCE OF Key
-hdb_keyset ::= SEQUENCE {
+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-Ext-KeySet ::= SEQUENCE OF HDB_keyset
+
+--
+-- We need a function of current (or given, but it will always be current) time
+-- and a base hdb_entry or its HDB-Ext-KeyRotation and service ticket lifetime,
+-- that outputs a sequence of {kvno, set_time, max_life} representing past keys
+-- (up to one per past and current KeyRotation), current keys (for the current
+-- KeyRotation), up to one future key for the current KeyRotation, and up to
+-- one future key for the _next_ (future) KeyRotation if there is one.
+--
+-- We have to impose constraints on new KeyRotation elements of
+-- HDB-Ext-KeyRotation.
+--
+-- So virtual keysets (keytabs) will contain:
+--
+-- - up to one past keyset for all KeyRotation periods that are "applicable"
+-- - the current keyset for all KeyRotation periods that are "applicable"
+-- - up to one future keyset for all KeyRotation periods that are "applicable"
+--
+-- An applicable KeyRotation period is:
+--
+-- - the KeyRotation whose `epoch` is a) in the past and b) nearest to the
+-- current time - we call this the current KeyRotation
+-- - a KeyRotation whose `epoch` is nearest but in the past of the current
+-- one
+-- - a KeyRotation whose `epoch` is nearest but in the future of the current
+-- one
+--
+-- A service principal's max ticket life will be bounded by half the current
+-- key rotation period.
+--
+-- Note: There can be more than one applicable past KeyRotation, and more than
+-- one applicable KeyRotation. We might not want to permit this.
+-- However, it's probably easier to permit it, though we might not test
+-- end-to-end.
+--
+-- Testing:
+--
+-- - We should have standalone unit tests for all these pure functions.
+--
+-- - We should have a test that uses kadm5 and GSS to test against a KDC using
+-- small key rotation periods on the order of seconds, with back-off in case
+-- of losing a race condition.
+--
+KeyRotationFlags ::= BIT STRING {
+ deleted(0), -- if set on a materialized principal, this will mean
+ -- the principal does not exist
+ -- if set on a namespace, this will mean that
+ -- only materialized principal below it exist
+ parent(1) -- if set on a materialized principal, this will mean
+ -- that the keys for kvnos in this KeyRotation spec
+ -- will be derived from the parent's base keys and
+ -- corresponding KeyRotation spec
+ -- if set on a namespace, this flag will be ignored
+ -- (or we could support nested namespaces?)
+}
+KeyRotation ::= SEQUENCE {
+ -- base-kvno is always computed at set time and set for the principal,
+ -- and is never subject to admin choice. The base-kvno is that of the
+ -- current kvno at that period's `from` given the previous period.
+ --
+ -- Also, insertion of KeyRotation elements before existing ones (in
+ -- time) is never permitted, and all new KeyRotation elements must be
+ -- in the future relative to existing ones.
+ --
+ -- HDB-Ext-KeyRotation will always be sorted (as stored) by `from`, in
+ -- descending order.
+ --
+ -- Max service ticket lifetime will be constrained to no more than half
+ -- the period of the the applicable KeyRotation elements.
+ --
+ flags[0] KeyRotationFlags,
+ epoch[1] KerberosTime, -- start of this period
+ period[2] INTEGER(0..4294967295), -- key rotation seconds
+ base-kvno[3] INTEGER(0..4294967295), -- starting from this kvno
+ base-key-kvno[4]INTEGER(0..4294967295), -- kvno of base-key
+ ...
+}
+HDB-Ext-KeyRotation ::= SEQUENCE SIZE (1..3) OF KeyRotation
HDB-extension ::= SEQUENCE {
mandatory[0] BOOLEAN, -- kdc MUST understand this extension,
@@ -108,7 +199,7 @@ HDB-extension ::= SEQUENCE {
data[1] CHOICE {
pkinit-acl[0] HDB-Ext-PKINIT-acl,
pkinit-cert-hash[1] HDB-Ext-PKINIT-hash,
- allowed-to-delegate-to[2] HDB-Ext-Constrained-delegation-acl,
+ allowed-to-delegate-to[2] HDB-Ext-Constrained-delegation-acl,
-- referral-info[3] HDB-Ext-Referrals,
lm-owf[4] HDB-Ext-Lan-Manager-OWF,
password[5] HDB-Ext-Password,
@@ -120,6 +211,8 @@ HDB-extension ::= SEQUENCE {
hist-kvno-diff-svc[11] INTEGER (0..4294967295),
policy[12] UTF8String,
principal-id[13] INTEGER(-9223372036854775808..9223372036854775807),
+ key-rotation[14] HDB-Ext-KeyRotation,
+ krb5-config[15] OCTET STRING,
...
},
...
@@ -127,7 +220,10 @@ HDB-extension ::= SEQUENCE {
HDB-extensions ::= SEQUENCE OF HDB-extension
-hdb_entry ::= SEQUENCE {
+-- Just for convenience, for encoding this as TL data in lib/kadm5
+HDB-EncTypeList ::= SEQUENCE OF INTEGER (0..4294967295)
+
+HDB_entry ::= SEQUENCE {
principal[0] Principal OPTIONAL, -- this is optional only
-- for compatibility with libkrb5
kvno[1] INTEGER (0..4294967295),
@@ -140,13 +236,18 @@ hdb_entry ::= SEQUENCE {
max-life[8] INTEGER (0..4294967295) OPTIONAL,
max-renew[9] INTEGER (0..4294967295) OPTIONAL,
flags[10] HDBFlags,
- etypes[11] SEQUENCE OF INTEGER (0..4294967295) OPTIONAL,
+ etypes[11] HDB-EncTypeList OPTIONAL,
generation[12] GENERATION OPTIONAL,
extensions[13] HDB-extensions OPTIONAL
}
-hdb_entry_alias ::= [APPLICATION 0] SEQUENCE {
+HDB_entry_alias ::= [APPLICATION 0] SEQUENCE {
principal[0] Principal OPTIONAL
}
+HDB-EntryOrAlias ::= CHOICE {
+ entry HDB_entry,
+ alias HDB_entry_alias
+}
+
END
diff --git a/lib/hdb/hdb.c b/lib/hdb/hdb.c
index 1cb33df0885c..9947254b18ec 100644
--- a/lib/hdb/hdb.c
+++ b/lib/hdb/hdb.c
@@ -66,59 +66,53 @@ const int hdb_interface_version = HDB_INTERFACE_VERSION;
static struct hdb_method methods[] = {
/* "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},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1 /*is_file_based*/, 1 /*can_taste*/,
+ "db:", hdb_db3_create},
#elif HAVE_DB1
- { HDB_INTERFACE_VERSION, NULL, NULL, "db:", hdb_db1_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db:", hdb_db1_create},
#endif
#if HAVE_DB1
- { HDB_INTERFACE_VERSION, NULL, NULL, "db1:", hdb_db1_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db1:", hdb_db1_create},
#endif
#if HAVE_DB3
- { HDB_INTERFACE_VERSION, NULL, NULL, "db3:", hdb_db3_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db3:", hdb_db3_create},
#endif
#if HAVE_DB1
- { HDB_INTERFACE_VERSION, NULL, NULL, "mit-db:", hdb_mitdb_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "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},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "mdb:", hdb_mdb_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "lmdb:", hdb_mdb_create},
#endif
#if HAVE_NDBM
- { HDB_INTERFACE_VERSION, NULL, NULL, "ndbm:", hdb_ndbm_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "ndbm:", hdb_ndbm_create},
#endif
- { HDB_INTERFACE_VERSION, NULL, NULL, "keytab:", hdb_keytab_create},
+#ifdef HAVE_SQLITE3
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "sqlite:", hdb_sqlite_create},
+#endif
+ /* The keytab interface can't use its hdb_open() method to "taste" a DB */
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "keytab:", hdb_keytab_create},
+ /* The rest are not file-based */
#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
- { HDB_INTERFACE_VERSION, NULL, NULL, "ldap:", hdb_ldap_create},
- { HDB_INTERFACE_VERSION, NULL, NULL, "ldapi:", hdb_ldapi_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:", hdb_ldap_create},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:", hdb_ldapi_create},
#elif defined(OPENLDAP)
- { HDB_INTERFACE_VERSION, NULL, NULL, "ldap:", NULL},
- { HDB_INTERFACE_VERSION, NULL, NULL, "ldapi:", NULL},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:", NULL},
+ { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:", NULL},
#endif
-#ifdef HAVE_SQLITE3
- { HDB_INTERFACE_VERSION, NULL, NULL, "sqlite:", hdb_sqlite_create},
-#endif
- { 0, NULL, NULL, NULL, NULL}
+ { 0, NULL, NULL, 0, 0, NULL, NULL}
};
-/*
- * 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.
+/**
+ * Returns the Keys of `e' for `kvno', or NULL if not found. The Keys will
+ * remain valid provided that the entry is not mutated.
+ *
+ * @param context Context
+ * @param e The HDB entry
+ * @param kvno The kvno
+ *
+ * @return A pointer to the Keys for the requested kvno.
*/
-#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 default_dbmethod =
- { HDB_INTERFACE_VERSION, NULL, NULL, "", hdb_ndbm_create };
-#endif
-
const Keys *
hdb_kvno2keys(krb5_context context,
const hdb_entry *e,
@@ -128,7 +122,7 @@ hdb_kvno2keys(krb5_context context,
HDB_extension *extp;
size_t i;
- if (kvno == 0)
+ if (kvno == 0 || e->kvno == kvno)
return &e->keys;
extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
@@ -144,6 +138,177 @@ hdb_kvno2keys(krb5_context context,
return NULL;
}
+/* Based on remove_HDB_Ext_KeySet(), generated by the ASN.1 compiler */
+static int
+dequeue_HDB_Ext_KeySet(HDB_Ext_KeySet *data, unsigned int element, hdb_keyset *ks)
+{
+ if (element >= data->len) {
+ ks->kvno = 0;
+ ks->keys.len = 0;
+ ks->keys.val = 0;
+ ks->set_time = 0;
+ return ASN1_OVERRUN;
+ }
+ *ks = data->val[element];
+ data->len--;
+ /* Swap instead of memmove()... changes the order of elements */
+ if (element < data->len)
+ data->val[element] = data->val[data->len];
+ if (data->len == 0) {
+ free(data->val);
+ data->val = 0;
+ }
+ return 0;
+}
+
+
+/**
+ * Removes from `e' and optionally outputs the keyset for the requested `kvno'.
+ *
+ * @param context Context
+ * @param e The HDB entry
+ * @param kvno The key version number
+ * @param ks A pointer to a variable of type hdb_keyset (may be NULL)
+ *
+ * @return Zero on success, an error code otherwise.
+ */
+krb5_error_code
+hdb_remove_keys(krb5_context context,
+ hdb_entry *e,
+ krb5_kvno kvno,
+ hdb_keyset *ks)
+{
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension *extp;
+ size_t i;
+
+ if (kvno == 0 || e->kvno == kvno) {
+ if (ks) {
+ KerberosTime t;
+
+ (void) hdb_entry_get_pw_change_time(e, &t);
+ if (t) {
+ if ((ks->set_time = malloc(sizeof(*ks->set_time))) == NULL)
+ return krb5_enomem(context);
+ *ks->set_time = t;
+ }
+ ks->kvno = e->kvno;
+ ks->keys = e->keys;
+ e->keys.len = 0;
+ e->keys.val = NULL;
+ e->kvno = 0;
+ } else {
+ free_Keys(&e->keys);
+ }
+ return 0;
+ }
+
+ if (ks) {
+ ks->kvno = 0;
+ ks->keys.len = 0;
+ ks->keys.val = 0;
+ ks->set_time = 0;
+ }
+
+ 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)
+ continue;
+ if (ks)
+ return dequeue_HDB_Ext_KeySet(hist_keys, i, ks);
+ return remove_HDB_Ext_KeySet(hist_keys, i);
+ }
+ return HDB_ERR_NOENTRY;
+}
+
+/**
+ * Removes from `e' and outputs all the base keys for virtual principal and/or
+ * key derivation.
+ *
+ * @param context Context
+ * @param e The HDB entry
+ * @param ks A pointer to a variable of type HDB_Ext_KeySet
+ * @param ckr A pointer to stable (copied) HDB_Ext_KeyRotation
+ *
+ * @return Zero on success, an error code otherwise.
+ */
+krb5_error_code
+_hdb_remove_base_keys(krb5_context context,
+ hdb_entry *e,
+ HDB_Ext_KeySet *base_keys,
+ const HDB_Ext_KeyRotation *ckr)
+{
+ krb5_error_code ret = 0;
+ size_t i, k;
+
+ base_keys->len = 0;
+ if ((base_keys->val = calloc(ckr->len, sizeof(base_keys->val[0]))) == NULL)
+ ret = krb5_enomem(context);
+
+ for (k = i = 0; ret == 0 && i < ckr->len; i++) {
+ const KeyRotation *krp = &ckr->val[i];
+
+ /*
+ * WARNING: O(N * M) where M is number of keysets and N is the number
+ * of base keysets.
+ *
+ * In practice N will never be > 3 because the ASN.1 module imposes
+ * that as a constraint, and M will generally be the same as N, so this
+ * will be O(1) after all.
+ */
+ ret = hdb_remove_keys(context, e, krp->base_key_kvno,
+ &base_keys->val[k]);
+ if (ret == 0)
+ k++;
+ else if (ret == HDB_ERR_NOENTRY)
+ ret = 0;
+ }
+ if (ret == 0)
+ base_keys->len = k;
+ else
+ free_HDB_Ext_KeySet(base_keys);
+ return 0;
+}
+
+/**
+ * Removes from `e' and outputs all the base keys for virtual principal and/or
+ * key derivation.
+ *
+ * @param context Context
+ * @param e The HDB entry
+ * @param is_current_keyset Whether to make the keys the current keys for `e'
+ * @param ks A pointer to an hdb_keyset containing the keys to set
+ *
+ * @return Zero on success, an error code otherwise.
+ */
+krb5_error_code
+hdb_install_keyset(krb5_context context,
+ hdb_entry *e,
+ int is_current_keyset,
+ const hdb_keyset *ks)
+{
+ krb5_error_code ret = 0;
+
+ if (is_current_keyset) {
+ if (e->keys.len &&
+ (ret = hdb_add_current_keys_to_history(context, e)))
+ return ret;
+ free_Keys(&e->keys);
+ e->kvno = ks->kvno;
+ if (ret == 0)
+ ret = copy_Keys(&ks->keys, &e->keys);
+ if (ret == 0 && ks->set_time)
+ ret = hdb_entry_set_pw_change_time(context, e, *ks->set_time);
+ return ret;
+ }
+ return hdb_add_history_keyset(context, e, ks);
+}
+
+
krb5_error_code
hdb_next_enctype2key(krb5_context context,
const hdb_entry *e,
@@ -180,9 +345,10 @@ hdb_enctype2key(krb5_context context,
void
hdb_free_key(Key *key)
{
- memset(key->key.keyvalue.data,
- 0,
- key->key.keyvalue.length);
+ memset_s(key->key.keyvalue.data,
+ key->key.keyvalue.length,
+ 0,
+ key->key.keyvalue.length);
free_Key(key);
free(key);
}
@@ -217,20 +383,23 @@ hdb_unlock(int fd)
}
void
-hdb_free_entry(krb5_context context, hdb_entry_ex *ent)
+hdb_free_entry(krb5_context context, HDB *db, hdb_entry *ent)
{
Key *k;
size_t i;
- if (ent->free_entry)
- (*ent->free_entry)(context, ent);
+ if (db && db->hdb_free_entry_context)
+ db->hdb_free_entry_context(context, db, ent);
- for(i = 0; i < ent->entry.keys.len; i++) {
- k = &ent->entry.keys.val[i];
+ for(i = 0; i < ent->keys.len; i++) {
+ k = &ent->keys.val[i];
- memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
+ memset_s(k->key.keyvalue.data,
+ k->key.keyvalue.length,
+ 0,
+ k->key.keyvalue.length);
}
- free_hdb_entry(&ent->entry);
+ free_HDB_entry(ent);
}
krb5_error_code
@@ -241,13 +410,13 @@ hdb_foreach(krb5_context context,
void *data)
{
krb5_error_code ret;
- hdb_entry_ex entry;
+ hdb_entry entry;
ret = db->hdb_firstkey(context, db, flags, &entry);
if (ret == 0)
krb5_clear_error_message(context);
while(ret == 0){
ret = (*func)(context, db, &entry, data);
- hdb_free_entry(context, &entry);
+ hdb_free_entry(context, db, &entry);
if(ret == 0)
ret = db->hdb_nextkey(context, db, flags, &entry);
}
@@ -318,40 +487,70 @@ hdb_init_db(krb5_context context, HDB *db)
}
/*
- * find the relevant method for `filename', returning a pointer to the
- * rest in `rest'.
- * return NULL if there's no such method.
+ * `default_dbmethod' is the last resort default.
+ *
+ * In hdb_create() we may try all the `methods[]' until one succeeds or all
+ * fail.
*/
+#if defined(HAVE_LMDB)
+static struct hdb_method default_dbmethod =
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_mdb_create };
+#elif defined(HAVE_DB3)
+static struct hdb_method default_dbmethod =
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db3_create };
+#elif defined(HAVE_DB1)
+static struct hdb_method default_dbmethod =
+ { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db1_create };
+#elif defined(HAVE_NDBM)
+static struct hdb_method default_dbmethod =
+ { HDB_INTERFACE_VERSION, NULL, NULL, 0, 1, "", hdb_ndbm_create };
+#else
+static struct hdb_method default_dbmethod =
+ { 0, NULL, NULL, 0, 0, NULL, NULL};
+#endif
+
+static int
+is_pathish(const char *s)
+{
+ if (s[0] == '/' ||
+ strncmp(s, "./", sizeof("./") - 1) == 0 ||
+ strncmp(s, "../", sizeof("../") - 1) == 0)
+ return 1;
+#ifdef WIN32
+ if (s[0] == '\\' || (isalpha((unsigned char)s[0]) && s[0] == ':') ||
+ strncmp(s, ".\\", sizeof(".\\") - 1) == 0 ||
+ strncmp(s, "\\\\", sizeof("\\\\") - 1) == 0)
+ return 1;
+#endif
+ return 0;
+}
static const struct hdb_method *
-find_method (const char *filename, const char **rest)
+has_method_prefix(const char *filename)
{
const struct hdb_method *h;
- for (h = methods; h->prefix != NULL; ++h) {
- if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
- *rest = filename + strlen(h->prefix);
+ for (h = methods; h->prefix != NULL; ++h)
+ if (strncmp(filename, h->prefix, strlen(h->prefix)) == 0)
return h;
- }
- }
-#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 &default_dbmethod;
- }
-#endif
-
return NULL;
}
+/*
+ * find the relevant method for `filename', returning a pointer to the
+ * rest in `rest'.
+ * return NULL if there's no such method.
+ */
+
+static const struct hdb_method *
+find_method(const char *filename, const char **rest)
+{
+ const struct hdb_method *h = has_method_prefix(filename);
+
+ *rest = h ? filename + strlen(h->prefix) : filename;
+ return h;
+}
+
struct cb_s {
const char *residual;
const char *filename;
@@ -390,6 +589,8 @@ make_sym(const char *prefix)
return sym;
}
+static const char *hdb_plugin_deps[] = { "hdb", "krb5", NULL };
+
krb5_error_code
hdb_list_builtin(krb5_context context, char **list)
{
@@ -414,12 +615,17 @@ hdb_list_builtin(krb5_context context, char **list)
if (h->create == NULL) {
struct cb_s cb_ctx;
char *f;
- char *sym;
+ struct heim_plugin_data hdb_plugin_data;
+
+ hdb_plugin_data.module = "krb5";
+ hdb_plugin_data.min_version = HDB_INTERFACE_VERSION;
+ hdb_plugin_data.deps = hdb_plugin_deps;
+ hdb_plugin_data.get_instance = hdb_get_instance;
/* Try loading the plugin */
if (asprintf(&f, "%sfoo", h->prefix) == -1)
f = NULL;
- if ((sym = make_sym(h->prefix)) == NULL) {
+ if ((hdb_plugin_data.name = make_sym(h->prefix)) == NULL) {
free(buf);
free(f);
return krb5_enomem(context);
@@ -427,11 +633,10 @@ hdb_list_builtin(krb5_context context, char **list)
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);
+ (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0,
+ &cb_ctx, callback);
free(f);
- free(sym);
+ free(rk_UNCONST(hdb_plugin_data.name));
if (cb_ctx.h == NULL || cb_ctx.h->create == NULL)
continue;
}
@@ -446,54 +651,198 @@ hdb_list_builtin(krb5_context context, char **list)
krb5_error_code
_hdb_keytab2hdb_entry(krb5_context context,
const krb5_keytab_entry *ktentry,
- hdb_entry_ex *entry)
+ hdb_entry *entry)
{
- entry->entry.kvno = ktentry->vno;
- entry->entry.created_by.time = ktentry->timestamp;
+ entry->kvno = ktentry->vno;
+ entry->created_by.time = ktentry->timestamp;
- entry->entry.keys.val = calloc(1, sizeof(entry->entry.keys.val[0]));
- if (entry->entry.keys.val == NULL)
+ entry->keys.val = calloc(1, sizeof(entry->keys.val[0]));
+ if (entry->keys.val == NULL)
return ENOMEM;
- entry->entry.keys.len = 1;
+ entry->keys.len = 1;
- entry->entry.keys.val[0].mkvno = NULL;
- entry->entry.keys.val[0].salt = NULL;
+ entry->keys.val[0].mkvno = NULL;
+ entry->keys.val[0].salt = NULL;
return krb5_copy_keyblock_contents(context,
&ktentry->keyblock,
- &entry->entry.keys.val[0].key);
+ &entry->keys.val[0].key);
+}
+
+static krb5_error_code
+load_config(krb5_context context, HDB *db)
+{
+ db->enable_virtual_hostbased_princs =
+ krb5_config_get_bool_default(context, NULL, FALSE, "hdb",
+ "enable_virtual_hostbased_princs",
+ NULL);
+ db->virtual_hostbased_princ_ndots =
+ krb5_config_get_int_default(context, NULL, 1, "hdb",
+ "virtual_hostbased_princ_mindots",
+ NULL);
+ db->virtual_hostbased_princ_maxdots =
+ krb5_config_get_int_default(context, NULL, 0, "hdb",
+ "virtual_hostbased_princ_maxdots",
+ NULL);
+ db->new_service_key_delay =
+ krb5_config_get_time_default(context, NULL, 0, "hdb",
+ "new_service_key_delay", NULL);
+ /*
+ * XXX Needs freeing in the HDB backends because we don't have a
+ * first-class hdb_close() :(
+ */
+ db->virtual_hostbased_princ_svcs =
+ krb5_config_get_strings(context, NULL, "hdb",
+ "virtual_hostbased_princ_svcs", NULL);
+ /* Check for ENOMEM */
+ if (db->virtual_hostbased_princ_svcs == NULL
+ && krb5_config_get_string(context, NULL, "hdb",
+ "virtual_hostbased_princ_svcs", NULL)) {
+ return krb5_enomem(context);
+ }
+ return 0;
}
/**
* 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.
+ * filename. Doesn't actually create or even open an HDB file(s);
+ * you have to call the hdb_open() open method of the resulting HDB
+ * to open the database, and you have to use O_CREAT to create it.
+ *
+ * If `filename' does not have a backend type prefix, all file-based
+ * backends will be tried until one succeeds or all fail, and if the
+ * HDB exists for some backend, that will be used. A build-time
+ * default backend type will be used if the `filename' does not exist.
+ *
+ * Note that the actual filename may have a suffix added, such as
+ * ".db". Also, for backends such as "ldap:" and "ldapi:" the
+ * `filename' is more like a URI.
+ *
+ * @param [in] context Context
+ * @param [out] db HDB handle output
+ * @param [in] filename The name of the HDB
+ *
+ * @return Zero on success else a krb5 error code.
*/
krb5_error_code
hdb_create(krb5_context context, HDB **db, const char *filename)
{
+ krb5_error_code ret = ENOTSUP;
struct cb_s cb_ctx;
+ *db = NULL;
if (filename == NULL)
- filename = HDB_DEFAULT_DB;
- cb_ctx.h = find_method (filename, &cb_ctx.residual);
+ filename = hdb_default_db(context);
+
+ cb_ctx.h = find_method(filename, &cb_ctx.residual);
cb_ctx.filename = filename;
if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) {
- char *sym;
-
- if ((sym = make_sym(filename)) == NULL)
+ struct heim_plugin_data hdb_plugin_data;
+
+ /*
+ * `filename' does not start with a known HDB backend prefix.
+ *
+ * Try plugins.
+ */
+ hdb_plugin_data.module = "krb5";
+ hdb_plugin_data.min_version = HDB_INTERFACE_VERSION;
+ hdb_plugin_data.deps = hdb_plugin_deps;
+ hdb_plugin_data.get_instance = hdb_get_instance;
+
+ if ((hdb_plugin_data.name = make_sym(filename)) == NULL)
return krb5_enomem(context);
- (void)_krb5_plugin_run_f(context, "krb5", sym, HDB_INTERFACE_VERSION,
- 0, &cb_ctx, callback);
+ (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0 /* flags */,
+ &cb_ctx, callback);
- free(sym);
+ free(rk_UNCONST(hdb_plugin_data.name));
+ }
+
+ if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) {
+ int pathish = is_pathish(filename);
+ /*
+ * `filename' does not start with a known HDB backend prefix and it
+ * wasn't handled by any plugin.
+ *
+ * If it's "filename-ish", try all builtin HDB backends that are
+ * local-file-ish, but use hdb_open() to see if the HDB exists and stop
+ * when a backend is found for which the HDB exists.
+ */
+ if (!pathish) {
+ krb5_set_error_message(context, ret = ENOTSUP,
+ "No database support for %s",
+ cb_ctx.filename);
+ return ret;
+ }
+ for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) {
+ if (cb_ctx.h->is_file_based)
+ continue;
+ if (!cb_ctx.h->can_taste)
+ continue;
+ /* Taste the file */
+ ret = (*cb_ctx.h->create)(context, db, filename);
+ if (ret == 0)
+ ret = (*db)->hdb_open(context, *db, O_RDONLY, 0);
+ if (ret == 0) {
+ (void) (*db)->hdb_close(context, *db);
+ break;
+ }
+ if (*db)
+ (*db)->hdb_destroy(context, *db);
+ *db = NULL;
+ }
+ if (cb_ctx.h->prefix == NULL)
+ cb_ctx.h = NULL;
}
+#ifdef HDB_DEFAULT_DB_TYPE
+ if (cb_ctx.h == NULL) {
+ /*
+ * If still we've not picked a backend, use a build configuration time
+ * default.
+ */
+ for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++)
+ if (strcmp(cb_ctx.h->prefix, HDB_DEFAULT_DB_TYPE) == 0)
+ break;
+ if (cb_ctx.h->prefix == NULL)
+ cb_ctx.h = NULL;
+ }
+#endif
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);
+ /* Last resort default */
+ cb_ctx.h = &default_dbmethod;
+ if (cb_ctx.h->prefix == NULL) {
+ krb5_set_error_message(context, ENOTSUP,
+ "Could not determine default DB backend for %s",
+ filename);
+ return ENOTSUP;
+ }
+ if (!*db) {
+ ret = (*cb_ctx.h->create)(context, db, cb_ctx.residual);
+ if (ret == 0)
+ (*db)->hdb_method_name = cb_ctx.h->prefix;
+ }
+ if (ret == 0 && *db)
+ ret = load_config(context, *db);
+ if (ret && *db) {
+ (*db)->hdb_destroy(context, *db);
+ *db = NULL;
+ }
+ return ret;
+}
+
+uintptr_t KRB5_CALLCONV
+hdb_get_instance(const char *libname)
+{
+ static const char *instance = "libhdb";
+
+ if (strcmp(libname, "hdb") == 0)
+ return (uintptr_t)instance;
+ else if (strcmp(libname, "krb5") == 0)
+ return krb5_get_instance(libname);
+
+ return 0;
}
diff --git a/lib/hdb/hdb.h b/lib/hdb/hdb.h
index 7c6dfcf9d8d2..87377513d549 100644
--- a/lib/hdb/hdb.h
+++ b/lib/hdb/hdb.h
@@ -42,30 +42,42 @@
#include <hdb_err.h>
+#include <heimbase-svc.h>
#include <heim_asn1.h>
#include <hdb_asn1.h>
+#define HDB_DB_FORMAT hdb_db_format
+
+typedef HDB_keyset hdb_keyset;
+typedef HDB_entry hdb_entry;
+typedef HDB_entry_alias hdb_entry_alias;
+
struct hdb_dbinfo;
enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
/* flags for various functions */
-#define HDB_F_DECRYPT 1 /* decrypt keys */
-#define HDB_F_REPLACE 2 /* replace entry */
-#define HDB_F_GET_CLIENT 4 /* fetch client */
-#define HDB_F_GET_SERVER 8 /* fetch server */
-#define HDB_F_GET_KRBTGT 16 /* fetch krbtgt */
-#define HDB_F_GET_ANY 28 /* fetch any of client,server,krbtgt */
-#define HDB_F_CANON 32 /* want canonicalition */
-#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 */
-#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 */
+#define HDB_F_DECRYPT 0x00001 /* decrypt keys */
+#define HDB_F_REPLACE 0x00002 /* replace entry */
+#define HDB_F_GET_CLIENT 0x00004 /* fetch client */
+#define HDB_F_GET_SERVER 0x00008 /* fetch server */
+#define HDB_F_GET_KRBTGT 0x00010 /* fetch krbtgt */
+#define HDB_F_GET_ANY ( HDB_F_GET_CLIENT | \
+ HDB_F_GET_SERVER | \
+ HDB_F_GET_KRBTGT ) /* fetch any of client,server,krbtgt */
+#define HDB_F_CANON 0x00020 /* want canonicalition */
+#define HDB_F_ADMIN_DATA 0x00040 /* want data that kdc don't use */
+#define HDB_F_KVNO_SPECIFIED 0x00080 /* we want a particular KVNO */
+#define HDB_F_LIVE_CLNT_KVNOS 0x00200 /* we want all live keys for pre-auth */
+#define HDB_F_LIVE_SVC_KVNOS 0x00400 /* we want all live keys for tix */
+#define HDB_F_ALL_KVNOS 0x00800 /* we want all the keys, live or not */
+#define HDB_F_FOR_AS_REQ 0x01000 /* fetch is for a AS REQ */
+#define HDB_F_FOR_TGS_REQ 0x02000 /* fetch is for a TGS REQ */
+#define HDB_F_PRECHECK 0x04000 /* check that the operation would succeed */
+#define HDB_F_DELAY_NEW_KEYS 0x08000 /* apply [hdb] new_service_key_delay */
+#define HDB_F_SYNTHETIC_OK 0x10000 /* synthetic principal for PKINIT or GSS preauth OK */
+#define HDB_F_GET_FAST_COOKIE 0x20000 /* fetch the FX-COOKIE key (not a normal principal) */
+#define HDB_F_ARMOR_PRINCIPAL 0x40000 /* fetch is for the client of an armor ticket */
/* hdb_capability_flags */
#define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1
@@ -73,29 +85,26 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
#define HDB_CAP_F_PASSWORD_UPDATE_KEYS 4
#define HDB_CAP_F_SHARED_DIRECTORY 8
-/* auth status values */
-#define HDB_AUTH_SUCCESS 0
-#define HDB_AUTH_WRONG_PASSWORD 1
-#define HDB_AUTH_INVALID_SIGNATURE 2
+#define heim_pcontext krb5_context
+#define heim_pconfig void *
+
+typedef struct hdb_request_desc {
+ HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS;
+} *hdb_request_t;
+
+#undef heim_pcontext
+#undef heim_pconfig
/* key usage for master key */
#define HDB_KU_MKEY 0x484442
-typedef struct hdb_master_key_data *hdb_master_key;
-
-/**
- * hdb_entry_ex is a wrapper structure around the hdb_entry structure
- * that allows backends to keep a pointer to the backing store, ie in
- * ->hdb_fetch_kvno(), so that we the kadmin/kpasswd backend gets around to
- * ->hdb_store(), the backend doesn't need to lookup the entry again.
+/*
+ * Second component of WELLKNOWN namespace principals, the third component is
+ * the common DNS suffix of the implied virtual hosts.
*/
+#define HDB_WK_NAMESPACE "HOSTBASED-NAMESPACE"
-typedef struct hdb_entry_ex {
- void *ctx;
- hdb_entry entry;
- void (*free_entry)(krb5_context, struct hdb_entry_ex *);
-} hdb_entry_ex;
-
+typedef struct hdb_master_key_data *hdb_master_key;
/**
* HDB backend function pointer structure
@@ -107,6 +116,7 @@ typedef struct hdb_entry_ex {
typedef struct HDB {
void *hdb_db;
void *hdb_dbc; /** don't use, only for DB3 */
+ const char *hdb_method_name;
char *hdb_name;
int hdb_master_key_set;
hdb_master_key hdb_master_key;
@@ -114,6 +124,17 @@ typedef struct HDB {
int hdb_capability_flags;
int lock_count;
int lock_type;
+ /*
+ * These fields cache config values.
+ *
+ * XXX Move these into a structure that we point to so that we
+ * don't need to break the ABI every time we add a field.
+ */
+ int enable_virtual_hostbased_princs;
+ size_t virtual_hostbased_princ_ndots; /* Min. # of .s in hostname */
+ size_t virtual_hostbased_princ_maxdots; /* Max. # of .s in namespace */
+ char **virtual_hostbased_princ_svcs; /* Which svcs are not wildcarded */
+ time_t new_service_key_delay; /* Delay for new keys */
/**
* Open (or create) the a Kerberos database.
*
@@ -134,9 +155,9 @@ typedef struct HDB {
*/
krb5_error_code (*hdb_close)(krb5_context, struct HDB*);
/**
- * Free an entry after use.
+ * Free backend-specific entry context.
*/
- void (*hdb_free)(krb5_context, struct HDB*, hdb_entry_ex*);
+ void (*hdb_free_entry_context)(krb5_context, struct HDB*, hdb_entry*);
/**
* Fetch an entry from the backend
*
@@ -146,12 +167,12 @@ typedef struct HDB {
*/
krb5_error_code (*hdb_fetch_kvno)(krb5_context, struct HDB*,
krb5_const_principal, unsigned, krb5_kvno,
- hdb_entry_ex*);
+ hdb_entry*);
/**
* Store an entry to database
*/
krb5_error_code (*hdb_store)(krb5_context, struct HDB*,
- unsigned, hdb_entry_ex*);
+ unsigned, hdb_entry*);
/**
* Remove an entry from the database.
*/
@@ -161,12 +182,12 @@ typedef struct HDB {
* As part of iteration, fetch one entry
*/
krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*,
- unsigned, hdb_entry_ex*);
+ unsigned, hdb_entry*);
/**
* As part of iteration, fetch next entry
*/
krb5_error_code (*hdb_nextkey)(krb5_context, struct HDB*,
- unsigned, hdb_entry_ex*);
+ unsigned, hdb_entry*);
/**
* Lock database
*
@@ -245,32 +266,35 @@ typedef struct HDB {
* The backend needs to call _kadm5_set_keys() and perform password
* quality checks.
*/
- krb5_error_code (*hdb_password)(krb5_context, struct HDB*, hdb_entry_ex*, const char *, int);
+ krb5_error_code (*hdb_password)(krb5_context, struct HDB*, hdb_entry*, const char *, int);
/**
- * Auth feedback
+ * Authentication auditing. Note that this function is called by
+ * both the AS and TGS, but currently only the AS sets the auth
+ * event type. This may change in a future version.
*
- * This is a feedback call that allows backends that provides
- * lockout functionality to register failure and/or successes.
+ * Event details are available by querying the request using
+ * heim_audit_getkv(HDB_REQUEST_KV_...).
*
* In case the entry is locked out, the backend should set the
* hdb_entry.flags.locked-out flag.
*/
- krb5_error_code (*hdb_auth_status)(krb5_context, struct HDB *, hdb_entry_ex *, int);
+ krb5_error_code (*hdb_audit)(krb5_context, struct HDB *, hdb_entry *, hdb_request_t);
+
/**
* Check if delegation is allowed.
*/
- krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
+ krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal);
/**
* Check if this name is an alias for the supplied client for PKINIT userPrinicpalName logins
*/
- krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
+ krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal);
/**
- * Check if s4u2self is allowed from this client to this server
+ * Check if s4u2self is allowed from this client to this server or the SPN is a valid SPN of this client (for user2user)
*/
- krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
+ krb5_error_code (*hdb_check_client_matches_target_service)(krb5_context, struct HDB *, hdb_entry *, hdb_entry *);
/**
* Enable/disable synchronous updates
@@ -281,12 +305,12 @@ typedef struct HDB {
krb5_error_code (*hdb_set_sync)(krb5_context, struct HDB *, int);
}HDB;
-#define HDB_INTERFACE_VERSION 10
+#define HDB_INTERFACE_VERSION 11
struct hdb_method {
- int version;
- krb5_error_code (*init)(krb5_context, void **);
- void (*fini)(void *);
+ HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context);
+ unsigned int is_file_based:1;
+ unsigned int can_taste:1;
const char *prefix;
krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
};
@@ -303,7 +327,7 @@ struct hdb_print_entry_arg {
};
typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*,
- hdb_entry_ex*, void*);
+ hdb_entry*, void*);
extern krb5_kt_ops hdb_kt_ops;
extern krb5_kt_ops hdb_get_kt_ops;
diff --git a/lib/hdb/hdb.opt b/lib/hdb/hdb.opt
new file mode 100644
index 000000000000..a96eb632e527
--- /dev/null
+++ b/lib/hdb/hdb.opt
@@ -0,0 +1,9 @@
+--sequence=HDB-extensions
+--sequence=HDB-Ext-KeyRotation
+--sequence=HDB-Ext-KeySet
+--sequence=Keys
+--decorate=HDB_entry:void:context?:::
+# The `aliased` field is for indicating whether a name used in an HDB
+# lookup was an alias. This could be useful to applications when hard
+# aliasing is implemented in an HDB backend, as it should be.
+--decorate=HDB_entry:int:aliased:::
diff --git a/lib/hdb/keys.c b/lib/hdb/keys.c
index 96c221ed275e..457e5daf7a7b 100644
--- a/lib/hdb/keys.c
+++ b/lib/hdb/keys.c
@@ -31,21 +31,10 @@
* SUCH DAMAGE.
*/
+#include "krb5_locl.h"
#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>
/*
@@ -212,18 +201,30 @@ parse_key_set(krb5_context context, const char *key,
}
/**
- * 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).
- *
+ * This function prunes an HDB entry's historic keys by kvno.
+ *
* @param context Context
* @param entry HDB entry
+ * @param kvno Keyset kvno to prune, or zero to prune all too-old keys
*/
krb5_error_code
-hdb_prune_keys(krb5_context context, hdb_entry *entry)
+hdb_prune_keys_kvno(krb5_context context, hdb_entry *entry, int kvno)
{
HDB_extension *ext;
HDB_Ext_KeySet *keys;
+ hdb_keyset *elem;
+ time_t keep_time = 0;
size_t nelem;
+ size_t i;
+
+ /*
+ * XXX Pruning old keys for namespace principals may not be desirable, but!
+ * as long as the `set_time's of the base keys for a namespace principal
+ * match the `epoch's of the corresponding KeyRotation periods, it will be
+ * perfectly acceptable to prune old [base] keys for namespace principals
+ * just as for any other principal. Therefore, we may not need to make any
+ * changes here w.r.t. namespace principals.
+ */
ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
if (ext == NULL)
@@ -231,14 +232,12 @@ hdb_prune_keys(krb5_context context, hdb_entry *entry)
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;
+ /*
+ * Optionally drop key history for keys older than now - max_life, which is
+ * all the keys no longer needed to decrypt extant tickets.
+ */
+ if (kvno == 0 && entry->max_life != NULL && nelem > 0) {
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
@@ -250,94 +249,123 @@ hdb_prune_keys(krb5_context context, hdb_entry *entry)
&& (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;
- }
- }
+ if (kvno == 0 && keep_time == 0)
+ return 0;
+
+ for (i = 0; i < nelem; /* see below */) {
+ elem = &keys->val[i];
+ if ((kvno && kvno == elem->kvno) ||
+ (keep_time && 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 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)
+{
+ if (!krb5_config_get_bool_default(context, NULL, FALSE,
+ "kadmin", "prune-key-history", NULL))
+ return 0;
+ return hdb_prune_keys_kvno(context, entry, 0);
+}
+
+/**
+ * This function adds a keyset 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_keyset(krb5_context context,
+ hdb_entry *entry,
+ const hdb_keyset *ks)
+{
+ size_t i;
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension ext;
+ HDB_extension *extp;
+ krb5_error_code ret = 0;
+
+ memset(&ext, 0, sizeof (ext));
+
+ extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
+ if (extp == NULL) {
+ ext.mandatory = FALSE;
+ ext.data.element = choice_HDB_extension_data_hist_keys;
+ ext.data.u.hist_keys.len = 0;
+ ext.data.u.hist_keys.val = 0;
+ extp = &ext;
+ }
+ hist_keys = &extp->data.u.hist_keys;
+
+ for (i = 0; i < hist_keys->len; i++) {
+ if (hist_keys->val[i].kvno == ks->kvno) {
+ /* Replace existing */
+ free_HDB_keyset(&hist_keys->val[i]);
+ ret = copy_HDB_keyset(ks, &hist_keys->val[i]);
+ break;
+ }
+ }
+ if (i >= hist_keys->len)
+ ret = add_HDB_Ext_KeySet(hist_keys, ks); /* Append new */
+ if (ret == 0 && extp == &ext)
+ ret = hdb_replace_extension(context, entry, &ext);
+ free_HDB_extension(&ext);
+ return ret;
+}
+
+/**
* 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
+ *
+ * @return Zero on success, or an error code otherwise.
*/
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;
+ hdb_keyset ks;
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;
- }
+ return ret;
- ret = hdb_prune_keys(context, entry);
- if (ret)
- goto out;
+ ks.keys = entry->keys;
+ ks.kvno = entry->kvno;
+ ks.set_time = &newtime;
- out:
- if (replace && ext) {
- free_HDB_extension(ext);
- free(ext);
- }
+ ret = hdb_add_history_keyset(context, entry, &ks);
+ if (ret == 0)
+ ret = hdb_prune_keys(context, entry);
return ret;
}
@@ -348,6 +376,8 @@ hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry)
* @param entry HDB entry
* @param kvno Key version number of the key to add to the history
* @param key The Key to add
+ *
+ * @return Zero on success, or an error code otherwise.
*/
krb5_error_code
hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key)
@@ -392,12 +422,11 @@ hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key
}
out:
- free_hdb_keyset(&keyset);
+ 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
@@ -433,7 +462,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
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);
+ ret = copy_HDB_keyset(&hist_keys->val[i], &keyset);
if (ret)
goto out;
ret = remove_HDB_Ext_KeySet(hist_keys, i);
@@ -456,7 +485,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
memset(&keyset.keys, 0, sizeof (keyset.keys));
out:
- free_hdb_keyset(&keyset);
+ free_HDB_keyset(&keyset);
return ret;
}
@@ -654,7 +683,8 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal,
ktypes = ks_tuple_strs;
if (ktypes == NULL) {
- ktypes = glob_rules_keys(context, principal);
+ config_ktypes = glob_rules_keys(context, principal);
+ ktypes = config_ktypes;
}
if (ktypes == NULL) {
config_ktypes = krb5_config_get_strings(context, NULL, "kadmin",
diff --git a/lib/hdb/keytab.c b/lib/hdb/keytab.c
index 81cf2b287261..df16cb782faa 100644
--- a/lib/hdb/keytab.c
+++ b/lib/hdb/keytab.c
@@ -42,7 +42,7 @@ struct hdb_data {
struct hdb_cursor {
HDB *db;
- hdb_entry_ex hdb_entry;
+ hdb_entry hdb_entry;
int first, next;
int key_idx;
};
@@ -160,7 +160,7 @@ find_db (krb5_context context,
}
hdb_free_dbinfo(context, &head);
if (*dbname == NULL &&
- (*dbname = strdup(HDB_DEFAULT_DB)) == NULL) {
+ (*dbname = strdup(hdb_default_db(context))) == NULL) {
free(*mkey);
*mkey = NULL;
return krb5_enomem(context);
@@ -181,7 +181,7 @@ hdb_get_entry(krb5_context context,
krb5_enctype enctype,
krb5_keytab_entry *entry)
{
- hdb_entry_ex ent;
+ hdb_entry ent;
krb5_error_code ret;
struct hdb_data *d = id->data;
const char *dbname = d->dbname;
@@ -190,6 +190,9 @@ hdb_get_entry(krb5_context context,
HDB *db;
size_t i;
+ if (!principal)
+ return KRB5_KT_NOTFOUND;
+
memset(&ent, 0, sizeof(ent));
if (dbname == NULL) {
@@ -215,38 +218,37 @@ hdb_get_entry(krb5_context context,
goto out2;
}
- ret = (*db->hdb_fetch_kvno)(context, db, principal,
- HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED|
- HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
- kvno, &ent);
+ ret = hdb_fetch_kvno(context, db, principal,
+ HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ 0, 0, kvno, &ent);
- if(ret == HDB_ERR_NOENTRY) {
+ if (ret == HDB_ERR_WRONG_REALM || ret == HDB_ERR_NOENTRY)
ret = KRB5_KT_NOTFOUND;
- goto out;
- }else if(ret)
+ if (ret)
goto out;
- if(kvno && (krb5_kvno)ent.entry.kvno != kvno) {
- hdb_free_entry(context, &ent);
+ if(kvno && (krb5_kvno)ent.kvno != kvno) {
+ hdb_free_entry(context, db, &ent);
ret = KRB5_KT_NOTFOUND;
goto out;
}
if(enctype == 0)
- if(ent.entry.keys.len > 0)
- enctype = ent.entry.keys.val[0].key.keytype;
+ if(ent.keys.len > 0)
+ enctype = ent.keys.val[0].key.keytype;
ret = KRB5_KT_NOTFOUND;
- for(i = 0; i < ent.entry.keys.len; i++) {
- if(ent.entry.keys.val[i].key.keytype == enctype) {
+ for(i = 0; i < ent.keys.len; i++) {
+ if(ent.keys.val[i].key.keytype == enctype) {
krb5_copy_principal(context, principal, &entry->principal);
- entry->vno = ent.entry.kvno;
+ entry->vno = ent.kvno;
krb5_copy_keyblock_contents(context,
- &ent.entry.keys.val[i].key,
+ &ent.keys.val[i].key,
&entry->keyblock);
ret = 0;
break;
}
}
- hdb_free_entry(context, &ent);
+ hdb_free_entry(context, db, &ent);
out:
(*db->hdb_close)(context, db);
(*db->hdb_destroy)(context, db);
@@ -336,8 +338,8 @@ hdb_next_entry(krb5_context context,
else if (ret)
return ret;
- if (c->hdb_entry.entry.keys.len == 0)
- hdb_free_entry(context, &c->hdb_entry);
+ if (c->hdb_entry.keys.len == 0)
+ hdb_free_entry(context, c->db, &c->hdb_entry);
else
c->next = FALSE;
}
@@ -353,8 +355,8 @@ hdb_next_entry(krb5_context context,
return ret;
/* If no keys on this entry, try again */
- if (c->hdb_entry.entry.keys.len == 0)
- hdb_free_entry(context, &c->hdb_entry);
+ if (c->hdb_entry.keys.len == 0)
+ hdb_free_entry(context, c->db, &c->hdb_entry);
else
c->next = FALSE;
}
@@ -365,14 +367,14 @@ hdb_next_entry(krb5_context context,
*/
ret = krb5_copy_principal(context,
- c->hdb_entry.entry.principal,
+ c->hdb_entry.principal,
&entry->principal);
if (ret)
return ret;
- entry->vno = c->hdb_entry.entry.kvno;
+ entry->vno = c->hdb_entry.kvno;
ret = krb5_copy_keyblock_contents(context,
- &c->hdb_entry.entry.keys.val[c->key_idx].key,
+ &c->hdb_entry.keys.val[c->key_idx].key,
&entry->keyblock);
if (ret) {
krb5_free_principal(context, entry->principal);
@@ -386,8 +388,8 @@ hdb_next_entry(krb5_context context,
* next entry
*/
- if ((size_t)c->key_idx == c->hdb_entry.entry.keys.len) {
- hdb_free_entry(context, &c->hdb_entry);
+ if ((size_t)c->key_idx == c->hdb_entry.keys.len) {
+ hdb_free_entry(context, c->db, &c->hdb_entry);
c->next = TRUE;
c->key_idx = 0;
}
@@ -404,7 +406,7 @@ hdb_end_seq_get(krb5_context context,
struct hdb_cursor *c = cursor->data;
if (!c->next)
- hdb_free_entry(context, &c->hdb_entry);
+ hdb_free_entry(context, c->db, &c->hdb_entry);
(c->db->hdb_close)(context, c->db);
(c->db->hdb_destroy)(context, c->db);
diff --git a/lib/hdb/libhdb-exports.def b/lib/hdb/libhdb-exports.def
index 67c0e33e0357..72a7fb7aaad7 100644
--- a/lib/hdb/libhdb-exports.def
+++ b/lib/hdb/libhdb-exports.def
@@ -1,7 +1,12 @@
EXPORTS
- encode_hdb_keyset
- hdb_add_master_key
+ encode_HDB_keyset
+ _hdb_fetch_kvno
+ _hdb_remove
+ _hdb_store
hdb_add_current_keys_to_history
+ hdb_add_history_key
+ hdb_add_history_keyset
+ hdb_add_master_key
hdb_change_kvno
hdb_check_db_format
hdb_clear_extension
@@ -16,22 +21,28 @@ EXPORTS
hdb_dbinfo_get_mkey_file
hdb_dbinfo_get_next
hdb_dbinfo_get_realm
+ hdb_derive_etypes
hdb_default_db
hdb_enctype2key
hdb_entry2string
hdb_entry2value
+ hdb_entry_add_key_rotation
hdb_entry_alias2value
hdb_entry_check_mandatory
hdb_entry_clear_password
hdb_entry_get_ConstrainedDelegACL
hdb_entry_get_aliases
+ hdb_entry_get_key_rotation
+ hdb_entry_get_krb5_config
hdb_entry_get_password
hdb_entry_get_pkinit_acl
hdb_entry_get_pkinit_cert
hdb_entry_get_pkinit_hash
hdb_entry_get_pw_change_time
+ hdb_entry_set_krb5_config
hdb_entry_set_password
hdb_entry_set_pw_change_time
+ hdb_fetch_kvno
hdb_find_extension
hdb_foreach
hdb_free_dbinfo
@@ -43,7 +54,9 @@ EXPORTS
hdb_generate_key_set_password
hdb_generate_key_set_password_with_ks_tuple
hdb_get_dbinfo
+ hdb_get_instance
hdb_init_db
+ hdb_install_keyset
hdb_interface_version DATA
hdb_key2principal
hdb_kvno2keys
@@ -54,7 +67,9 @@ EXPORTS
hdb_print_entry
hdb_process_master_key
hdb_prune_keys
+ hdb_prune_keys_kvno
hdb_read_master_key
+ hdb_remove_keys
hdb_replace_extension
hdb_seal_key
hdb_seal_key_mkey
@@ -67,54 +82,99 @@ EXPORTS
hdb_unseal_key
hdb_unseal_key_mkey
hdb_unseal_keys
+ hdb_unseal_keys_kvno
hdb_unseal_keys_mkey
+ hdb_validate_key_rotation
+ hdb_validate_key_rotations
hdb_value2entry
hdb_value2entry_alias
hdb_write_master_key
- length_hdb_keyset
+ length_HDB_keyset
initialize_hdb_error_table_r
hdb_kt_ops
hdb_get_kt_ops
; MIT KDB related entries
- _hdb_mdb_value2entry
- _hdb_mit_dump2mitdb_entry
+ _hdb_mdb_value2entry
+ _hdb_mit_dump2mitdb_entry
; some random bits needed for libkadm
- HDBFlags2int
+ add_HDB_Ext_KeyRotation
+ add_HDB_Ext_KeySet
+ add_Keys
asn1_HDBFlags_units
copy_Event
+ copy_HDB_EncTypeList
+ copy_hdb_entry
+ copy_HDB_entry
+ copy_hdb_entry_alias
+ copy_HDB_entry_alias
+ copy_HDB_EntryOrAlias
copy_HDB_extensions
+ copy_HDB_Ext_KeyRotation
copy_Key
- copy_Keys
+ copy_Keys
copy_Salt
+ decode_HDB_EncTypeList
+ decode_hdb_entry
+ decode_HDB_entry
+ decode_hdb_entry_alias
+ decode_HDB_entry_alias
+ decode_HDB_EntryOrAlias
decode_HDB_Ext_Aliases
- decode_HDB_Ext_PKINIT_acl
decode_HDB_extension
- decode_Key
- decode_Keys
+ decode_HDB_Ext_KeyRotation
+ decode_HDB_Ext_PKINIT_acl
+ decode_Key
+ decode_Keys
+ encode_HDB_EncTypeList
+ encode_hdb_entry
+ encode_HDB_entry
+ encode_hdb_entry_alias
+ encode_HDB_entry_alias
+ encode_HDB_EntryOrAlias
encode_HDB_Ext_Aliases
- encode_HDB_Ext_PKINIT_acl
encode_HDB_extension
- encode_Key
- encode_Keys
+ encode_HDB_Ext_KeyRotation
+ encode_HDB_Ext_PKINIT_acl
+ encode_hdb_keyset
+ encode_Key
+ encode_Keys
free_Event
+ free_HDB_EncTypeList
+ free_hdb_entry
+ free_HDB_entry
+ free_hdb_entry_alias
+ free_HDB_entry_alias
+ free_HDB_EntryOrAlias
free_HDB_Ext_Aliases
- free_HDB_Ext_PKINIT_acl
free_HDB_extension
free_HDB_extensions
+ free_HDB_Ext_KeyRotation
+ free_HDB_Ext_KeySet
+ free_HDB_Ext_PKINIT_acl
+ free_hdb_keyset
+ free_HDB_keyset
free_Key
free_Keys
- free_Salt
- free_hdb_entry
- free_hdb_keyset
+ free_Salt
+ HDBFlags2int
int2HDBFlags
+ int2KeyRotationFlags
+ KeyRotationFlags2int
+ length_HDB_EncTypeList
+ length_hdb_entry
+ length_HDB_entry
+ length_hdb_entry_alias
+ length_HDB_entry_alias
+ length_HDB_EntryOrAlias
length_HDB_Ext_Aliases
- length_HDB_Ext_PKINIT_acl
length_HDB_extension
- length_Key
- length_Keys
- add_Keys
- add_HDB_Ext_KeySet
- remove_Keys
+ length_HDB_Ext_KeyRotation
+ length_HDB_Ext_PKINIT_acl
+ length_hdb_keyset
+ length_Key
+ length_Keys
+ remove_HDB_Ext_KeyRotation
+ remove_Keys
diff --git a/lib/hdb/ndbm.c b/lib/hdb/ndbm.c
index 5b2c07e5f644..52c52c890dc0 100644
--- a/lib/hdb/ndbm.c
+++ b/lib/hdb/ndbm.c
@@ -53,7 +53,8 @@ struct ndbm_db {
static krb5_error_code
NDBM_destroy(krb5_context context, HDB *db)
{
- hdb_clear_master_key (context, db);
+ hdb_clear_master_key(context, db);
+ krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
free(db->hdb_name);
free(db);
return 0;
@@ -75,7 +76,7 @@ NDBM_unlock(krb5_context context, HDB *db)
static krb5_error_code
NDBM_seq(krb5_context context, HDB *db,
- unsigned flags, hdb_entry_ex *entry, int first)
+ unsigned flags, hdb_entry *entry, int first)
{
struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
@@ -98,21 +99,21 @@ NDBM_seq(krb5_context context, HDB *db,
data.data = value.dptr;
data.length = value.dsize;
memset(entry, 0, sizeof(*entry));
- if(hdb_value2entry(context, &data, &entry->entry))
+ if(hdb_value2entry(context, &data, entry))
return NDBM_seq(context, db, flags, entry, 0);
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
- ret = hdb_unseal_keys (context, db, &entry->entry);
+ ret = hdb_unseal_keys (context, db, entry);
if (ret)
- hdb_free_entry (context, entry);
+ hdb_free_entry (context, db, entry);
}
- if (ret == 0 && entry->entry.principal == NULL) {
- entry->entry.principal = malloc (sizeof(*entry->entry.principal));
- if (entry->entry.principal == NULL) {
- hdb_free_entry (context, entry);
+ if (ret == 0 && entry->principal == NULL) {
+ entry->principal = malloc (sizeof(*entry->principal));
+ if (entry->principal == NULL) {
+ hdb_free_entry (context, db, entry);
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
} else {
- hdb_key2principal (context, &key_data, entry->entry.principal);
+ hdb_key2principal (context, &key_data, entry->principal);
}
}
return ret;
@@ -120,14 +121,14 @@ NDBM_seq(krb5_context context, HDB *db,
static krb5_error_code
-NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry)
+NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry *entry)
{
return NDBM_seq(context, db, flags, entry, 1);
}
static krb5_error_code
-NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry)
+NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry *entry)
{
return NDBM_seq(context, db, flags, entry, 0);
}
@@ -136,23 +137,22 @@ static krb5_error_code
open_lock_file(krb5_context context, const char *db_name, int *fd)
{
char *lock_file;
+ int ret = 0;
/* lock old and new databases */
- asprintf(&lock_file, "%s.lock", db_name);
- if(lock_file == NULL) {
+ if (asprintf(&lock_file, "%s.lock", db_name) == -1) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
*fd = open(lock_file, O_RDWR | O_CREAT, 0600);
- free(lock_file);
if(*fd < 0) {
- int ret = errno;
+ ret = errno;
krb5_set_error_message(context, ret, "open(%s): %s", lock_file,
strerror(ret));
- return ret;
}
- return 0;
+ free(lock_file);
+ return ret;
}
@@ -160,7 +160,8 @@ static krb5_error_code
NDBM_rename(krb5_context context, HDB *db, const char *new_name)
{
int ret;
- char *old_dir, *old_pag, *new_dir, *new_pag;
+ char *old_dir = NULL, *old_pag = NULL;
+ char *new_dir = NULL, *new_pag = NULL;
int old_lock_fd, new_lock_fd;
/* lock old and new databases */
@@ -189,10 +190,26 @@ NDBM_rename(krb5_context context, HDB *db, const char *new_name)
return ret;
}
- asprintf(&old_dir, "%s.dir", db->hdb_name);
- asprintf(&old_pag, "%s.pag", db->hdb_name);
- asprintf(&new_dir, "%s.dir", new_name);
- asprintf(&new_pag, "%s.pag", new_name);
+ if (asprintf(&old_dir, "%s.dir", db->hdb_name) == -1) {
+ old_dir = NULL;
+ ret = ENOMEM;
+ goto out;
+ }
+ if (asprintf(&old_pag, "%s.pag", db->hdb_name) == -1) {
+ old_pag = NULL;
+ ret = ENOMEM;
+ goto out;
+ }
+ if (asprintf(&new_dir, "%s.dir", new_name) == -1) {
+ new_dir = NULL;
+ ret = ENOMEM;
+ goto out;
+ }
+ if (asprintf(&new_pag, "%s.pag", new_name) == -1) {
+ new_pag = NULL;
+ ret = ENOMEM;
+ goto out;
+ }
ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
if (ret) {
@@ -202,6 +219,7 @@ NDBM_rename(krb5_context context, HDB *db, const char *new_name)
krb5_set_error_message(context, ret, "rename: %s", strerror(ret));
}
+ out:
free(old_dir);
free(old_pag);
free(new_dir);
diff --git a/lib/hdb/print.c b/lib/hdb/print.c
index 0d1e2855217d..7f2535881892 100644
--- a/lib/hdb/print.c
+++ b/lib/hdb/print.c
@@ -453,7 +453,8 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
unsigned char *ptr;
ptr = (unsigned char *)&last_pw_chg;
- val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+ val = ((unsigned long)ptr[3] << 24) | (ptr[2] << 16)
+ | (ptr[1] << 8) | ptr[0];
d.data = &val;
d.length = sizeof (last_pw_chg);
sz = append_string(context, sp, "\t%u\t%u\t",
@@ -474,12 +475,16 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
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;
+ 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;
+ if (sz == -1) {
+ free(modby_p);
+ return ENOMEM;
+ }
sz = append_hex(context, sp, 1, 1, &d);
if (sz == -1) {
free(modby_p);
@@ -489,7 +494,8 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
d.length = plen + 1;
sz = append_hex(context, sp, 1, 1, &d);
free(modby_p);
- if (sz == -1) return ENOMEM;
+ if (sz == -1)
+ return ENOMEM;
}
/*
* Dump keys (remembering to not include any with kvno higher than
@@ -556,7 +562,7 @@ 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,
+hdb_print_entry(krb5_context context, HDB *db, hdb_entry *entry,
void *data)
{
struct hdb_print_entry_arg *parg = data;
@@ -572,10 +578,10 @@ hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry,
switch (parg->fmt) {
case HDB_DUMP_HEIMDAL:
- ret = entry2string_int(context, sp, &entry->entry);
+ ret = entry2string_int(context, sp, entry);
break;
case HDB_DUMP_MIT:
- ret = entry2mit_string_int(context, sp, &entry->entry);
+ ret = entry2mit_string_int(context, sp, entry);
break;
default:
heim_abort("Only two dump formats supported: Heimdal and MIT");
diff --git a/lib/hdb/test_concurrency.c b/lib/hdb/test_concurrency.c
new file mode 100644
index 000000000000..35c01f59f594
--- /dev/null
+++ b/lib/hdb/test_concurrency.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/*
+ * This test tries to test reader/writer concurrency for the SQLite3 and LMDB
+ * HDB backends. We're hoping to find that one thread or process can dump the
+ * HDB while another writes -- this way backups and ipropd-master need not
+ * block write transactions when dumping a huge HDB.
+ *
+ * It has two modes: threaded, and forked.
+ *
+ * Apparently, neither LMDB nor SQLite3 give us the desired level of
+ * concurrency in threaded mode, with this test not making progress. This is
+ * surprising, at least for SQLite3, which is supposed to support N readers, 1
+ * writer and be thread-safe. LMDB also is supposed to support N readers, 1
+ * writers, but perhaps not all in one process?
+ */
+
+#include "hdb_locl.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <getarg.h>
+
+struct tsync {
+ pthread_mutex_t lock;
+ pthread_cond_t rcv;
+ pthread_cond_t wcv;
+ const char *hdb_name;
+ const char *fname;
+ volatile int writer_go;
+ volatile int reader_go;
+ int writer_go_pipe[2];
+ int reader_go_pipe[2];
+};
+
+static void *
+threaded_reader(void *d)
+{
+ krb5_error_code ret;
+ krb5_context context;
+ struct tsync *s = d;
+ hdb_entry entr;
+ HDB *dbr = NULL;
+
+ printf("Reader thread opening HDB\n");
+
+ if ((krb5_init_context(&context)))
+ errx(1, "krb5_init_context failed");
+
+ printf("Reader thread waiting for writer to create the HDB\n");
+ (void) pthread_mutex_lock(&s->lock);
+ s->writer_go = 1;
+ (void) pthread_cond_signal(&s->wcv);
+ while (!s->reader_go)
+ (void) pthread_cond_wait(&s->rcv, &s->lock);
+ s->reader_go = 0;
+ (void) pthread_mutex_unlock(&s->lock);
+
+ /* Open a new HDB handle to read */
+ if ((ret = hdb_create(context, &dbr, s->hdb_name))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not get a handle for HDB %s (read)",
+ s->hdb_name);
+ }
+ if ((ret = dbr->hdb_open(context, dbr, O_RDONLY, 0))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not open HDB %s", s->hdb_name);
+ }
+ if ((ret = dbr->hdb_firstkey(context, dbr, 0, &entr))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name);
+ }
+ free_HDB_entry(&entr);
+
+ /* Tell the writer to go ahead and write */
+ printf("Reader thread iterated one entry; telling writer to write more\n");
+ s->writer_go = 1;
+ (void) pthread_mutex_lock(&s->lock);
+ (void) pthread_cond_signal(&s->wcv);
+
+ /* Wait for the writer to have written one more entry to the HDB */
+ printf("Reader thread waiting for writer\n");
+ while (!s->reader_go)
+ (void) pthread_cond_wait(&s->rcv, &s->lock);
+ s->reader_go = 0;
+ (void) pthread_mutex_unlock(&s->lock);
+
+ /* Iterate the rest */
+ printf("Reader thread iterating another entry\n");
+ if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret,
+ "Could not iterate while writing to HDB %s", s->hdb_name);
+ }
+ printf("Reader thread iterated another entry\n");
+ free_HDB_entry(&entr);
+ if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) {
+ //(void) unlink(s->fname);
+ krb5_warn(context, ret,
+ "HDB %s sees writes committed since starting iteration",
+ s->hdb_name);
+ } else if (ret != HDB_ERR_NOENTRY) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret,
+ "Could not iterate while writing to HDB %s (2)", s->hdb_name);
+ }
+
+ /* Tell the writer we're done */
+ printf("Reader thread telling writer to go\n");
+ s->writer_go = 1;
+ (void) pthread_cond_signal(&s->wcv);
+ (void) pthread_mutex_unlock(&s->lock);
+
+ dbr->hdb_close(context, dbr);
+ dbr->hdb_destroy(context, dbr);
+ krb5_free_context(context);
+ printf("Reader thread exiting\n");
+ return 0;
+}
+
+static void
+forked_reader(struct tsync *s)
+{
+ krb5_error_code ret;
+ krb5_context context;
+ hdb_entry entr;
+ ssize_t bytes;
+ char b[1];
+ HDB *dbr = NULL;
+
+ printf("Reader process opening HDB\n");
+
+ (void) close(s->writer_go_pipe[0]);
+ (void) close(s->reader_go_pipe[1]);
+ s->writer_go_pipe[0] = -1;
+ s->reader_go_pipe[1] = -1;
+ if ((krb5_init_context(&context)))
+ errx(1, "krb5_init_context failed");
+
+ printf("Reader process waiting for writer\n");
+ while ((bytes = read(s->reader_go_pipe[0], b, sizeof(b))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1)
+ err(1, "Could not read from reader-go pipe (error)");
+
+ /* Open a new HDB handle to read */
+ if ((ret = hdb_create(context, &dbr, s->hdb_name))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not get a handle for HDB %s (read)",
+ s->hdb_name);
+ }
+ if ((ret = dbr->hdb_open(context, dbr, O_RDONLY, 0))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not open HDB %s", s->hdb_name);
+ }
+ if ((ret = dbr->hdb_firstkey(context, dbr, 0, &entr))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name);
+ }
+ printf("Reader process iterated one entry\n");
+ free_HDB_entry(&entr);
+
+ /* Tell the writer to go ahead and write */
+ printf("Reader process iterated one entry; telling writer to write more\n");
+ while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1)
+ err(1, "Could not write to writer-go pipe (error)");
+
+
+ /* Wait for the writer to have written one more entry to the HDB */
+ printf("Reader process waiting for writer\n");
+ while ((bytes = read(s->reader_go_pipe[0], b, sizeof(b))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1)
+ err(1, "Could not read from reader-go pipe (error)");
+ if (bytes == 0)
+ errx(1, "Could not read from reader-go pipe (EOF)");
+
+ /* Iterate the rest */
+ if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr))) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret,
+ "Could not iterate while writing to HDB %s", s->hdb_name);
+ }
+ free_HDB_entry(&entr);
+ printf("Reader process iterated another entry\n");
+ if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) {
+ //(void) unlink(s->fname);
+ krb5_warn(context, ret,
+ "HDB %s sees writes committed since starting iteration (%s)",
+ s->hdb_name, entr.principal->name.name_string.val[0]);
+ } else if (ret != HDB_ERR_NOENTRY) {
+ //(void) unlink(s->fname);
+ krb5_err(context, 1, ret,
+ "Could not iterate while writing to HDB %s (2)", s->hdb_name);
+ }
+
+ /* Tell the writer we're done */
+ printf("Reader process done; telling writer to go\n");
+ while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1)
+ err(1, "Could not write to writer-go pipe (error)");
+
+ dbr->hdb_close(context, dbr);
+ dbr->hdb_destroy(context, dbr);
+ krb5_free_context(context);
+ (void) close(s->writer_go_pipe[1]);
+ (void) close(s->reader_go_pipe[0]);
+ printf("Reader process exiting\n");
+ _exit(0);
+}
+
+static krb5_error_code
+make_entry(krb5_context context, hdb_entry *entry, const char *name)
+{
+ krb5_error_code ret;
+
+ memset(entry, 0, sizeof(*entry));
+ entry->kvno = 2;
+ entry->keys.len = 0;
+ entry->keys.val = NULL;
+ entry->created_by.time = time(NULL);
+ entry->modified_by = NULL;
+ entry->valid_start = NULL;
+ entry->valid_end = NULL;
+ entry->max_life = NULL;
+ entry->max_renew = NULL;
+ entry->etypes = NULL;
+ entry->generation = NULL;
+ entry->extensions = NULL;
+ if ((ret = krb5_make_principal(context, &entry->principal,
+ "TEST.H5L.SE", name, NULL)))
+ return ret;
+ if ((ret = krb5_make_principal(context, &entry->created_by.principal,
+ "TEST.H5L.SE", "tester", NULL)))
+ return ret;
+ return 0;
+}
+
+static void
+readers_turn(struct tsync *s, pid_t child, int threaded)
+{
+ if (threaded) {
+ (void) pthread_mutex_lock(&s->lock);
+ s->reader_go = 1;
+ (void) pthread_cond_signal(&s->rcv);
+
+ while (!s->writer_go)
+ (void) pthread_cond_wait(&s->wcv, &s->lock);
+ s->writer_go = 0;
+ (void) pthread_mutex_unlock(&s->lock);
+ } else {
+ ssize_t bytes;
+ char b[1];
+
+ while ((bytes = write(s->reader_go_pipe[1], "", sizeof(""))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1) {
+ kill(child, SIGKILL);
+ err(1, "Could not write to reader-go pipe (error)");
+ }
+ if (bytes == 0) {
+ kill(child, SIGKILL);
+ err(1, "Could not write to reader-go pipe (EOF?)");
+ }
+
+ while ((bytes = read(s->writer_go_pipe[0], b, sizeof(b))) == -1 &&
+ errno == EINTR)
+ ;
+ if (bytes == -1) {
+ kill(child, SIGKILL);
+ err(1, "Could not read from writer-go pipe");
+ }
+ if (bytes == 0) {
+ kill(child, SIGKILL);
+ errx(1, "Child errored");
+ }
+ s->writer_go = 0;
+ }
+}
+
+static void
+test_hdb_concurrency(char *name, const char *ext, int threaded)
+{
+ krb5_error_code ret;
+ krb5_context context;
+ char *fname = strchr(name, ':') + 1;
+ char *fname_ext = NULL;
+ pthread_t reader_thread;
+ struct tsync ts;
+ hdb_entry entw;
+ pid_t child = getpid();
+ HDB *dbw = NULL;
+ int status;
+ int fd;
+
+ memset(&ts, 0, sizeof(ts));
+ (void) pthread_cond_init(&ts.rcv, NULL);
+ (void) pthread_cond_init(&ts.wcv, NULL);
+ (void) pthread_mutex_init(&ts.lock, NULL);
+
+ if ((krb5_init_context(&context)))
+ errx(1, "krb5_init_context failed");
+
+ /* Use mkstemp() then unlink() to avoid warnings about mktemp(); ugh */
+ if ((fd = mkstemp(fname)) == -1)
+ err(1, "mkstemp(%s)", fname);
+ (void) close(fd);
+ (void) unlink(fname);
+ if (asprintf(&fname_ext, "%s%s", fname, ext ? ext : "") == -1 ||
+ fname_ext == NULL)
+ err(1, "Out of memory");
+ ts.hdb_name = name;
+ ts.fname = fname_ext;
+
+ if (threaded) {
+ printf("Starting reader thread\n");
+ (void) pthread_mutex_lock(&ts.lock);
+ if ((errno = pthread_create(&reader_thread, NULL, threaded_reader, &ts))) {
+ (void) unlink(fname_ext);
+ krb5_err(context, 1, errno, "Could not create a thread to read HDB");
+ }
+
+ /* Wait for reader */
+ while (!ts.writer_go)
+ (void) pthread_cond_wait(&ts.wcv, &ts.lock);
+ (void) pthread_mutex_unlock(&ts.lock);
+ } else {
+ printf("Starting reader process\n");
+ if (pipe(ts.writer_go_pipe) == -1)
+ err(1, "Could not create a pipe");
+ if (pipe(ts.reader_go_pipe) == -1)
+ err(1, "Could not create a pipe");
+ switch ((child = fork())) {
+ case -1: err(1, "Could not fork a child");
+ case 0: forked_reader(&ts); _exit(0);
+ default: break;
+ }
+ (void) close(ts.writer_go_pipe[1]);
+ ts.writer_go_pipe[1] = -1;
+ }
+
+ printf("Writing two entries into HDB\n");
+ if ((ret = hdb_create(context, &dbw, name)))
+ krb5_err(context, 1, ret, "Could not get a handle for HDB %s (write)",
+ name);
+ if ((ret = dbw->hdb_open(context, dbw, O_RDWR | O_CREAT, 0600)))
+ krb5_err(context, 1, ret, "Could not create HDB %s", name);
+
+ /* Add two entries */
+ memset(&entw, 0, sizeof(entw));
+ if ((ret = make_entry(context, &entw, "foo")) ||
+ (ret = dbw->hdb_store(context, dbw, 0, &entw))) {
+ (void) unlink(fname_ext);
+ krb5_err(context, 1, ret,
+ "Could not store entry for \"foo\" in HDB %s", name);
+ }
+ free_HDB_entry(&entw);
+ if ((ret = make_entry(context, &entw, "bar")) ||
+ (ret = dbw->hdb_store(context, dbw, 0, &entw))) {
+ (void) unlink(fname_ext);
+ krb5_err(context, 1, ret,
+ "Could not store entry for \"foo\" in HDB %s", name);
+ }
+ free_HDB_entry(&entw);
+
+ /* Tell the reader to start reading */
+ readers_turn(&ts, child, threaded);
+
+ /* Store one more entry */
+ if ((ret = make_entry(context, &entw, "foobar")) ||
+ (ret = dbw->hdb_store(context, dbw, 0, &entw))) {
+ (void) unlink(fname_ext);
+ krb5_err(context, 1, ret,
+ "Could not store entry for \"foobar\" in HDB %s "
+ "while iterating it", name);
+ }
+ free_HDB_entry(&entw);
+
+ /* Tell the reader to go again */
+ readers_turn(&ts, child, threaded);
+
+ dbw->hdb_close(context, dbw);
+ dbw->hdb_destroy(context, dbw);
+ if (threaded) {
+ (void) pthread_join(reader_thread, NULL);
+ } else {
+ (void) close(ts.writer_go_pipe[1]);
+ (void) close(ts.reader_go_pipe[0]);
+ (void) close(ts.reader_go_pipe[1]);
+ while (wait(&status) == -1 && errno == EINTR)
+ ;
+ (void) close(ts.writer_go_pipe[0]);
+ if (!WIFEXITED(status))
+ errx(1, "Child reader died");
+ if (WEXITSTATUS(status) != 0)
+ errx(1, "Child reader errored");
+ }
+ (void) unlink(fname_ext);
+ krb5_free_context(context);
+}
+
+static int use_fork;
+static int use_threads;
+static int help_flag;
+static int version_flag;
+
+struct getargs args[] = {
+ { "use-fork", 'f', arg_flag, &use_fork, NULL, NULL },
+ { "use-threads", 't', arg_flag, &use_threads, 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]);
+
+int
+main(int argc, char **argv)
+{
+ char stemplate[sizeof("sqlite:testhdb-XXXXXX")];
+#ifdef HAVE_LMDB
+ char ltemplate[sizeof("lmdb:testhdb-XXXXXX")];
+#endif
+ int o = 0;
+
+ setprogname(argv[0]);
+
+ if (getarg(args, num_args, argc, argv, &o))
+ krb5_std_usage(1, args, num_args);
+
+ if (help_flag)
+ krb5_std_usage(0, args, num_args);
+
+ if (version_flag){
+ print_version(NULL);
+ return 0;
+ }
+
+ if (!use_fork && !use_threads)
+ use_threads = use_fork = 1;
+
+#ifdef HAVE_FORK
+ if (use_fork) {
+ printf("Testing SQLite3 HDB backend (multi-process)\n");
+ memcpy(stemplate, "sqlite:testhdb-XXXXXX", sizeof("sqlite:testhdb-XXXXXX"));
+ test_hdb_concurrency(stemplate, "", 0);
+
+#ifdef HAVE_LMDB
+ printf("Testing LMDB HDB backend (multi-process)\n");
+ memcpy(ltemplate, "lmdb:testhdb-XXXXXX", sizeof("lmdb:testhdb-XXXXXX"));
+ test_hdb_concurrency(ltemplate, ".lmdb", 0);
+#endif
+ }
+#endif
+
+ if (use_threads) {
+ printf("Testing SQLite3 HDB backend (multi-process)\n");
+ memcpy(stemplate, "sqlite:testhdb-XXXXXX", sizeof("sqlite:testhdb-XXXXXX"));
+ test_hdb_concurrency(stemplate, "", 1);
+
+#ifdef HAVE_LMDB
+ printf("Testing LMDB HDB backend (multi-process)\n");
+ memcpy(ltemplate, "lmdb:testhdb-XXXXXX", sizeof("lmdb:testhdb-XXXXXX"));
+ test_hdb_concurrency(ltemplate, ".lmdb", 1);
+#endif
+ }
+ return 0;
+}
diff --git a/lib/hdb/test_dbinfo.c b/lib/hdb/test_dbinfo.c
index b94b75bb3746..195fd4151dc4 100644
--- a/lib/hdb/test_dbinfo.c
+++ b/lib/hdb/test_dbinfo.c
@@ -44,6 +44,65 @@ struct getargs args[] = {
static int num_args = sizeof(args) / sizeof(args[0]);
+/*
+ * Prove that HDB_EntryOrAlias being a CHOICE of hdb_entry or hdb_entry_alias
+ * adds nothing to the encoding of those types.
+ */
+static
+void
+check_HDB_EntryOrAlias(krb5_context context)
+{
+ HDB_EntryOrAlias eoa;
+ hdb_entry entry;
+ hdb_entry_alias alias;
+ krb5_data v;
+ size_t len;
+ int ret;
+
+ memset(&entry, 0, sizeof(entry));
+ memset(&alias, 0, sizeof(alias));
+ memset(&eoa, 0, sizeof(eoa));
+ krb5_data_zero(&v);
+
+ ret = krb5_make_principal(context, &alias.principal, "KTH.SE", "foo",
+ NULL);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_make_principal");
+ ASN1_MALLOC_ENCODE(HDB_entry_alias, v.data, v.length, &alias, &len, ret);
+ if (ret)
+ krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias");
+ if (v.length != len)
+ abort();
+ ret = decode_HDB_EntryOrAlias(v.data, v.length, &eoa, &len);
+ if (ret)
+ krb5_err(context, 1, ret, "decode_HDB_EntryOrAlias");
+ if (v.length != len)
+ abort();
+ free_HDB_EntryOrAlias(&eoa);
+ free_HDB_entry_alias(&alias);
+ krb5_data_free(&v);
+
+ ret = krb5_make_principal(context, &entry.principal, "KTH.SE", "foo",
+ NULL);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_make_principal");
+ entry.kvno = 5;
+ entry.flags.initial = 1;
+ ASN1_MALLOC_ENCODE(HDB_entry, v.data, v.length, &entry, &len, ret);
+ if (ret)
+ krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias");
+ if (v.length != len)
+ abort();
+ ret = decode_HDB_EntryOrAlias(v.data, v.length, &eoa, &len);
+ if (ret)
+ krb5_err(context, 1, ret, "decode_HDB_EntryOrAlias");
+ if (v.length != len)
+ abort();
+ free_HDB_EntryOrAlias(&eoa);
+ free_HDB_entry(&entry);
+ krb5_data_free(&v);
+}
+
int
main(int argc, char **argv)
{
@@ -68,6 +127,8 @@ main(int argc, char **argv)
if (ret)
errx (1, "krb5_init_context failed: %d", ret);
+ check_HDB_EntryOrAlias(context);
+
ret = hdb_get_dbinfo(context, &info);
if (ret)
krb5_err(context, 1, ret, "hdb_get_dbinfo");
diff --git a/lib/hdb/test_hdbkeys.c b/lib/hdb/test_hdbkeys.c
index 7cf4629b6ce0..d6bc31d4caf3 100644
--- a/lib/hdb/test_hdbkeys.c
+++ b/lib/hdb/test_hdbkeys.c
@@ -104,7 +104,7 @@ main(int argc, char **argv)
krb5_free_principal (context, principal);
- ASN1_MALLOC_ENCODE(hdb_keyset, data, length, &keyset, &len, ret);
+ ASN1_MALLOC_ENCODE(HDB_keyset, data, length, &keyset, &len, ret);
if (ret)
krb5_errx(context, 1, "encode keyset");
if (len != length)
diff --git a/lib/hdb/test_hdbplugin.c b/lib/hdb/test_hdbplugin.c
deleted file mode 100644
index 4ebceb8da072..000000000000
--- a/lib/hdb/test_hdbplugin.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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_namespace.c b/lib/hdb/test_namespace.c
new file mode 100644
index 000000000000..f9b4cdbdde89
--- /dev/null
+++ b/lib/hdb/test_namespace.c
@@ -0,0 +1,941 @@
+/*
+ * Copyright (c) 2020 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/*
+ * This program implements an ephemeral, memory-based HDB backend, stores into
+ * it just one HDB entry -one for a namespace- then checks that virtual
+ * principals are returned below that namespace by hdb_fetch_kvno(), and that
+ * the logic for automatic key rotation of virtual principals is correct.
+ */
+
+#include "hdb_locl.h"
+#include <hex.h>
+
+static KeyRotation krs[2];
+static const char *base_pw[2] = { "Testing123...", "Tested123..." };
+
+typedef struct {
+ HDB hdb; /* generic members */
+ /*
+ * Make this dict a global, add a mutex lock around it, and a .finit and/or
+ * atexit() handler to free it, and we'd have a first-class MEMORY HDB.
+ *
+ * What would a first-class MEMORY HDB be good for though, besides testing?
+ *
+ * However, we could move this dict into `HDB' and then have _hdb_store()
+ * and friends support it as a cache for frequently-used & seldom-changing
+ * entries, such as: K/M, namespaces, and krbtgt principals. That would
+ * speed up lookups, especially for backends with poor reader-writer
+ * concurrency (DB, LMDB) and LDAP. Such entries could be cached for a
+ * minute or three at a time.
+ */
+ heim_dict_t dict;
+} TEST_HDB;
+
+struct hdb_called {
+ int create;
+ int init;
+ int fini;
+};
+
+static krb5_error_code
+TDB_close(krb5_context context, HDB *db)
+{
+ return 0;
+}
+
+static krb5_error_code
+TDB_destroy(krb5_context context, HDB *db)
+{
+ TEST_HDB *tdb = (void *)db;
+
+ heim_release(tdb->dict);
+ free(tdb->hdb.hdb_name);
+ free(tdb);
+ return 0;
+}
+
+static krb5_error_code
+TDB_set_sync(krb5_context context, HDB *db, int on)
+{
+ return 0;
+}
+
+static krb5_error_code
+TDB_lock(krb5_context context, HDB *db, int operation)
+{
+
+ return 0;
+}
+
+static krb5_error_code
+TDB_unlock(krb5_context context, HDB *db)
+{
+
+ return 0;
+}
+
+static krb5_error_code
+TDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+ /* XXX Implement */
+ /* Tricky thing: heim_dict_iterate_f() is inconvenient here */
+ /* We need this to check that virtual principals aren't created */
+ return 0;
+}
+
+static krb5_error_code
+TDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+ /* XXX Implement */
+ /* Tricky thing: heim_dict_iterate_f() is inconvenient here */
+ /* We need this to check that virtual principals aren't created */
+ return 0;
+}
+
+static krb5_error_code
+TDB_rename(krb5_context context, HDB *db, const char *new_name)
+{
+ return EEXIST;
+}
+
+static krb5_error_code
+TDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
+{
+ krb5_error_code ret = 0;
+ TEST_HDB *tdb = (void *)db;
+ heim_object_t k, v = NULL;
+
+ if ((k = heim_data_create(key.data, key.length)) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0 && (v = heim_dict_get_value(tdb->dict, k)) == NULL)
+ ret = HDB_ERR_NOENTRY;
+ if (ret == 0)
+ ret = krb5_data_copy(reply, heim_data_get_ptr(v), heim_data_get_length(v));
+ heim_release(k);
+ return ret;
+}
+
+static krb5_error_code
+TDB__put(krb5_context context, HDB *db, int rplc, krb5_data kd, krb5_data vd)
+{
+ krb5_error_code ret = 0;
+ TEST_HDB *tdb = (void *)db;
+ heim_object_t k = NULL;
+ heim_object_t v = NULL;
+
+ if ((k = heim_data_create(kd.data, kd.length)) == NULL ||
+ (v = heim_data_create(vd.data, vd.length)) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0 && !rplc && heim_dict_get_value(tdb->dict, k) != NULL)
+ ret = HDB_ERR_EXISTS;
+ if (ret == 0 && heim_dict_set_value(tdb->dict, k, v))
+ ret = krb5_enomem(context);
+ heim_release(k);
+ heim_release(v);
+ return ret;
+}
+
+static krb5_error_code
+TDB__del(krb5_context context, HDB *db, krb5_data key)
+{
+ krb5_error_code ret = 0;
+ TEST_HDB *tdb = (void *)db;
+ heim_object_t k;
+
+ if ((k = heim_data_create(key.data, key.length)) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0 && heim_dict_get_value(tdb->dict, k) == NULL)
+ ret = HDB_ERR_NOENTRY;
+ if (ret == 0)
+ heim_dict_delete_key(tdb->dict, k);
+ heim_release(k);
+ return ret;
+}
+
+static krb5_error_code
+TDB_open(krb5_context context, HDB *db, int flags, mode_t mode)
+{
+ return 0;
+}
+
+static krb5_error_code
+hdb_test_create(krb5_context context, struct HDB **db, const char *arg)
+{
+ TEST_HDB *tdb;
+
+ if ((tdb = calloc(1, sizeof(tdb[0]))) == NULL ||
+ (tdb->hdb.hdb_name = strdup(arg)) == NULL ||
+ (tdb->dict = heim_dict_create(10)) == NULL) {
+ if (tdb)
+ free(tdb->hdb.hdb_name);
+ free(tdb);
+ return krb5_enomem(context);
+ }
+
+ tdb->hdb.hdb_db = NULL;
+ tdb->hdb.hdb_master_key_set = 0;
+ tdb->hdb.hdb_openp = 0;
+ tdb->hdb.hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
+ tdb->hdb.hdb_open = TDB_open;
+ tdb->hdb.hdb_close = TDB_close;
+ tdb->hdb.hdb_fetch_kvno = _hdb_fetch_kvno;
+ tdb->hdb.hdb_store = _hdb_store;
+ tdb->hdb.hdb_remove = _hdb_remove;
+ tdb->hdb.hdb_firstkey = TDB_firstkey;
+ tdb->hdb.hdb_nextkey= TDB_nextkey;
+ tdb->hdb.hdb_lock = TDB_lock;
+ tdb->hdb.hdb_unlock = TDB_unlock;
+ tdb->hdb.hdb_rename = TDB_rename;
+ tdb->hdb.hdb__get = TDB__get;
+ tdb->hdb.hdb__put = TDB__put;
+ tdb->hdb.hdb__del = TDB__del;
+ tdb->hdb.hdb_destroy = TDB_destroy;
+ tdb->hdb.hdb_set_sync = TDB_set_sync;
+ *db = &tdb->hdb;
+
+ return 0;
+}
+
+static krb5_error_code
+hdb_test_init(krb5_context context, void **ctx)
+{
+ *ctx = NULL;
+ return 0;
+}
+
+static void hdb_test_fini(void *ctx)
+{
+}
+
+struct hdb_method hdb_test =
+{
+#ifdef WIN32
+ /* Not c99 */
+ HDB_INTERFACE_VERSION,
+ hdb_test_init,
+ hdb_test_fini,
+ 1 /*is_file_based*/, 1 /*can_taste*/,
+ "test",
+ hdb_test_create
+#else
+ .minor_version = HDB_INTERFACE_VERSION,
+ .init = hdb_test_init,
+ .fini = hdb_test_fini,
+ .is_file_based = 1,
+ .can_taste = 1,
+ .prefix = "test",
+ .create = hdb_test_create
+#endif
+};
+
+static krb5_error_code
+make_base_key(krb5_context context,
+ krb5_const_principal p,
+ const char *pw,
+ krb5_keyblock *k)
+{
+ return krb5_string_to_key(context, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
+ pw, p, k);
+}
+
+static krb5_error_code
+tderive_key(krb5_context context,
+ const char *p,
+ KeyRotation *kr,
+ int toffset,
+ krb5_keyblock *base,
+ krb5int32 etype,
+ krb5_keyblock *k,
+ uint32_t *kvno,
+ time_t *set_time)
+{
+ krb5_error_code ret = 0;
+ krb5_crypto crypto = NULL;
+ EncryptionKey intermediate;
+ krb5_data pad, out;
+ size_t len;
+ int n;
+
+ n = toffset / kr->period;
+ *set_time = kr->epoch + kr->period * n;
+ *kvno = kr->base_kvno + n;
+
+ out.data = 0;
+ out.length = 0;
+
+ /* Derive intermediate key */
+ pad.data = (void *)(uintptr_t)p;
+ pad.length = strlen(p);
+ ret = krb5_enctype_keysize(context, base->keytype, &len);
+ if (ret == 0)
+ ret = krb5_crypto_init(context, base, 0, &crypto);
+ if (ret == 0)
+ ret = krb5_crypto_prfplus(context, crypto, &pad, len, &out);
+ if (crypto)
+ krb5_crypto_destroy(context, crypto);
+ crypto = NULL;
+ if (ret == 0)
+ ret = krb5_random_to_key(context, etype, out.data, out.length,
+ &intermediate);
+ krb5_data_free(&out);
+
+ /* Derive final key */
+ pad.data = kvno;
+ pad.length = sizeof(*kvno);
+ if (ret == 0)
+ ret = krb5_enctype_keysize(context, etype, &len);
+ if (ret == 0)
+ ret = krb5_crypto_init(context, &intermediate, 0, &crypto);
+ if (ret == 0) {
+ *kvno = htonl(*kvno);
+ ret = krb5_crypto_prfplus(context, crypto, &pad, len, &out);
+ *kvno = ntohl(*kvno);
+ }
+ if (crypto)
+ krb5_crypto_destroy(context, crypto);
+ if (ret == 0)
+ ret = krb5_random_to_key(context, etype, out.data, out.length, k);
+ krb5_data_free(&out);
+
+ free_EncryptionKey(&intermediate);
+ return ret;
+}
+
+/* Create a namespace principal */
+static void
+make_namespace(krb5_context context, HDB *db, const char *name)
+{
+ krb5_error_code ret = 0;
+ hdb_entry e;
+ Key k;
+
+ memset(&k, 0, sizeof(k));
+ k.mkvno = 0;
+ k.salt = 0;
+
+ /* Setup the HDB entry */
+ memset(&e, 0, sizeof(e));
+ e.created_by.time = krs[0].epoch;
+ e.valid_start = e.valid_end = e.pw_end = 0;
+ e.generation = 0;
+ e.flags = int2HDBFlags(0);
+ e.flags.server = e.flags.client = 1;
+ e.flags.virtual = 1;
+
+ /* Setup etypes */
+ if (ret == 0 &&
+ (e.etypes = malloc(sizeof(*e.etypes))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0)
+ e.etypes->len = 3;
+ if (ret == 0 &&
+ (e.etypes->val = calloc(e.etypes->len,
+ sizeof(e.etypes->val[0]))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0) {
+ e.etypes->val[0] = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128;
+ e.etypes->val[1] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192;
+ e.etypes->val[2] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ }
+
+ /* Setup max_life and max_renew */
+ if (ret == 0 &&
+ (e.max_life = malloc(sizeof(*e.max_life))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0 &&
+ (e.max_renew = malloc(sizeof(*e.max_renew))) == NULL)
+ ret = krb5_enomem(context);
+ if (ret == 0)
+ /* Make it long, so we see the clamped max */
+ *e.max_renew = 2 * ((*e.max_life = 15 * 24 * 3600));
+
+ /* Setup principal name and created_by */
+ if (ret == 0)
+ ret = krb5_parse_name(context, name, &e.principal);
+ if (ret == 0)
+ ret = krb5_parse_name(context, "admin@BAR.EXAMPLE",
+ &e.created_by.principal);
+
+ /* Make base keys for first epoch */
+ if (ret == 0)
+ ret = make_base_key(context, e.principal, base_pw[0], &k.key);
+ if (ret == 0)
+ add_Keys(&e.keys, &k);
+ if (ret == 0)
+ ret = hdb_entry_set_pw_change_time(context, &e, krs[0].epoch);
+ free_Key(&k);
+ e.kvno = krs[0].base_key_kvno;
+
+ /* Move them to history */
+ if (ret == 0)
+ ret = hdb_add_current_keys_to_history(context, &e);
+ free_Keys(&e.keys);
+
+ /* Make base keys for second epoch */
+ if (ret == 0)
+ ret = make_base_key(context, e.principal, base_pw[1], &k.key);
+ if (ret == 0)
+ add_Keys(&e.keys, &k);
+ e.kvno = krs[1].base_key_kvno;
+ if (ret == 0)
+ ret = hdb_entry_set_pw_change_time(context, &e, krs[1].epoch);
+
+ /* Add the key rotation metadata */
+ if (ret == 0)
+ ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[0]);
+ if (ret == 0)
+ ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[1]);
+
+ if (ret == 0)
+ ret = db->hdb_store(context, db, 0, &e);
+ if (ret)
+ krb5_err(context, 1, ret, "failed to setup a namespace principal");
+ free_Key(&k);
+ hdb_free_entry(context, db, &e);
+}
+
+#define WK_PREFIX "WELLKNOWN/" HDB_WK_NAMESPACE "/"
+
+static const char *expected[] = {
+ WK_PREFIX "_/bar.example@BAR.EXAMPLE",
+ "HTTP/bar.example@BAR.EXAMPLE",
+ "HTTP/foo.bar.example@BAR.EXAMPLE",
+ "host/foo.bar.example@BAR.EXAMPLE",
+ "HTTP/blah.foo.bar.example@BAR.EXAMPLE",
+};
+static const char *unexpected[] = {
+ WK_PREFIX "_/no.example@BAZ.EXAMPLE",
+ "HTTP/no.example@BAR.EXAMPLE",
+ "HTTP/foo.no.example@BAR.EXAMPLE",
+ "HTTP/blah.foo.no.example@BAR.EXAMPLE",
+};
+
+/*
+ * We'll fetch as many entries as we have principal names in `expected[]', for
+ * as many KeyRotation periods as we have (between 1 and 3), and for up to 5
+ * different time offsets in each period.
+ */
+#define NUM_OFFSETS 5
+static hdb_entry e[
+ (sizeof(expected) / sizeof(expected[0])) *
+ (sizeof(krs) / sizeof(krs[0])) *
+ NUM_OFFSETS
+];
+
+static int
+hist_key_compar(const void *va, const void *vb)
+{
+ const hdb_keyset *a = va;
+ const hdb_keyset *b = vb;
+
+ return a->kvno - b->kvno;
+}
+
+/*
+ * Fetch keys for some decent time in the given kr.
+ *
+ * `kr' is an index into the global `krs[]'.
+ * `t' is a number 0..4 inclusive that identifies a time period relative to the
+ * epoch of `krs[kr]' (see code below).
+ */
+static void
+fetch_entries(krb5_context context,
+ HDB *db,
+ size_t kr,
+ size_t t,
+ int must_fail)
+{
+ krb5_error_code ret = 0;
+ krb5_principal p = NULL;
+ krb5_keyblock base_key, dk;
+ hdb_entry *ep;
+ hdb_entry no;
+ size_t i, b;
+ int toffset = 0;
+
+ memset(&base_key, 0, sizeof(base_key));
+
+ /* Work out offset of first entry in `e[]' */
+ assert(kr < sizeof(krs) / sizeof(krs[0]));
+ assert(t < NUM_OFFSETS);
+ b = (kr * NUM_OFFSETS + t) * (sizeof(expected) / sizeof(expected[0]));
+ assert(b < sizeof(e) / sizeof(e[0]));
+ assert(sizeof(e) / sizeof(e[0]) - b >=
+ (sizeof(expected) / sizeof(expected[0])));
+
+ switch (t) {
+ case 0: toffset = 1; break; /* epoch + 1s */
+ case 1: toffset = 1 + (krs[kr].period >> 1); break; /* epoch + period/2 */
+ case 2: toffset = 1 + (krs[kr].period >> 2); break; /* epoch + period/4 */
+ case 3: toffset = 1 + (krs[kr].period >> 3); break; /* epoch + period/8 */
+ case 4: toffset = 1 - (krs[kr].period >> 3); break; /* epoch - period/8 */
+ }
+
+ for (i = 0; ret == 0 && i < sizeof(expected) / sizeof(expected[0]); i++) {
+ ep = &e[b + i];
+ memset(ep, 0, sizeof(*ep));
+ if (ret == 0)
+ ret = krb5_parse_name(context, expected[i], &p);
+ if (ret == 0 && i == 0) {
+ if (toffset < 0 && kr)
+ ret = make_base_key(context, p, base_pw[kr - 1], &base_key);
+ else
+ ret = make_base_key(context, p, base_pw[kr], &base_key);
+ }
+ if (ret == 0)
+ ret = hdb_fetch_kvno(context, db, p,
+ HDB_F_DECRYPT | HDB_F_ALL_KVNOS,
+ krs[kr].epoch + toffset, 0, 0, ep);
+ if (i && must_fail && ret == 0)
+ krb5_errx(context, 1,
+ "virtual principal that shouldn't exist does");
+ if (kr == 0 && toffset < 0 && ret == HDB_ERR_NOENTRY)
+ continue;
+ if (kr == 0 && toffset < 0) {
+ /*
+ * Virtual principals don't exist before their earliest key
+ * rotation epoch's start time.
+ */
+ if (i == 0) {
+ if (ret)
+ krb5_errx(context, 1,
+ "namespace principal does not exist before its time");
+ } else if (i != 0) {
+ if (ret == 0)
+ krb5_errx(context, 1,
+ "virtual principal exists before its time");
+ if (ret != HDB_ERR_NOENTRY)
+ krb5_errx(context, 1, "wrong error code");
+ ret = 0;
+ }
+ } else {
+ if (ret == 0 &&
+ !krb5_principal_compare(context, p, ep->principal))
+ krb5_errx(context, 1, "wrong principal in fetched entry");
+ }
+
+ {
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension *ext;
+ ext = hdb_find_extension(ep,
+ choice_HDB_extension_data_hist_keys);
+ if (ext) {
+ /* Sort key history by kvno, why not */
+ hist_keys = &ext->data.u.hist_keys;
+ qsort(hist_keys->val, hist_keys->len,
+ sizeof(hist_keys->val[0]), hist_key_compar);
+ }
+ }
+
+ krb5_free_principal(context, p);
+ }
+ if (ret && must_fail) {
+ free_EncryptionKey(&base_key);
+ return;
+ }
+ if (ret)
+ krb5_err(context, 1, ret, "virtual principal test failed");
+
+ for (i = 0; i < sizeof(unexpected) / sizeof(unexpected[0]); i++) {
+ memset(&no, 0, sizeof(no));
+ if (ret == 0)
+ ret = krb5_parse_name(context, unexpected[i], &p);
+ if (ret == 0)
+ ret = hdb_fetch_kvno(context, db, p, HDB_F_DECRYPT,
+ krs[kr].epoch + toffset, 0, 0, &no);
+ if (ret == 0)
+ krb5_errx(context, 1, "bogus principal exists, wat");
+ krb5_free_principal(context, p);
+ ret = 0;
+ }
+
+ if (kr == 0 && toffset < 0)
+ return;
+
+ /*
+ * XXX
+ *
+ * Add check that derived keys are a) different, b) as expected, using a
+ * set of test vectors or else by computing the expected keys here with
+ * code that's not shared with lib/hdb/common.c.
+ *
+ * Add check that we get expected past and/or future keys, not just current
+ * keys.
+ */
+ for (i = 1; ret == 0 && i < sizeof(expected) / sizeof(expected[0]); i++) {
+ uint32_t kvno;
+ time_t set_time, chg_time;
+
+ ep = &e[b + i];
+ if (toffset > 0) {
+ ret = tderive_key(context, expected[i], &krs[kr], toffset,
+ &base_key, base_key.keytype, &dk, &kvno, &set_time);
+ } else /* XXX */{
+ /* XXX */
+ assert(kr);
+ ret = tderive_key(context, expected[i], &krs[kr - 1],
+ krs[kr].epoch - krs[kr - 1].epoch + toffset,
+ &base_key, base_key.keytype, &dk, &kvno, &set_time);
+ }
+ if (ret)
+ krb5_err(context, 1, ret, "deriving keys for comparison");
+
+ if (kvno != ep->kvno)
+ krb5_errx(context, 1, "kvno mismatch (%u != %u)", kvno, ep->kvno);
+ (void) hdb_entry_get_pw_change_time(ep, &chg_time);
+ if (set_time != chg_time)
+ krb5_errx(context, 1, "key change time mismatch");
+ if (ep->keys.len == 0)
+ krb5_errx(context, 1, "no keys!");
+ if (ep->keys.val[0].key.keytype != dk.keytype)
+ krb5_errx(context, 1, "enctype mismatch!");
+ if (ep->keys.val[0].key.keyvalue.length !=
+ dk.keyvalue.length)
+ krb5_errx(context, 1, "key length mismatch!");
+ if (memcmp(ep->keys.val[0].key.keyvalue.data,
+ dk.keyvalue.data, dk.keyvalue.length) != 0)
+ krb5_errx(context, 1, "key mismatch!");
+ if (memcmp(ep->keys.val[0].key.keyvalue.data,
+ e[b + i - 1].keys.val[0].key.keyvalue.data,
+ dk.keyvalue.length) == 0)
+ krb5_errx(context, 1, "different virtual principals have the same keys!");
+ /* XXX Add check that we have the expected number of history keys */
+ free_EncryptionKey(&dk);
+ }
+ free_EncryptionKey(&base_key);
+}
+
+static void
+check_kvnos(krb5_context context)
+{
+ HDB_Ext_KeySet keysets;
+ size_t i, k, m, p; /* iterator indices */
+
+ keysets.len = 0;
+ keysets.val = 0;
+
+ /* For every principal name */
+ for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++) {
+ free_HDB_Ext_KeySet(&keysets);
+
+ /* For every entry we've fetched for it */
+ for (k = 0; k < sizeof(e)/sizeof(e[0]); k++) {
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension *ext;
+ hdb_entry *ep;
+ int match = 0;
+
+ if ((k % NUM_OFFSETS) != i)
+ continue;
+
+ ep = &e[k];
+ if (ep->principal == NULL)
+ continue; /* Didn't fetch this one */
+
+ /*
+ * Check that the current keys for it match what we've seen already
+ * or else add them to `keysets'.
+ */
+ for (m = 0; m < keysets.len; m++) {
+ if (ep->kvno == keysets.val[m].kvno) {
+ /* Check the key is the same */
+ if (ep->keys.val[0].key.keytype !=
+ keysets.val[m].keys.val[0].key.keytype ||
+ ep->keys.val[0].key.keyvalue.length !=
+ keysets.val[m].keys.val[0].key.keyvalue.length ||
+ memcmp(ep->keys.val[0].key.keyvalue.data,
+ keysets.val[m].keys.val[0].key.keyvalue.data,
+ ep->keys.val[0].key.keyvalue.length) != 0)
+ krb5_errx(context, 1,
+ "key mismatch for same princ & kvno");
+ match = 1;
+ }
+ }
+ if (m == keysets.len) {
+ hdb_keyset ks;
+
+ ks.kvno = ep->kvno;
+ ks.keys = ep->keys;
+ ks.set_time = 0;
+ if (add_HDB_Ext_KeySet(&keysets, &ks))
+ krb5_err(context, 1, ENOMEM, "out of memory");
+ match = 1;
+ }
+ if (match)
+ continue;
+
+ /* For all non-current keysets, repeat the above */
+ ext = hdb_find_extension(ep,
+ choice_HDB_extension_data_hist_keys);
+ if (!ext)
+ continue;
+ hist_keys = &ext->data.u.hist_keys;
+ for (p = 0; p < hist_keys->len; p++) {
+ for (m = 0; m < keysets.len; m++) {
+ if (keysets.val[m].kvno == hist_keys->val[p].kvno)
+ if (ep->keys.val[0].key.keytype !=
+ keysets.val[m].keys.val[0].key.keytype ||
+ ep->keys.val[0].key.keyvalue.length !=
+ keysets.val[m].keys.val[0].key.keyvalue.length ||
+ memcmp(ep->keys.val[0].key.keyvalue.data,
+ keysets.val[m].keys.val[0].key.keyvalue.data,
+ ep->keys.val[0].key.keyvalue.length) != 0)
+ krb5_errx(context, 1,
+ "key mismatch for same princ & kvno");
+ }
+ if (m == keysets.len) {
+ hdb_keyset ks;
+ ks.kvno = ep->kvno;
+ ks.keys = ep->keys;
+ ks.set_time = 0;
+ if (add_HDB_Ext_KeySet(&keysets, &ks))
+ krb5_err(context, 1, ENOMEM, "out of memory");
+ }
+ }
+ }
+ }
+ free_HDB_Ext_KeySet(&keysets);
+}
+
+static void
+print_em(krb5_context context)
+{
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension *ext;
+ size_t i, p;
+
+ for (i = 0; i < sizeof(e)/sizeof(e[0]); i++) {
+ const char *name = expected[i % (sizeof(expected)/sizeof(expected[0]))];
+ char *x;
+
+ if (0 == i % (sizeof(expected)/sizeof(expected[0])))
+ continue;
+ if (e[i].principal == NULL)
+ continue;
+ hex_encode(e[i].keys.val[0].key.keyvalue.data,
+ e[i].keys.val[0].key.keyvalue.length, &x);
+ printf("%s %u %s\n", x, e[i].kvno, name);
+ free(x);
+
+ ext = hdb_find_extension(&e[i], choice_HDB_extension_data_hist_keys);
+ if (!ext)
+ continue;
+ hist_keys = &ext->data.u.hist_keys;
+ for (p = 0; p < hist_keys->len; p++) {
+ hex_encode(hist_keys->val[p].keys.val[0].key.keyvalue.data,
+ hist_keys->val[p].keys.val[0].key.keyvalue.length, &x);
+ printf("%s %u %s\n", x, hist_keys->val[p].kvno, name);
+ free(x);
+ }
+ }
+}
+
+#if 0
+static void
+check_expected_kvnos(krb5_context context)
+{
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension *ext;
+ size_t i, k, m, p;
+
+ for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++) {
+ for (k = 0; k < sizeof(krs)/sizeof(krs[0]); k++) {
+ hdb_entry *ep = &e[k * sizeof(expected)/sizeof(expected[0]) + i];
+
+ if (ep->principal == NULL)
+ continue;
+ for (m = 0; m < NUM_OFFSETS; m++) {
+ ext = hdb_find_extension(ep,
+ choice_HDB_extension_data_hist_keys);
+ if (!ext)
+ continue;
+ hist_keys = &ext->data.u.hist_keys;
+ for (p = 0; p < hist_keys->len; p++) {
+ fprintf(stderr, "%s at %lu, %lu: history kvno %u\n",
+ expected[i], k, m, hist_keys->val[p].kvno);
+ }
+ }
+ fprintf(stderr, "%s at %lu: kvno %u\n", expected[i], k,
+ ep->kvno);
+ }
+ }
+}
+#endif
+
+#define SOME_TIME 1596318329
+#define SOME_BASE_KVNO 150
+#define SOME_EPOCH (SOME_TIME - (7 * 24 * 3600) - (SOME_TIME % (7 * 24 * 3600)))
+#define SOME_PERIOD 3600
+
+#define CONF \
+ "[hdb]\n" \
+ "\tenable_virtual_hostbased_princs = true\n" \
+ "\tvirtual_hostbased_princ_mindots = 1\n" \
+ "\tvirtual_hostbased_princ_maxdots = 3\n" \
+
+int
+main(int argc, char **argv)
+{
+ krb5_error_code ret;
+ krb5_context context;
+ size_t i;
+ HDB *db = NULL;
+
+ setprogname(argv[0]);
+ memset(e, 0, sizeof(e));
+ ret = krb5_init_context(&context);
+ if (ret == 0)
+ ret = krb5_set_config(context, CONF);
+ if (ret == 0)
+ ret = krb5_plugin_register(context, PLUGIN_TYPE_DATA, "hdb_test_interface",
+ &hdb_test);
+ if (ret == 0)
+ ret = hdb_create(context, &db, "test:mem");
+ if (ret)
+ krb5_err(context, 1, ret, "failed to setup HDB driver and test");
+
+ assert(db->enable_virtual_hostbased_princs);
+ assert(db->virtual_hostbased_princ_ndots == 1);
+ assert(db->virtual_hostbased_princ_maxdots == 3);
+
+ /* Setup key rotation metadata in a convenient way */
+ /*
+ * FIXME Reorder these two KRs to match how we store them to avoid
+ * confusion. #0 should be future-most, #1 should past-post.
+ */
+ krs[0].flags = krs[1].flags = int2KeyRotationFlags(0);
+ krs[0].epoch = SOME_EPOCH - 20 * 24 * 3600;
+ krs[0].period = SOME_PERIOD >> 1;
+ krs[0].base_kvno = 150;
+ krs[0].base_key_kvno = 1;
+ krs[1].epoch = SOME_TIME;
+ krs[1].period = SOME_PERIOD;
+ krs[1].base_kvno = krs[0].base_kvno + 1 + (krs[1].epoch + (krs[0].period - 1) - krs[0].epoch) / krs[0].period;
+ krs[1].base_key_kvno = 2;
+
+ {
+ HDB_Ext_KeyRotation existing_krs, new_krs;
+ KeyRotation ordered_krs[2];
+
+ ordered_krs[0] = krs[1];
+ ordered_krs[1] = krs[0];
+ existing_krs.len = 0;
+ existing_krs.val = 0;
+ new_krs.len = 1;
+ new_krs.val = &ordered_krs[1];
+ if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) ||
+ (ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)))
+ krb5_err(context, 1, ret, "Valid KeyRotation thought invalid");
+ new_krs.len = 1;
+ new_krs.val = &ordered_krs[0];
+ if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) ||
+ (ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)))
+ krb5_err(context, 1, ret, "Valid KeyRotation thought invalid");
+ new_krs.len = 2;
+ new_krs.val = &ordered_krs[0];
+ if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) ||
+ (ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)))
+ krb5_err(context, 1, ret, "Valid KeyRotation thought invalid");
+ existing_krs.len = 1;
+ existing_krs.val = &ordered_krs[1];
+ if ((ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)))
+ krb5_err(context, 1, ret, "Valid KeyRotation thought invalid");
+ existing_krs.len = 2;
+ existing_krs.val = &ordered_krs[0];
+ if ((ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)))
+ krb5_err(context, 1, ret, "Valid KeyRotation thought invalid");
+
+ new_krs.len = 2;
+ new_krs.val = &krs[0];
+ if ((ret = hdb_validate_key_rotations(context, &existing_krs,
+ &new_krs)) == 0)
+ krb5_errx(context, 1, "Invalid KeyRotation thought valid");
+ }
+
+ make_namespace(context, db, WK_PREFIX "_/bar.example@BAR.EXAMPLE");
+
+ fetch_entries(context, db, 1, 0, 0);
+ fetch_entries(context, db, 1, 1, 0);
+ fetch_entries(context, db, 1, 2, 0);
+ fetch_entries(context, db, 1, 3, 0);
+ fetch_entries(context, db, 1, 4, 0); /* Just before newest KR */
+
+ fetch_entries(context, db, 0, 0, 0);
+ fetch_entries(context, db, 0, 1, 0);
+ fetch_entries(context, db, 0, 2, 0);
+ fetch_entries(context, db, 0, 3, 0);
+ fetch_entries(context, db, 0, 4, 1); /* Must fail: just before 1st KR */
+
+ /*
+ * Check that for every virtual principal in `expected[]', all the keysets
+ * with the same kvno, in all the entries fetched for different times,
+ * match.
+ */
+ check_kvnos(context);
+
+#if 0
+ /*
+ * Check that for every virtual principal in `expected[]' we have the
+ * expected key history.
+ */
+ check_expected_kvnos(context);
+#endif
+
+ /*
+ * XXX Add various tests here, checking `e[]':
+ *
+ * - Extract all {principal, kvno, key} for all keys, current and
+ * otherwise, then sort by {key, kvno, principal}, then check that the
+ * only time we have matching keys is when the kvno and principal also
+ * match.
+ */
+
+ print_em(context);
+
+ /*
+ * XXX Test adding a third KR, a 4th KR, dropping KRs...
+ */
+
+ /* Cleanup */
+ for (i = 0; ret == 0 && i < sizeof(e) / sizeof(e[0]); i++)
+ hdb_free_entry(context, db, &e[i]);
+ db->hdb_destroy(context, db);
+ krb5_free_context(context);
+ return 0;
+}
diff --git a/lib/hdb/version-script.map b/lib/hdb/version-script.map
index 579a2efe7c41..058060dae0c1 100644
--- a/lib/hdb/version-script.map
+++ b/lib/hdb/version-script.map
@@ -2,9 +2,13 @@
HEIMDAL_HDB_1.0 {
global:
- encode_hdb_keyset;
- hdb_add_master_key;
+ _hdb_fetch_kvno;
+ _hdb_remove;
+ _hdb_store;
hdb_add_current_keys_to_history;
+ hdb_add_history_key;
+ hdb_add_history_keyset;
+ hdb_add_master_key;
hdb_change_kvno;
hdb_check_db_format;
hdb_clear_extension;
@@ -20,21 +24,27 @@ HEIMDAL_HDB_1.0 {
hdb_dbinfo_get_next;
hdb_dbinfo_get_realm;
hdb_default_db;
+ hdb_derive_etypes;
hdb_enctype2key;
hdb_entry2string;
hdb_entry2value;
+ hdb_entry_add_key_rotation;
hdb_entry_alias2value;
hdb_entry_check_mandatory;
hdb_entry_clear_password;
hdb_entry_get_ConstrainedDelegACL;
hdb_entry_get_aliases;
+ hdb_entry_get_key_rotation;
+ hdb_entry_get_krb5_config;
hdb_entry_get_password;
hdb_entry_get_pkinit_acl;
hdb_entry_get_pkinit_cert;
hdb_entry_get_pkinit_hash;
hdb_entry_get_pw_change_time;
+ hdb_entry_set_krb5_config;
hdb_entry_set_password;
hdb_entry_set_pw_change_time;
+ hdb_fetch_kvno;
hdb_find_extension;
hdb_foreach;
hdb_free_dbinfo;
@@ -46,7 +56,9 @@ HEIMDAL_HDB_1.0 {
hdb_generate_key_set_password;
hdb_generate_key_set_password_with_ks_tuple;
hdb_get_dbinfo;
+ hdb_get_instance;
hdb_init_db;
+ hdb_install_keyset;
hdb_key2principal;
hdb_kvno2keys;
hdb_list_builtin;
@@ -56,7 +68,9 @@ HEIMDAL_HDB_1.0 {
hdb_print_entry;
hdb_process_master_key;
hdb_prune_keys;
+ hdb_prune_keys_kvno;
hdb_read_master_key;
+ hdb_remove_keys;
hdb_replace_extension;
hdb_seal_key;
hdb_seal_key_mkey;
@@ -69,11 +83,15 @@ HEIMDAL_HDB_1.0 {
hdb_unseal_key;
hdb_unseal_key_mkey;
hdb_unseal_keys;
+ hdb_unseal_keys_kvno;
hdb_unseal_keys_mkey;
+ hdb_validate_key_rotation;
+ hdb_validate_key_rotations;
hdb_value2entry;
hdb_value2entry_alias;
hdb_write_master_key;
length_hdb_keyset;
+ length_HDB_keyset;
hdb_interface_version;
initialize_hdb_error_table_r;
@@ -85,44 +103,86 @@ HEIMDAL_HDB_1.0 {
hdb_get_kt_ops;
# some random bits needed for libkadm
+ add_HDB_Ext_KeyRotation;
+ add_HDB_Ext_KeySet;
add_HDB_Ext_KeySet;
add_Keys;
+ add_Keys;
asn1_HDBFlags_units;
copy_Event;
+ copy_HDB_EncTypeList;
+ copy_hdb_entry;
+ copy_hdb_entry_alias;
+ copy_HDB_entry;
+ copy_HDB_entry_alias;
+ copy_HDB_EntryOrAlias;
copy_HDB_extensions;
+ copy_HDB_Ext_KeyRotation;
copy_Key;
copy_Keys;
copy_Salt;
+ decode_HDB_EncTypeList;
+ decode_hdb_entry;
+ decode_hdb_entry_alias;
+ decode_HDB_entry;
+ decode_HDB_entry_alias;
+ decode_HDB_EntryOrAlias;
decode_HDB_Ext_Aliases;
decode_HDB_extension;
+ decode_HDB_Ext_KeyRotation;
decode_HDB_Ext_PKINIT_acl;
decode_Key;
decode_Keys;
+ encode_HDB_EncTypeList;
+ encode_hdb_entry;
+ encode_hdb_entry_alias;
+ encode_HDB_entry;
+ encode_HDB_entry_alias;
+ encode_HDB_EntryOrAlias;
encode_HDB_Ext_Aliases;
encode_HDB_extension;
+ encode_HDB_Ext_KeyRotation;
encode_HDB_Ext_PKINIT_acl;
+ encode_hdb_keyset;
+ encode_HDB_keyset;
encode_Key;
encode_Keys;
free_Event;
+ free_HDB_EncTypeList;
free_hdb_entry;
+ free_hdb_entry_alias;
+ free_HDB_entry;
+ free_HDB_entry_alias;
+ free_HDB_EntryOrAlias;
free_HDB_Ext_Aliases;
free_HDB_extension;
free_HDB_extensions;
+ free_HDB_Ext_KeyRotation;
+ free_HDB_Ext_KeySet;
free_HDB_Ext_PKINIT_acl;
free_hdb_keyset;
+ free_HDB_keyset;
free_Key;
free_Keys;
free_Salt;
HDBFlags2int;
int2HDBFlags;
+ int2KeyRotationFlags;
+ KeyRotationFlags2int;
+ length_HDB_EncTypeList;
+ length_hdb_entry;
+ length_hdb_entry_alias;
+ length_HDB_entry;
+ length_HDB_entry_alias;
+ length_HDB_EntryOrAlias;
length_HDB_Ext_Aliases;
length_HDB_extension;
+ length_HDB_Ext_KeyRotation;
length_HDB_Ext_PKINIT_acl;
length_Key;
length_Keys;
+ remove_HDB_Ext_KeyRotation;
remove_Keys;
- add_Keys;
- add_HDB_Ext_KeySet;
local:
*;