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