summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/kcm
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/kcm')
-rw-r--r--crypto/heimdal/kcm/Makefile.am44
-rw-r--r--crypto/heimdal/kcm/Makefile.in868
-rw-r--r--crypto/heimdal/kcm/acl.c180
-rw-r--r--crypto/heimdal/kcm/acquire.c531
-rw-r--r--crypto/heimdal/kcm/cache.c636
-rw-r--r--crypto/heimdal/kcm/client.c185
-rw-r--r--crypto/heimdal/kcm/config.c390
-rw-r--r--crypto/heimdal/kcm/connect.c688
-rw-r--r--crypto/heimdal/kcm/cursor.c151
-rw-r--r--crypto/heimdal/kcm/events.c440
-rw-r--r--crypto/heimdal/kcm/glue.c279
-rw-r--r--crypto/heimdal/kcm/headers.h89
-rw-r--r--crypto/heimdal/kcm/kcm.8224
-rw-r--r--crypto/heimdal/kcm/kcm_locl.h173
-rw-r--r--crypto/heimdal/kcm/kcm_protos.h288
-rw-r--r--crypto/heimdal/kcm/log.c85
-rw-r--r--crypto/heimdal/kcm/main.c107
-rw-r--r--crypto/heimdal/kcm/protocol.c1046
-rw-r--r--crypto/heimdal/kcm/renew.c124
19 files changed, 6528 insertions, 0 deletions
diff --git a/crypto/heimdal/kcm/Makefile.am b/crypto/heimdal/kcm/Makefile.am
new file mode 100644
index 0000000..baf89ac
--- /dev/null
+++ b/crypto/heimdal/kcm/Makefile.am
@@ -0,0 +1,44 @@
+# $Id: Makefile.am 20466 2007-04-20 08:29:05Z lha $
+
+include $(top_srcdir)/Makefile.am.common
+
+AM_CPPFLAGS += $(INCLUDE_krb4) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5
+
+libexec_PROGRAMS = kcm
+
+kcm_SOURCES = \
+ acl.c \
+ acquire.c \
+ cache.c \
+ client.c \
+ config.c \
+ connect.c \
+ cursor.c \
+ events.c \
+ glue.c \
+ headers.h \
+ kcm_locl.h \
+ kcm_protos.h \
+ log.c \
+ main.c \
+ protocol.c \
+ renew.c
+
+$(srcdir)/kcm_protos.h:
+ cd $(srcdir); perl ../cf/make-proto.pl -o kcm_protos.h -q -P comment $(kcm_SOURCES) || rm -f kcm_protos.h
+
+$(kcm_OBJECTS): $(srcdir)/kcm_protos.h
+
+man_MANS = kcm.8
+
+LDADD = $(top_builddir)/lib/hdb/libhdb.la \
+ $(LIB_openldap) \
+ $(top_builddir)/lib/krb5/libkrb5.la \
+ $(LIB_krb4) \
+ $(LIB_hcrypto) \
+ $(top_builddir)/lib/asn1/libasn1.la \
+ $(LIB_roken) \
+ $(LIB_door_create) \
+ $(LIB_pidfile)
+
+EXTRA_DIST = $(man_MANS)
diff --git a/crypto/heimdal/kcm/Makefile.in b/crypto/heimdal/kcm/Makefile.in
new file mode 100644
index 0000000..c3996df
--- /dev/null
+++ b/crypto/heimdal/kcm/Makefile.in
@@ -0,0 +1,868 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# $Id: Makefile.am 20466 2007-04-20 08:29:05Z lha $
+
+# $Id: Makefile.am.common 10998 2002-05-19 18:35:37Z joda $
+
+# $Id: Makefile.am.common 22488 2008-01-21 11:47:22Z lha $
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/Makefile.am.common \
+ $(top_srcdir)/cf/Makefile.am.common
+libexec_PROGRAMS = kcm$(EXEEXT)
+subdir = kcm
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/cf/aix.m4 \
+ $(top_srcdir)/cf/auth-modules.m4 $(top_srcdir)/cf/autobuild.m4 \
+ $(top_srcdir)/cf/broken-getaddrinfo.m4 \
+ $(top_srcdir)/cf/broken-glob.m4 \
+ $(top_srcdir)/cf/broken-realloc.m4 \
+ $(top_srcdir)/cf/broken-snprintf.m4 $(top_srcdir)/cf/broken.m4 \
+ $(top_srcdir)/cf/broken2.m4 $(top_srcdir)/cf/c-attribute.m4 \
+ $(top_srcdir)/cf/capabilities.m4 \
+ $(top_srcdir)/cf/check-compile-et.m4 \
+ $(top_srcdir)/cf/check-getpwnam_r-posix.m4 \
+ $(top_srcdir)/cf/check-man.m4 \
+ $(top_srcdir)/cf/check-netinet-ip-and-tcp.m4 \
+ $(top_srcdir)/cf/check-type-extra.m4 \
+ $(top_srcdir)/cf/check-var.m4 $(top_srcdir)/cf/check-x.m4 \
+ $(top_srcdir)/cf/check-xau.m4 $(top_srcdir)/cf/crypto.m4 \
+ $(top_srcdir)/cf/db.m4 $(top_srcdir)/cf/destdirs.m4 \
+ $(top_srcdir)/cf/dlopen.m4 \
+ $(top_srcdir)/cf/find-func-no-libs.m4 \
+ $(top_srcdir)/cf/find-func-no-libs2.m4 \
+ $(top_srcdir)/cf/find-func.m4 \
+ $(top_srcdir)/cf/find-if-not-broken.m4 \
+ $(top_srcdir)/cf/framework-security.m4 \
+ $(top_srcdir)/cf/have-struct-field.m4 \
+ $(top_srcdir)/cf/have-type.m4 $(top_srcdir)/cf/irix.m4 \
+ $(top_srcdir)/cf/krb-bigendian.m4 \
+ $(top_srcdir)/cf/krb-func-getlogin.m4 \
+ $(top_srcdir)/cf/krb-ipv6.m4 $(top_srcdir)/cf/krb-prog-ln-s.m4 \
+ $(top_srcdir)/cf/krb-readline.m4 \
+ $(top_srcdir)/cf/krb-struct-spwd.m4 \
+ $(top_srcdir)/cf/krb-struct-winsize.m4 \
+ $(top_srcdir)/cf/largefile.m4 $(top_srcdir)/cf/mips-abi.m4 \
+ $(top_srcdir)/cf/misc.m4 $(top_srcdir)/cf/need-proto.m4 \
+ $(top_srcdir)/cf/osfc2.m4 $(top_srcdir)/cf/otp.m4 \
+ $(top_srcdir)/cf/proto-compat.m4 $(top_srcdir)/cf/pthreads.m4 \
+ $(top_srcdir)/cf/resolv.m4 $(top_srcdir)/cf/retsigtype.m4 \
+ $(top_srcdir)/cf/roken-frag.m4 \
+ $(top_srcdir)/cf/socket-wrapper.m4 $(top_srcdir)/cf/sunos.m4 \
+ $(top_srcdir)/cf/telnet.m4 $(top_srcdir)/cf/test-package.m4 \
+ $(top_srcdir)/cf/version-script.m4 $(top_srcdir)/cf/wflags.m4 \
+ $(top_srcdir)/cf/win32.m4 $(top_srcdir)/cf/with-all.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/include/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(man8dir)"
+libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(libexec_PROGRAMS)
+am_kcm_OBJECTS = acl.$(OBJEXT) acquire.$(OBJEXT) cache.$(OBJEXT) \
+ client.$(OBJEXT) config.$(OBJEXT) connect.$(OBJEXT) \
+ cursor.$(OBJEXT) events.$(OBJEXT) glue.$(OBJEXT) log.$(OBJEXT) \
+ main.$(OBJEXT) protocol.$(OBJEXT) renew.$(OBJEXT)
+kcm_OBJECTS = $(am_kcm_OBJECTS)
+kcm_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+kcm_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \
+ $(am__DEPENDENCIES_1) $(top_builddir)/lib/krb5/libkrb5.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/lib/asn1/libasn1.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(top_builddir)/include@am__isrc@
+depcomp =
+am__depfiles_maybe =
+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)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(kcm_SOURCES)
+DIST_SOURCES = $(kcm_SOURCES)
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AIX_EXTRA_KAFS = @AIX_EXTRA_KAFS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CANONICAL_HOST = @CANONICAL_HOST@
+CATMAN = @CATMAN@
+CATMANEXT = @CATMANEXT@
+CC = @CC@
+CFLAGS = @CFLAGS@
+COMPILE_ET = @COMPILE_ET@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBLIB = @DBLIB@
+DEFS = @DEFS@
+DIR_com_err = @DIR_com_err@
+DIR_hcrypto = @DIR_hcrypto@
+DIR_hdbdir = @DIR_hdbdir@
+DIR_roken = @DIR_roken@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+GROFF = @GROFF@
+INCLUDES_roken = @INCLUDES_roken@
+INCLUDE_hcrypto = @INCLUDE_hcrypto@
+INCLUDE_hesiod = @INCLUDE_hesiod@
+INCLUDE_krb4 = @INCLUDE_krb4@
+INCLUDE_openldap = @INCLUDE_openldap@
+INCLUDE_readline = @INCLUDE_readline@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_VERSION_SCRIPT = @LDFLAGS_VERSION_SCRIPT@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBADD_roken = @LIBADD_roken@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_AUTH_SUBDIRS = @LIB_AUTH_SUBDIRS@
+LIB_NDBM = @LIB_NDBM@
+LIB_XauFileName = @LIB_XauFileName@
+LIB_XauReadAuth = @LIB_XauReadAuth@
+LIB_XauWriteAuth = @LIB_XauWriteAuth@
+LIB_bswap16 = @LIB_bswap16@
+LIB_bswap32 = @LIB_bswap32@
+LIB_com_err = @LIB_com_err@
+LIB_com_err_a = @LIB_com_err_a@
+LIB_com_err_so = @LIB_com_err_so@
+LIB_crypt = @LIB_crypt@
+LIB_db_create = @LIB_db_create@
+LIB_dbm_firstkey = @LIB_dbm_firstkey@
+LIB_dbopen = @LIB_dbopen@
+LIB_dlopen = @LIB_dlopen@
+LIB_dn_expand = @LIB_dn_expand@
+LIB_door_create = @LIB_door_create@
+LIB_el_init = @LIB_el_init@
+LIB_freeaddrinfo = @LIB_freeaddrinfo@
+LIB_gai_strerror = @LIB_gai_strerror@
+LIB_getaddrinfo = @LIB_getaddrinfo@
+LIB_gethostbyname = @LIB_gethostbyname@
+LIB_gethostbyname2 = @LIB_gethostbyname2@
+LIB_getnameinfo = @LIB_getnameinfo@
+LIB_getpwnam_r = @LIB_getpwnam_r@
+LIB_getsockopt = @LIB_getsockopt@
+LIB_hcrypto = @LIB_hcrypto@
+LIB_hcrypto_a = @LIB_hcrypto_a@
+LIB_hcrypto_appl = @LIB_hcrypto_appl@
+LIB_hcrypto_so = @LIB_hcrypto_so@
+LIB_hesiod = @LIB_hesiod@
+LIB_hstrerror = @LIB_hstrerror@
+LIB_kdb = @LIB_kdb@
+LIB_krb4 = @LIB_krb4@
+LIB_loadquery = @LIB_loadquery@
+LIB_logout = @LIB_logout@
+LIB_logwtmp = @LIB_logwtmp@
+LIB_openldap = @LIB_openldap@
+LIB_openpty = @LIB_openpty@
+LIB_otp = @LIB_otp@
+LIB_pidfile = @LIB_pidfile@
+LIB_readline = @LIB_readline@
+LIB_res_ndestroy = @LIB_res_ndestroy@
+LIB_res_nsearch = @LIB_res_nsearch@
+LIB_res_search = @LIB_res_search@
+LIB_roken = @LIB_roken@
+LIB_security = @LIB_security@
+LIB_setsockopt = @LIB_setsockopt@
+LIB_socket = @LIB_socket@
+LIB_syslog = @LIB_syslog@
+LIB_tgetent = @LIB_tgetent@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NROFF = @NROFF@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREADS_CFLAGS = @PTHREADS_CFLAGS@
+PTHREADS_LIBS = @PTHREADS_LIBS@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VERSIONING = @VERSIONING@
+VOID_RETSIGTYPE = @VOID_RETSIGTYPE@
+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@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dpagaix_cflags = @dpagaix_cflags@
+dpagaix_ldadd = @dpagaix_ldadd@
+dpagaix_ldflags = @dpagaix_ldflags@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUFFIXES = .et .h .x .z .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8
+AM_CPPFLAGS = -I$(top_builddir)/include $(INCLUDES_roken) \
+ $(INCLUDE_krb4) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5
+@do_roken_rename_TRUE@ROKEN_RENAME = -DROKEN_RENAME
+AM_CFLAGS = $(WFLAGS)
+CP = cp
+buildinclude = $(top_builddir)/include
+LIB_getattr = @LIB_getattr@
+LIB_getpwent_r = @LIB_getpwent_r@
+LIB_odm_initialize = @LIB_odm_initialize@
+LIB_setpcred = @LIB_setpcred@
+HESIODLIB = @HESIODLIB@
+HESIODINCLUDE = @HESIODINCLUDE@
+NROFF_MAN = groff -mandoc -Tascii
+LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_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
+@KRB5_TRUE@LIB_tsasl = $(top_builddir)/lib/tsasl/libtsasl.la
+@DCE_TRUE@LIB_kdfs = $(top_builddir)/lib/kdfs/libkdfs.la
+kcm_SOURCES = \
+ acl.c \
+ acquire.c \
+ cache.c \
+ client.c \
+ config.c \
+ connect.c \
+ cursor.c \
+ events.c \
+ glue.c \
+ headers.h \
+ kcm_locl.h \
+ kcm_protos.h \
+ log.c \
+ main.c \
+ protocol.c \
+ renew.c
+
+man_MANS = kcm.8
+LDADD = $(top_builddir)/lib/hdb/libhdb.la \
+ $(LIB_openldap) \
+ $(top_builddir)/lib/krb5/libkrb5.la \
+ $(LIB_krb4) \
+ $(LIB_hcrypto) \
+ $(top_builddir)/lib/asn1/libasn1.la \
+ $(LIB_roken) \
+ $(LIB_door_create) \
+ $(LIB_pidfile)
+
+EXTRA_DIST = $(man_MANS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .et .h .x .z .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.am.common $(top_srcdir)/cf/Makefile.am.common $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps kcm/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign --ignore-deps kcm/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)"
+ @list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(libexecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(libexecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(libexecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(libexecdir)/$$f"; \
+ done
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+kcm$(EXEEXT): $(kcm_OBJECTS) $(kcm_DEPENDENCIES)
+ @rm -f kcm$(EXEEXT)
+ $(LINK) $(kcm_OBJECTS) $(kcm_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+.c.o:
+ $(COMPILE) -c $<
+
+.c.obj:
+ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+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; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ 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; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ 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; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS) all-local
+installdirs:
+ for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(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
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-libexecPROGRAMS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man8
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libexecPROGRAMS uninstall-man
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-hook
+
+uninstall-man: uninstall-man8
+
+.MAKE: 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-libexecPROGRAMS clean-libtool 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-info install-info-am \
+ install-libexecPROGRAMS install-man install-man8 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 \
+ uninstall-libexecPROGRAMS uninstall-man uninstall-man8
+
+
+install-suid-programs:
+ @foo='$(bin_SUIDS)'; \
+ for file in $$foo; do \
+ x=$(DESTDIR)$(bindir)/$$file; \
+ if chown 0:0 $$x && chmod u+s $$x; then :; else \
+ echo "*"; \
+ echo "* Failed to install $$x setuid root"; \
+ echo "*"; \
+ fi; done
+
+install-exec-hook: install-suid-programs
+
+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)'; \
+ for f in $$foo; do \
+ f=`basename $$f`; \
+ if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \
+ else file="$$f"; fi; \
+ if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \
+ : ; else \
+ echo " $(CP) $$file $(buildinclude)/$$f"; \
+ $(CP) $$file $(buildinclude)/$$f; \
+ fi ; \
+ done ; \
+ foo='$(nobase_include_HEADERS)'; \
+ for f in $$foo; do \
+ if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \
+ else file="$$f"; fi; \
+ $(mkdir_p) $(buildinclude)/`dirname $$f` ; \
+ if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \
+ : ; else \
+ echo " $(CP) $$file $(buildinclude)/$$f"; \
+ $(CP) $$file $(buildinclude)/$$f; \
+ fi ; \
+ done
+
+all-local: install-build-headers
+
+check-local::
+ @if test '$(CHECK_LOCAL)' = "no-check-local"; then \
+ foo=''; elif test '$(CHECK_LOCAL)'; then \
+ foo='$(CHECK_LOCAL)'; else \
+ foo='$(PROGRAMS)'; fi; \
+ if test "$$foo"; then \
+ failed=0; all=0; \
+ for i in $$foo; do \
+ all=`expr $$all + 1`; \
+ if (./$$i --version && ./$$i --help) > /dev/null 2>&1; then \
+ echo "PASS: $$i"; \
+ else \
+ echo "FAIL: $$i"; \
+ failed=`expr $$failed + 1`; \
+ fi; \
+ done; \
+ if test "$$failed" -eq 0; then \
+ banner="All $$all tests passed"; \
+ else \
+ banner="$$failed of $$all tests failed"; \
+ fi; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"; \
+ test "$$failed" -eq 0 || exit 1; \
+ fi
+
+.x.c:
+ @cmp -s $< $@ 2> /dev/null || cp $< $@
+#NROFF_MAN = nroff -man
+.1.cat1:
+ $(NROFF_MAN) $< > $@
+.3.cat3:
+ $(NROFF_MAN) $< > $@
+.5.cat5:
+ $(NROFF_MAN) $< > $@
+.8.cat8:
+ $(NROFF_MAN) $< > $@
+
+dist-cat1-mans:
+ @foo='$(man1_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.1) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat1/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat3-mans:
+ @foo='$(man3_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.3) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat3/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat5-mans:
+ @foo='$(man5_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.5) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat5/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat8-mans:
+ @foo='$(man8_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.8) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat8/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-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)
+
+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)
+
+install-data-hook: install-cat-mans
+uninstall-hook: uninstall-cat-mans
+
+.et.h:
+ $(COMPILE_ET) $<
+.et.c:
+ $(COMPILE_ET) $<
+
+#
+# Useful target for debugging
+#
+
+check-valgrind:
+ tobjdir=`cd $(top_builddir) && pwd` ; \
+ tsrcdir=`cd $(top_srcdir) && pwd` ; \
+ env TESTS_ENVIRONMENT="$${tobjdir}/libtool --mode execute valgrind --leak-check=full --trace-children=yes --quiet -q --num-callers=30 --suppressions=$${tsrcdir}/cf/valgrind-suppressions" make check
+
+#
+# Target to please samba build farm, builds distfiles in-tree.
+# Will break when automake changes...
+#
+
+distdir-in-tree: $(DISTFILES) $(INFO_DEPS)
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" != .; then \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) distdir-in-tree) ; \
+ fi ; \
+ done
+
+$(srcdir)/kcm_protos.h:
+ cd $(srcdir); perl ../cf/make-proto.pl -o kcm_protos.h -q -P comment $(kcm_SOURCES) || rm -f kcm_protos.h
+
+$(kcm_OBJECTS): $(srcdir)/kcm_protos.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/crypto/heimdal/kcm/acl.c b/crypto/heimdal/kcm/acl.c
new file mode 100644
index 0000000..1b96204
--- /dev/null
+++ b/crypto/heimdal/kcm/acl.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: acl.c 20472 2007-04-20 10:43:25Z lha $");
+
+krb5_error_code
+kcm_access(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ kcm_ccache ccache)
+{
+ int read_p = 0;
+ int write_p = 0;
+ uint16_t mask;
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ switch (opcode) {
+ case KCM_OP_INITIALIZE:
+ case KCM_OP_DESTROY:
+ case KCM_OP_STORE:
+ case KCM_OP_REMOVE_CRED:
+ case KCM_OP_SET_FLAGS:
+ case KCM_OP_CHOWN:
+ case KCM_OP_CHMOD:
+ case KCM_OP_GET_INITIAL_TICKET:
+ case KCM_OP_GET_TICKET:
+ write_p = 1;
+ read_p = 0;
+ break;
+ case KCM_OP_NOOP:
+ case KCM_OP_GET_NAME:
+ case KCM_OP_RESOLVE:
+ case KCM_OP_GEN_NEW:
+ case KCM_OP_RETRIEVE:
+ case KCM_OP_GET_PRINCIPAL:
+ case KCM_OP_GET_FIRST:
+ case KCM_OP_GET_NEXT:
+ case KCM_OP_END_GET:
+ case KCM_OP_MAX:
+ write_p = 0;
+ read_p = 1;
+ break;
+ }
+
+ if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM) {
+ /* System caches cannot be reinitialized or destroyed by users */
+ if (opcode == KCM_OP_INITIALIZE ||
+ opcode == KCM_OP_DESTROY ||
+ opcode == KCM_OP_REMOVE_CRED) {
+ ret = KRB5_FCC_PERM;
+ goto out;
+ }
+
+ /* Let root always read system caches */
+ if (client->uid == 0) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ mask = 0;
+
+ /* Root may do whatever they like */
+ if (client->uid == ccache->uid || CLIENT_IS_ROOT(client)) {
+ if (read_p)
+ mask |= S_IRUSR;
+ if (write_p)
+ mask |= S_IWUSR;
+ } else if (client->gid == ccache->gid || CLIENT_IS_ROOT(client)) {
+ if (read_p)
+ mask |= S_IRGRP;
+ if (write_p)
+ mask |= S_IWGRP;
+ } else {
+ if (read_p)
+ mask |= S_IROTH;
+ if (write_p)
+ mask |= S_IWOTH;
+ }
+
+ ret = ((ccache->mode & mask) == mask) ? 0 : KRB5_FCC_PERM;
+
+out:
+ if (ret) {
+ kcm_log(2, "Process %d is not permitted to call %s on cache %s",
+ client->pid, kcm_op2string(opcode), ccache->name);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_chmod(krb5_context context,
+ kcm_client *client,
+ kcm_ccache ccache,
+ uint16_t mode)
+{
+ KCM_ASSERT_VALID(ccache);
+
+ /* System cache mode can only be set at startup */
+ if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM)
+ return KRB5_FCC_PERM;
+
+ if (ccache->uid != client->uid)
+ return KRB5_FCC_PERM;
+
+ if (ccache->gid != client->gid)
+ return KRB5_FCC_PERM;
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ ccache->mode = mode;
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return 0;
+}
+
+krb5_error_code
+kcm_chown(krb5_context context,
+ kcm_client *client,
+ kcm_ccache ccache,
+ uid_t uid,
+ gid_t gid)
+{
+ KCM_ASSERT_VALID(ccache);
+
+ /* System cache owner can only be set at startup */
+ if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM)
+ return KRB5_FCC_PERM;
+
+ if (ccache->uid != client->uid)
+ return KRB5_FCC_PERM;
+
+ if (ccache->gid != client->gid)
+ return KRB5_FCC_PERM;
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ ccache->uid = uid;
+ ccache->gid = gid;
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return 0;
+}
+
diff --git a/crypto/heimdal/kcm/acquire.c b/crypto/heimdal/kcm/acquire.c
new file mode 100644
index 0000000..416881a
--- /dev/null
+++ b/crypto/heimdal/kcm/acquire.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: acquire.c 22118 2007-12-03 21:44:00Z lha $");
+
+static krb5_error_code
+change_pw_and_update_keytab(krb5_context context, kcm_ccache ccache);
+
+/*
+ * Get a new ticket using a keytab/cached key and swap it into
+ * an existing redentials cache
+ */
+
+krb5_error_code
+kcm_ccache_acquire(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds **credp)
+{
+ krb5_error_code ret = 0;
+ krb5_creds cred;
+ krb5_const_realm realm;
+ krb5_get_init_creds_opt opt;
+ krb5_ccache_data ccdata;
+ char *in_tkt_service = NULL;
+ int done = 0;
+
+ memset(&cred, 0, sizeof(cred));
+
+ KCM_ASSERT_VALID(ccache);
+
+ /* We need a cached key or keytab to acquire credentials */
+ if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
+ if (ccache->key.keyblock.keyvalue.length == 0)
+ krb5_abortx(context,
+ "kcm_ccache_acquire: KCM_FLAGS_USE_CACHED_KEY without key");
+ } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) {
+ if (ccache->key.keytab == NULL)
+ krb5_abortx(context,
+ "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab");
+ } else {
+ kcm_log(0, "Cannot acquire initial credentials for cache %s without key",
+ ccache->name);
+ return KRB5_FCC_INTERNAL;
+ }
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ /* Fake up an internal ccache */
+ kcm_internal_ccache(context, ccache, &ccdata);
+
+ /* Now, actually acquire the creds */
+ if (ccache->server != NULL) {
+ ret = krb5_unparse_name(context, ccache->server, &in_tkt_service);
+ if (ret) {
+ kcm_log(0, "Failed to unparse service principal name for cache %s: %s",
+ ccache->name, krb5_get_err_text(context, ret));
+ return ret;
+ }
+ }
+
+ realm = krb5_principal_get_realm(context, ccache->client);
+
+ krb5_get_init_creds_opt_init(&opt);
+ krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, &opt);
+ if (ccache->tkt_life != 0)
+ krb5_get_init_creds_opt_set_tkt_life(&opt, ccache->tkt_life);
+ if (ccache->renew_life != 0)
+ krb5_get_init_creds_opt_set_renew_life(&opt, ccache->renew_life);
+
+ if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) {
+ ret = krb5_get_init_creds_keyblock(context,
+ &cred,
+ ccache->client,
+ &ccache->key.keyblock,
+ 0,
+ in_tkt_service,
+ &opt);
+ } else {
+ /* loosely based on lib/krb5/init_creds_pw.c */
+ while (!done) {
+ ret = krb5_get_init_creds_keytab(context,
+ &cred,
+ ccache->client,
+ ccache->key.keytab,
+ 0,
+ in_tkt_service,
+ &opt);
+ switch (ret) {
+ case KRB5KDC_ERR_KEY_EXPIRED:
+ if (in_tkt_service != NULL &&
+ strcmp(in_tkt_service, "kadmin/changepw") == 0) {
+ goto out;
+ }
+
+ ret = change_pw_and_update_keytab(context, ccache);
+ if (ret)
+ goto out;
+ break;
+ case 0:
+ default:
+ done = 1;
+ break;
+ }
+ }
+ }
+
+ if (ret) {
+ kcm_log(0, "Failed to acquire credentials for cache %s: %s",
+ ccache->name, krb5_get_err_text(context, ret));
+ if (in_tkt_service != NULL)
+ free(in_tkt_service);
+ goto out;
+ }
+
+ if (in_tkt_service != NULL)
+ free(in_tkt_service);
+
+ /* Swap them in */
+ kcm_ccache_remove_creds_internal(context, ccache);
+
+ ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp);
+ if (ret) {
+ kcm_log(0, "Failed to store credentials for cache %s: %s",
+ ccache->name, krb5_get_err_text(context, ret));
+ krb5_free_cred_contents(context, &cred);
+ goto out;
+ }
+
+out:
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+static krb5_error_code
+change_pw(krb5_context context,
+ kcm_ccache ccache,
+ char *cpn,
+ char *newpw)
+{
+ krb5_error_code ret;
+ krb5_creds cpw_cred;
+ int result_code;
+ krb5_data result_code_string;
+ krb5_data result_string;
+ krb5_get_init_creds_opt options;
+
+ memset(&cpw_cred, 0, sizeof(cpw_cred));
+
+ krb5_get_init_creds_opt_init(&options);
+ krb5_get_init_creds_opt_set_tkt_life(&options, 60);
+ krb5_get_init_creds_opt_set_forwardable(&options, FALSE);
+ krb5_get_init_creds_opt_set_proxiable(&options, FALSE);
+
+ krb5_data_zero(&result_code_string);
+ krb5_data_zero(&result_string);
+
+ ret = krb5_get_init_creds_keytab(context,
+ &cpw_cred,
+ ccache->client,
+ ccache->key.keytab,
+ 0,
+ "kadmin/changepw",
+ &options);
+ if (ret) {
+ kcm_log(0, "Failed to acquire password change credentials "
+ "for principal %s: %s",
+ cpn, krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ ret = krb5_set_password(context,
+ &cpw_cred,
+ newpw,
+ ccache->client,
+ &result_code,
+ &result_code_string,
+ &result_string);
+ if (ret) {
+ kcm_log(0, "Failed to change password for principal %s: %s",
+ cpn, krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ if (result_code) {
+ kcm_log(0, "Failed to change password for principal %s: %.*s",
+ cpn,
+ (int)result_string.length,
+ result_string.length > 0 ? (char *)result_string.data : "");
+ goto out;
+ }
+
+out:
+ krb5_data_free(&result_string);
+ krb5_data_free(&result_code_string);
+ krb5_free_cred_contents(context, &cpw_cred);
+
+ return ret;
+}
+
+struct kcm_keyseed_data {
+ krb5_salt salt;
+ const char *password;
+};
+
+static krb5_error_code
+kcm_password_key_proc(krb5_context context,
+ krb5_enctype etype,
+ krb5_salt salt,
+ krb5_const_pointer keyseed,
+ krb5_keyblock **key)
+{
+ krb5_error_code ret;
+ struct kcm_keyseed_data *s = (struct kcm_keyseed_data *)keyseed;
+
+ /* we may be called multiple times */
+ krb5_free_salt(context, s->salt);
+ krb5_data_zero(&s->salt.saltvalue);
+
+ /* stash the salt */
+ s->salt.salttype = salt.salttype;
+
+ ret = krb5_data_copy(&s->salt.saltvalue,
+ salt.saltvalue.data,
+ salt.saltvalue.length);
+ if (ret)
+ return ret;
+
+ *key = (krb5_keyblock *)malloc(sizeof(**key));
+ if (*key == NULL) {
+ return ENOMEM;
+ }
+
+ ret = krb5_string_to_key_salt(context, etype, s->password,
+ s->salt, *key);
+ if (ret) {
+ free(*key);
+ *key = NULL;
+ }
+
+ return ret;
+}
+
+static krb5_error_code
+get_salt_and_kvno(krb5_context context,
+ kcm_ccache ccache,
+ krb5_enctype *etypes,
+ char *cpn,
+ char *newpw,
+ krb5_salt *salt,
+ unsigned *kvno)
+{
+ krb5_error_code ret;
+ krb5_creds creds;
+ krb5_ccache_data ccdata;
+ krb5_flags options = 0;
+ krb5_kdc_rep reply;
+ struct kcm_keyseed_data s;
+
+ memset(&creds, 0, sizeof(creds));
+ memset(&reply, 0, sizeof(reply));
+
+ s.password = NULL;
+ s.salt.salttype = (int)ETYPE_NULL;
+ krb5_data_zero(&s.salt.saltvalue);
+
+ *kvno = 0;
+ kcm_internal_ccache(context, ccache, &ccdata);
+ s.password = newpw;
+
+ /* Do an AS-REQ to determine salt and key version number */
+ ret = krb5_copy_principal(context, ccache->client, &creds.client);
+ if (ret)
+ return ret;
+
+ /* Yes, get a ticket to ourselves */
+ ret = krb5_copy_principal(context, ccache->client, &creds.server);
+ if (ret) {
+ krb5_free_principal(context, creds.client);
+ return ret;
+ }
+
+ ret = krb5_get_in_tkt(context,
+ options,
+ NULL,
+ etypes,
+ NULL,
+ kcm_password_key_proc,
+ &s,
+ NULL,
+ NULL,
+ &creds,
+ &ccdata,
+ &reply);
+ if (ret) {
+ kcm_log(0, "Failed to get self ticket for principal %s: %s",
+ cpn, krb5_get_err_text(context, ret));
+ krb5_free_salt(context, s.salt);
+ } else {
+ *salt = s.salt; /* retrieve stashed salt */
+ if (reply.kdc_rep.enc_part.kvno != NULL)
+ *kvno = *(reply.kdc_rep.enc_part.kvno);
+ }
+ /* ccache may have been modified but it will get trashed anyway */
+
+ krb5_free_cred_contents(context, &creds);
+ krb5_free_kdc_rep(context, &reply);
+
+ return ret;
+}
+
+static krb5_error_code
+update_keytab_entry(krb5_context context,
+ kcm_ccache ccache,
+ krb5_enctype etype,
+ char *cpn,
+ char *spn,
+ char *newpw,
+ krb5_salt salt,
+ unsigned kvno)
+{
+ krb5_error_code ret;
+ krb5_keytab_entry entry;
+ krb5_data pw;
+
+ memset(&entry, 0, sizeof(entry));
+
+ pw.data = (char *)newpw;
+ pw.length = strlen(newpw);
+
+ ret = krb5_string_to_key_data_salt(context, etype, pw,
+ salt, &entry.keyblock);
+ if (ret) {
+ kcm_log(0, "String to key conversion failed for principal %s "
+ "and etype %d: %s",
+ cpn, etype, krb5_get_err_text(context, ret));
+ return ret;
+ }
+
+ if (spn == NULL) {
+ ret = krb5_copy_principal(context, ccache->client,
+ &entry.principal);
+ if (ret) {
+ kcm_log(0, "Failed to copy principal name %s: %s",
+ cpn, krb5_get_err_text(context, ret));
+ return ret;
+ }
+ } else {
+ ret = krb5_parse_name(context, spn, &entry.principal);
+ if (ret) {
+ kcm_log(0, "Failed to parse SPN alias %s: %s",
+ spn, krb5_get_err_text(context, ret));
+ return ret;
+ }
+ }
+
+ entry.vno = kvno;
+ entry.timestamp = time(NULL);
+
+ ret = krb5_kt_add_entry(context, ccache->key.keytab, &entry);
+ if (ret) {
+ kcm_log(0, "Failed to update keytab for principal %s "
+ "and etype %d: %s",
+ cpn, etype, krb5_get_err_text(context, ret));
+ }
+
+ krb5_kt_free_entry(context, &entry);
+
+ return ret;
+}
+
+static krb5_error_code
+update_keytab_entries(krb5_context context,
+ kcm_ccache ccache,
+ krb5_enctype *etypes,
+ char *cpn,
+ char *spn,
+ char *newpw,
+ krb5_salt salt,
+ unsigned kvno)
+{
+ krb5_error_code ret = 0;
+ int i;
+
+ for (i = 0; etypes[i] != ETYPE_NULL; i++) {
+ ret = update_keytab_entry(context, ccache, etypes[i],
+ cpn, spn, newpw, salt, kvno);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static void
+generate_random_pw(krb5_context context,
+ char *buf,
+ size_t bufsiz)
+{
+ unsigned char x[512], *p;
+ size_t i;
+
+ memset(x, 0, sizeof(x));
+ krb5_generate_random_block(x, sizeof(x));
+ p = x;
+
+ for (i = 0; i < bufsiz; i++) {
+ while (isprint(*p) == 0)
+ p++;
+
+ if (p - x >= sizeof(x)) {
+ krb5_generate_random_block(x, sizeof(x));
+ p = x;
+ }
+ buf[i] = (char)*p++;
+ }
+ buf[bufsiz - 1] = '\0';
+ memset(x, 0, sizeof(x));
+}
+
+static krb5_error_code
+change_pw_and_update_keytab(krb5_context context,
+ kcm_ccache ccache)
+{
+ char newpw[121];
+ krb5_error_code ret;
+ unsigned kvno;
+ krb5_salt salt;
+ krb5_enctype *etypes = NULL;
+ int i;
+ char *cpn = NULL;
+ char **spns = NULL;
+
+ krb5_data_zero(&salt.saltvalue);
+
+ ret = krb5_unparse_name(context, ccache->client, &cpn);
+ if (ret) {
+ kcm_log(0, "Failed to unparse name: %s",
+ krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ ret = krb5_get_default_in_tkt_etypes(context, &etypes);
+ if (ret) {
+ kcm_log(0, "Failed to determine default encryption types: %s",
+ krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ /* Generate a random password (there is no set keys protocol) */
+ generate_random_pw(context, newpw, sizeof(newpw));
+
+ /* Change it */
+ ret = change_pw(context, ccache, cpn, newpw);
+ if (ret)
+ goto out;
+
+ /* Do an AS-REQ to determine salt and key version number */
+ ret = get_salt_and_kvno(context, ccache, etypes, cpn, newpw,
+ &salt, &kvno);
+ if (ret) {
+ kcm_log(0, "Failed to determine salting principal for principal %s: %s",
+ cpn, krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ /* Add canonical name */
+ ret = update_keytab_entries(context, ccache, etypes, cpn,
+ NULL, newpw, salt, kvno);
+ if (ret)
+ goto out;
+
+ /* Add SPN aliases, if any */
+ spns = krb5_config_get_strings(context, NULL, "kcm",
+ "system_ccache", "spn_aliases", NULL);
+ if (spns != NULL) {
+ for (i = 0; spns[i] != NULL; i++) {
+ ret = update_keytab_entries(context, ccache, etypes, cpn,
+ spns[i], newpw, salt, kvno);
+ if (ret)
+ goto out;
+ }
+ }
+
+ kcm_log(0, "Changed expired password for principal %s in cache %s",
+ cpn, ccache->name);
+
+out:
+ if (cpn != NULL)
+ free(cpn);
+ if (spns != NULL)
+ krb5_config_free_strings(spns);
+ if (etypes != NULL)
+ free(etypes);
+ krb5_free_salt(context, salt);
+ memset(newpw, 0, sizeof(newpw));
+
+ return ret;
+}
+
diff --git a/crypto/heimdal/kcm/cache.c b/crypto/heimdal/kcm/cache.c
new file mode 100644
index 0000000..aeb30cc
--- /dev/null
+++ b/crypto/heimdal/kcm/cache.c
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: cache.c 14566 2005-02-06 01:22:49Z lukeh $");
+
+static HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static kcm_ccache_data *ccache_head = NULL;
+static unsigned int ccache_nextid = 0;
+
+char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
+{
+ unsigned n;
+ char *name;
+
+ HEIMDAL_MUTEX_lock(&ccache_mutex);
+ n = ++ccache_nextid;
+ HEIMDAL_MUTEX_unlock(&ccache_mutex);
+
+ asprintf(&name, "%d:%u", uid, n);
+
+ return name;
+}
+
+static krb5_error_code
+kcm_ccache_resolve_internal(krb5_context context,
+ const char *name,
+ kcm_ccache *ccache)
+{
+ kcm_ccache p;
+ krb5_error_code ret;
+
+ *ccache = NULL;
+
+ ret = KRB5_FCC_NOFILE;
+
+ HEIMDAL_MUTEX_lock(&ccache_mutex);
+
+ for (p = ccache_head; p != NULL; p = p->next) {
+ if ((p->flags & KCM_FLAGS_VALID) == 0)
+ continue;
+ if (strcmp(p->name, name) == 0) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ kcm_retain_ccache(context, p);
+ *ccache = p;
+ }
+
+ HEIMDAL_MUTEX_unlock(&ccache_mutex);
+
+ return ret;
+}
+
+krb5_error_code kcm_debug_ccache(krb5_context context)
+{
+ kcm_ccache p;
+
+ for (p = ccache_head; p != NULL; p = p->next) {
+ char *cpn = NULL, *spn = NULL;
+ int ncreds = 0;
+ struct kcm_creds *k;
+
+ if ((p->flags & KCM_FLAGS_VALID) == 0) {
+ kcm_log(7, "cache %08x: empty slot");
+ continue;
+ }
+
+ KCM_ASSERT_VALID(p);
+
+ for (k = p->creds; k != NULL; k = k->next)
+ ncreds++;
+
+ if (p->client != NULL)
+ krb5_unparse_name(context, p->client, &cpn);
+ if (p->server != NULL)
+ krb5_unparse_name(context, p->server, &spn);
+
+ kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o "
+ "uid %d gid %d client %s server %s ncreds %d",
+ p, p->name, p->refcnt, p->flags, p->mode, p->uid, p->gid,
+ (cpn == NULL) ? "<none>" : cpn,
+ (spn == NULL) ? "<none>" : spn,
+ ncreds);
+
+ if (cpn != NULL)
+ free(cpn);
+ if (spn != NULL)
+ free(spn);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+kcm_ccache_destroy_internal(krb5_context context, const char *name)
+{
+ kcm_ccache *p;
+ krb5_error_code ret;
+
+ ret = KRB5_FCC_NOFILE;
+
+ HEIMDAL_MUTEX_lock(&ccache_mutex);
+ for (p = &ccache_head; *p != NULL; p = &(*p)->next) {
+ if (((*p)->flags & KCM_FLAGS_VALID) == 0)
+ continue;
+ if (strcmp((*p)->name, name) == 0) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret)
+ goto out;
+
+ kcm_release_ccache(context, p);
+
+out:
+ HEIMDAL_MUTEX_unlock(&ccache_mutex);
+
+ return ret;
+}
+
+static krb5_error_code
+kcm_ccache_alloc(krb5_context context,
+ const char *name,
+ kcm_ccache *ccache)
+{
+ kcm_ccache slot = NULL, p;
+ krb5_error_code ret;
+ int new_slot = 0;
+
+ *ccache = NULL;
+
+ /* First, check for duplicates */
+ HEIMDAL_MUTEX_lock(&ccache_mutex);
+ ret = 0;
+ for (p = ccache_head; p != NULL; p = p->next) {
+ if (p->flags & KCM_FLAGS_VALID) {
+ if (strcmp(p->name, name) == 0) {
+ ret = KRB5_CC_WRITE;
+ break;
+ }
+ } else if (slot == NULL)
+ slot = p;
+ }
+
+ if (ret)
+ goto out;
+
+ /*
+ * Then try and find an empty slot
+ * XXX we need to recycle slots for this to actually do anything
+ */
+ if (slot == NULL) {
+ for (; p != NULL; p = p->next) {
+ if ((p->flags & KCM_FLAGS_VALID) == 0) {
+ slot = p;
+ break;
+ }
+ }
+
+ if (slot == NULL) {
+ slot = (kcm_ccache_data *)malloc(sizeof(*slot));
+ if (slot == NULL) {
+ ret = KRB5_CC_NOMEM;
+ goto out;
+ }
+ slot->next = ccache_head;
+ HEIMDAL_MUTEX_init(&slot->mutex);
+ new_slot = 1;
+ }
+ }
+
+ slot->name = strdup(name);
+ if (slot->name == NULL) {
+ ret = KRB5_CC_NOMEM;
+ goto out;
+ }
+
+ slot->refcnt = 1;
+ slot->flags = KCM_FLAGS_VALID;
+ slot->mode = S_IRUSR | S_IWUSR;
+ slot->uid = -1;
+ slot->gid = -1;
+ slot->client = NULL;
+ slot->server = NULL;
+ slot->creds = NULL;
+ slot->n_cursor = 0;
+ slot->cursors = NULL;
+ slot->key.keytab = NULL;
+ slot->tkt_life = 0;
+ slot->renew_life = 0;
+
+ if (new_slot)
+ ccache_head = slot;
+
+ *ccache = slot;
+
+ HEIMDAL_MUTEX_unlock(&ccache_mutex);
+ return 0;
+
+out:
+ HEIMDAL_MUTEX_unlock(&ccache_mutex);
+ if (new_slot && slot != NULL) {
+ HEIMDAL_MUTEX_destroy(&slot->mutex);
+ free(slot);
+ }
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_remove_creds_internal(krb5_context context,
+ kcm_ccache ccache)
+{
+ struct kcm_creds *k;
+ struct kcm_cursor *c;
+
+ k = ccache->creds;
+ while (k != NULL) {
+ struct kcm_creds *old;
+
+ krb5_free_cred_contents(context, &k->cred);
+ old = k;
+ k = k->next;
+ free(old);
+ }
+ ccache->creds = NULL;
+
+ /* remove anything that would have pointed into the creds too */
+
+ ccache->n_cursor = 0;
+
+ c = ccache->cursors;
+ while (c != NULL) {
+ struct kcm_cursor *old;
+
+ old = c;
+ c = c->next;
+ free(old);
+ }
+ ccache->cursors = NULL;
+
+ return 0;
+}
+
+krb5_error_code
+kcm_ccache_remove_creds(krb5_context context,
+ kcm_ccache ccache)
+{
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ ret = kcm_ccache_remove_creds_internal(context, ccache);
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_zero_ccache_data_internal(krb5_context context,
+ kcm_ccache_data *cache)
+{
+ if (cache->client != NULL) {
+ krb5_free_principal(context, cache->client);
+ cache->client = NULL;
+ }
+
+ if (cache->server != NULL) {
+ krb5_free_principal(context, cache->server);
+ cache->server = NULL;
+ }
+
+ kcm_ccache_remove_creds_internal(context, cache);
+
+ return 0;
+}
+
+krb5_error_code
+kcm_zero_ccache_data(krb5_context context,
+ kcm_ccache cache)
+{
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(cache);
+
+ HEIMDAL_MUTEX_lock(&cache->mutex);
+ ret = kcm_zero_ccache_data_internal(context, cache);
+ HEIMDAL_MUTEX_unlock(&cache->mutex);
+
+ return ret;
+}
+
+static krb5_error_code
+kcm_free_ccache_data_internal(krb5_context context,
+ kcm_ccache_data *cache)
+{
+ KCM_ASSERT_VALID(cache);
+
+ if (cache->name != NULL) {
+ free(cache->name);
+ cache->name = NULL;
+ }
+
+ if (cache->flags & KCM_FLAGS_USE_KEYTAB) {
+ krb5_kt_close(context, cache->key.keytab);
+ cache->key.keytab = NULL;
+ } else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) {
+ krb5_free_keyblock_contents(context, &cache->key.keyblock);
+ krb5_keyblock_zero(&cache->key.keyblock);
+ }
+
+ cache->flags = 0;
+ cache->mode = 0;
+ cache->uid = -1;
+ cache->gid = -1;
+
+ kcm_zero_ccache_data_internal(context, cache);
+
+ cache->tkt_life = 0;
+ cache->renew_life = 0;
+
+ cache->next = NULL;
+ cache->refcnt = 0;
+
+ HEIMDAL_MUTEX_unlock(&cache->mutex);
+ HEIMDAL_MUTEX_destroy(&cache->mutex);
+
+ return 0;
+}
+
+krb5_error_code
+kcm_retain_ccache(krb5_context context,
+ kcm_ccache ccache)
+{
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ ccache->refcnt++;
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return 0;
+}
+
+krb5_error_code
+kcm_release_ccache(krb5_context context,
+ kcm_ccache *ccache)
+{
+ kcm_ccache c = *ccache;
+ krb5_error_code ret = 0;
+
+ KCM_ASSERT_VALID(c);
+
+ HEIMDAL_MUTEX_lock(&c->mutex);
+ if (c->refcnt == 1) {
+ ret = kcm_free_ccache_data_internal(context, c);
+ if (ret == 0)
+ free(c);
+ } else {
+ c->refcnt--;
+ HEIMDAL_MUTEX_unlock(&c->mutex);
+ }
+
+ *ccache = NULL;
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_gen_new(krb5_context context,
+ pid_t pid,
+ uid_t uid,
+ gid_t gid,
+ kcm_ccache *ccache)
+{
+ krb5_error_code ret;
+ char *name;
+
+ name = kcm_ccache_nextid(pid, uid, gid);
+ if (name == NULL) {
+ return KRB5_CC_NOMEM;
+ }
+
+ ret = kcm_ccache_new(context, name, ccache);
+
+ free(name);
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_new(krb5_context context,
+ const char *name,
+ kcm_ccache *ccache)
+{
+ krb5_error_code ret;
+
+ ret = kcm_ccache_alloc(context, name, ccache);
+ if (ret == 0) {
+ /*
+ * one reference is held by the linked list,
+ * one by the caller
+ */
+ kcm_retain_ccache(context, *ccache);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_resolve(krb5_context context,
+ const char *name,
+ kcm_ccache *ccache)
+{
+ krb5_error_code ret;
+
+ ret = kcm_ccache_resolve_internal(context, name, ccache);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_destroy(krb5_context context,
+ const char *name)
+{
+ krb5_error_code ret;
+
+ ret = kcm_ccache_destroy_internal(context, name);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_destroy_if_empty(krb5_context context,
+ kcm_ccache ccache)
+{
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ if (ccache->creds == NULL) {
+ ret = kcm_ccache_destroy_internal(context, ccache->name);
+ } else
+ ret = 0;
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_store_cred(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds *creds,
+ int copy)
+{
+ krb5_error_code ret;
+ krb5_creds *tmp;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ ret = kcm_ccache_store_cred_internal(context, ccache, creds, copy, &tmp);
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_store_cred_internal(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds *creds,
+ int copy,
+ krb5_creds **credp)
+{
+ struct kcm_creds **c;
+ krb5_error_code ret;
+
+ for (c = &ccache->creds; *c != NULL; c = &(*c)->next)
+ ;
+
+ *c = (struct kcm_creds *)malloc(sizeof(struct kcm_creds));
+ if (*c == NULL) {
+ return KRB5_CC_NOMEM;
+ }
+
+ *credp = &(*c)->cred;
+
+ if (copy) {
+ ret = krb5_copy_creds_contents(context, creds, *credp);
+ if (ret) {
+ free(*c);
+ *c = NULL;
+ }
+ } else {
+ **credp = *creds;
+ ret = 0;
+ }
+
+ (*c)->next = NULL;
+
+ return ret;
+}
+
+static void
+remove_cred(krb5_context context,
+ struct kcm_creds **c)
+{
+ struct kcm_creds *cred;
+
+ cred = *c;
+
+ *c = cred->next;
+
+ krb5_free_cred_contents(context, &cred->cred);
+ free(cred);
+}
+
+krb5_error_code
+kcm_ccache_remove_cred_internal(krb5_context context,
+ kcm_ccache ccache,
+ krb5_flags whichfields,
+ const krb5_creds *mcreds)
+{
+ krb5_error_code ret;
+ struct kcm_creds **c;
+
+ ret = KRB5_CC_NOTFOUND;
+
+ for (c = &ccache->creds; *c != NULL; c = &(*c)->next) {
+ if (krb5_compare_creds(context, whichfields, mcreds, &(*c)->cred)) {
+ remove_cred(context, c);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_remove_cred(krb5_context context,
+ kcm_ccache ccache,
+ krb5_flags whichfields,
+ const krb5_creds *mcreds)
+{
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ ret = kcm_ccache_remove_cred_internal(context, ccache, whichfields, mcreds);
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_retrieve_cred_internal(krb5_context context,
+ kcm_ccache ccache,
+ krb5_flags whichfields,
+ const krb5_creds *mcreds,
+ krb5_creds **creds)
+{
+ krb5_boolean match;
+ struct kcm_creds *c;
+ krb5_error_code ret;
+
+ memset(creds, 0, sizeof(*creds));
+
+ ret = KRB5_CC_END;
+
+ match = FALSE;
+ for (c = ccache->creds; c != NULL; c = c->next) {
+ match = krb5_compare_creds(context, whichfields, mcreds, &c->cred);
+ if (match)
+ break;
+ }
+
+ if (match) {
+ ret = 0;
+ *creds = &c->cred;
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_retrieve_cred(krb5_context context,
+ kcm_ccache ccache,
+ krb5_flags whichfields,
+ const krb5_creds *mcreds,
+ krb5_creds **credp)
+{
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ ret = kcm_ccache_retrieve_cred_internal(context, ccache,
+ whichfields, mcreds, credp);
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
diff --git a/crypto/heimdal/kcm/client.c b/crypto/heimdal/kcm/client.c
new file mode 100644
index 0000000..f075894
--- /dev/null
+++ b/crypto/heimdal/kcm/client.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+#include <pwd.h>
+
+RCSID("$Id: client.c 20487 2007-04-21 06:25:06Z lha $");
+
+krb5_error_code
+kcm_ccache_resolve_client(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ const char *name,
+ kcm_ccache *ccache)
+{
+ krb5_error_code ret;
+
+ ret = kcm_ccache_resolve(context, name, ccache);
+ if (ret) {
+ kcm_log(1, "Failed to resolve cache %s: %s",
+ name, krb5_get_err_text(context, ret));
+ return ret;
+ }
+
+ ret = kcm_access(context, client, opcode, *ccache);
+ if (ret) {
+ ret = KRB5_FCC_NOFILE; /* don't disclose */
+ kcm_release_ccache(context, ccache);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_destroy_client(krb5_context context,
+ kcm_client *client,
+ const char *name)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+
+ ret = kcm_ccache_resolve(context, name, &ccache);
+ if (ret) {
+ kcm_log(1, "Failed to resolve cache %s: %s",
+ name, krb5_get_err_text(context, ret));
+ return ret;
+ }
+
+ ret = kcm_access(context, client, KCM_OP_DESTROY, ccache);
+ if (ret) {
+ kcm_release_ccache(context, &ccache);
+ return ret;
+ }
+
+ ret = kcm_ccache_destroy(context, ccache->name);
+ if (ret == 0) {
+ /* don't leave any events dangling */
+ kcm_cleanup_events(context, ccache);
+ }
+
+ kcm_release_ccache(context, &ccache);
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_new_client(krb5_context context,
+ kcm_client *client,
+ const char *name,
+ kcm_ccache *ccache_p)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+
+ /* We insist the ccache name starts with UID or UID: */
+ if (name_constraints != 0) {
+ char prefix[64];
+ size_t prefix_len;
+ int bad = 1;
+
+ snprintf(prefix, sizeof(prefix), "%ld:", (long)client->uid);
+ prefix_len = strlen(prefix);
+
+ if (strncmp(name, prefix, prefix_len) == 0)
+ bad = 0;
+ else {
+ prefix[prefix_len - 1] = '\0';
+ if (strcmp(name, prefix) == 0)
+ bad = 0;
+ }
+
+ /* Allow root to create badly-named ccaches */
+ if (bad && !CLIENT_IS_ROOT(client))
+ return KRB5_CC_BADNAME;
+ }
+
+ ret = kcm_ccache_resolve(context, name, &ccache);
+ if (ret == 0) {
+ if ((ccache->uid != client->uid ||
+ ccache->gid != client->gid) && !CLIENT_IS_ROOT(client))
+ return KRB5_FCC_PERM;
+ } else if (ret != KRB5_FCC_NOFILE && !(CLIENT_IS_ROOT(client) && ret == KRB5_FCC_PERM)) {
+ return ret;
+ }
+
+ if (ret == KRB5_FCC_NOFILE) {
+ ret = kcm_ccache_new(context, name, &ccache);
+ if (ret) {
+ kcm_log(1, "Failed to initialize cache %s: %s",
+ name, krb5_get_err_text(context, ret));
+ return ret;
+ }
+
+ /* bind to current client */
+ ccache->uid = client->uid;
+ ccache->gid = client->gid;
+ } else {
+ ret = kcm_zero_ccache_data(context, ccache);
+ if (ret) {
+ kcm_log(1, "Failed to empty cache %s: %s",
+ name, krb5_get_err_text(context, ret));
+ kcm_release_ccache(context, &ccache);
+ return ret;
+ }
+ kcm_cleanup_events(context, ccache);
+ }
+
+ ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache);
+ if (ret) {
+ kcm_release_ccache(context, &ccache);
+ kcm_ccache_destroy(context, name);
+ return ret;
+ }
+
+ /*
+ * Finally, if the user is root and the cache was created under
+ * another user's name, chown the cache to that user and their
+ * default gid.
+ */
+ if (CLIENT_IS_ROOT(client)) {
+ unsigned long uid;
+ int matches = sscanf(name,"%ld:",&uid);
+ if (matches == 0)
+ matches = sscanf(name,"%ld",&uid);
+ if (matches == 1) {
+ struct passwd *pwd = getpwuid(uid);
+ if (pwd != NULL) {
+ gid_t gid = pwd->pw_gid;
+ kcm_chown(context, client, ccache, uid, gid);
+ }
+ }
+ }
+
+ *ccache_p = ccache;
+ return 0;
+}
+
diff --git a/crypto/heimdal/kcm/config.c b/crypto/heimdal/kcm/config.c
new file mode 100644
index 0000000..5de797e
--- /dev/null
+++ b/crypto/heimdal/kcm/config.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+#include <getarg.h>
+#include <parse_bytes.h>
+
+RCSID("$Id: config.c 15296 2005-05-30 10:17:43Z lha $");
+
+static const char *config_file; /* location of kcm config file */
+
+size_t max_request = 0; /* maximal size of a request */
+char *socket_path = NULL;
+char *door_path = NULL;
+
+static char *max_request_str; /* `max_request' as a string */
+
+int detach_from_console = -1;
+#define DETACH_IS_DEFAULT FALSE
+
+static const char *system_cache_name = NULL;
+static const char *system_keytab = NULL;
+static const char *system_principal = NULL;
+static const char *system_server = NULL;
+static const char *system_perms = NULL;
+static const char *system_user = NULL;
+static const char *system_group = NULL;
+
+static const char *renew_life = NULL;
+static const char *ticket_life = NULL;
+
+int disallow_getting_krbtgt = -1;
+int name_constraints = -1;
+
+static int help_flag;
+static int version_flag;
+
+static struct getargs args[] = {
+ {
+ "cache-name", 0, arg_string, &system_cache_name,
+ "system cache name", "cachename"
+ },
+ {
+ "config-file", 'c', arg_string, &config_file,
+ "location of config file", "file"
+ },
+ {
+ "group", 'g', arg_string, &system_group,
+ "system cache group", "group"
+ },
+ {
+ "max-request", 0, arg_string, &max_request,
+ "max size for a kcm-request", "size"
+ },
+#if DETACH_IS_DEFAULT
+ {
+ "detach", 'D', arg_negative_flag, &detach_from_console,
+ "don't detach from console"
+ },
+#else
+ {
+ "detach", 0 , arg_flag, &detach_from_console,
+ "detach from console"
+ },
+#endif
+ { "help", 'h', arg_flag, &help_flag },
+ {
+ "system-principal", 'k', arg_string, &system_principal,
+ "system principal name", "principal"
+ },
+ {
+ "lifetime", 'l', arg_string, &ticket_life,
+ "lifetime of system tickets", "time"
+ },
+ {
+ "mode", 'm', arg_string, &system_perms,
+ "octal mode of system cache", "mode"
+ },
+ {
+ "name-constraints", 'n', arg_negative_flag, &name_constraints,
+ "disable credentials cache name constraints"
+ },
+ {
+ "disallow-getting-krbtgt", 0, arg_flag, &disallow_getting_krbtgt,
+ "disable fetching krbtgt from the cache"
+ },
+ {
+ "renewable-life", 'r', arg_string, &renew_life,
+ "renewable lifetime of system tickets", "time"
+ },
+ {
+ "socket-path", 's', arg_string, &socket_path,
+ "path to kcm domain socket", "path"
+ },
+#ifdef HAVE_DOOR_CREATE
+ {
+ "door-path", 's', arg_string, &door_path,
+ "path to kcm door", "path"
+ },
+#endif
+ {
+ "server", 'S', arg_string, &system_server,
+ "server to get system ticket for", "principal"
+ },
+ {
+ "keytab", 't', arg_string, &system_keytab,
+ "system keytab name", "keytab"
+ },
+ {
+ "user", 'u', arg_string, &system_user,
+ "system cache owner", "user"
+ },
+ { "version", 'v', arg_flag, &version_flag }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int ret)
+{
+ arg_printusage (args, num_args, NULL, "");
+ exit (ret);
+}
+
+static int parse_owners(kcm_ccache ccache)
+{
+ uid_t uid = 0;
+ gid_t gid = 0;
+ struct passwd *pw;
+ struct group *gr;
+ int uid_p = 0;
+ int gid_p = 0;
+
+ if (system_user != NULL) {
+ if (isdigit((unsigned char)system_user[0])) {
+ pw = getpwuid(atoi(system_user));
+ } else {
+ pw = getpwnam(system_user);
+ }
+ if (pw == NULL) {
+ return errno;
+ }
+
+ system_user = strdup(pw->pw_name);
+ if (system_user == NULL) {
+ return ENOMEM;
+ }
+
+ uid = pw->pw_uid; uid_p = 1;
+ gid = pw->pw_gid; gid_p = 1;
+ }
+
+ if (system_group != NULL) {
+ if (isdigit((unsigned char)system_group[0])) {
+ gr = getgrgid(atoi(system_group));
+ } else {
+ gr = getgrnam(system_group);
+ }
+ if (gr == NULL) {
+ return errno;
+ }
+
+ gid = gr->gr_gid; gid_p = 1;
+ }
+
+ if (uid_p)
+ ccache->uid = uid;
+ else
+ ccache->uid = 0; /* geteuid() XXX */
+
+ if (gid_p)
+ ccache->gid = gid;
+ else
+ ccache->gid = 0; /* getegid() XXX */
+
+ return 0;
+}
+
+static const char *
+kcm_system_config_get_string(const char *string)
+{
+ return krb5_config_get_string(kcm_context, NULL, "kcm",
+ "system_ccache", string, NULL);
+}
+
+static krb5_error_code
+ccache_init_system(void)
+{
+ kcm_ccache ccache;
+ krb5_error_code ret;
+
+ if (system_cache_name == NULL)
+ system_cache_name = kcm_system_config_get_string("cc_name");
+
+ ret = kcm_ccache_new(kcm_context,
+ system_cache_name ? system_cache_name : "SYSTEM",
+ &ccache);
+ if (ret)
+ return ret;
+
+ ccache->flags |= KCM_FLAGS_OWNER_IS_SYSTEM;
+ ccache->flags |= KCM_FLAGS_USE_KEYTAB;
+
+ ret = parse_owners(ccache);
+ if (ret)
+ return ret;
+
+ ret = krb5_parse_name(kcm_context, system_principal, &ccache->client);
+ if (ret) {
+ kcm_release_ccache(kcm_context, &ccache);
+ return ret;
+ }
+
+ if (system_server == NULL)
+ system_server = kcm_system_config_get_string("server");
+
+ if (system_server != NULL) {
+ ret = krb5_parse_name(kcm_context, system_server, &ccache->server);
+ if (ret) {
+ kcm_release_ccache(kcm_context, &ccache);
+ return ret;
+ }
+ }
+
+ if (system_keytab == NULL)
+ system_keytab = kcm_system_config_get_string("keytab_name");
+
+ if (system_keytab != NULL) {
+ ret = krb5_kt_resolve(kcm_context, system_keytab, &ccache->key.keytab);
+ } else {
+ ret = krb5_kt_default(kcm_context, &ccache->key.keytab);
+ }
+ if (ret) {
+ kcm_release_ccache(kcm_context, &ccache);
+ return ret;
+ }
+
+ if (renew_life == NULL)
+ renew_life = kcm_system_config_get_string("renew_life");
+
+ if (renew_life == NULL)
+ renew_life = "1 month";
+
+ if (renew_life != NULL) {
+ ccache->renew_life = parse_time(renew_life, "s");
+ if (ccache->renew_life < 0) {
+ kcm_release_ccache(kcm_context, &ccache);
+ return EINVAL;
+ }
+ }
+
+ if (ticket_life == NULL)
+ ticket_life = kcm_system_config_get_string("ticket_life");
+
+ if (ticket_life != NULL) {
+ ccache->tkt_life = parse_time(ticket_life, "s");
+ if (ccache->tkt_life < 0) {
+ kcm_release_ccache(kcm_context, &ccache);
+ return EINVAL;
+ }
+ }
+
+ if (system_perms == NULL)
+ system_perms = kcm_system_config_get_string("mode");
+
+ if (system_perms != NULL) {
+ int mode;
+
+ if (sscanf(system_perms, "%o", &mode) != 1)
+ return EINVAL;
+
+ ccache->mode = mode;
+ }
+
+ if (disallow_getting_krbtgt == -1) {
+ disallow_getting_krbtgt =
+ krb5_config_get_bool_default(kcm_context, NULL, FALSE, "kcm",
+ "disallow-getting-krbtgt", NULL);
+ }
+
+ /* enqueue default actions for credentials cache */
+ ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL);
+
+ kcm_release_ccache(kcm_context, &ccache); /* retained by event queue */
+
+ return ret;
+}
+
+void
+kcm_configure(int argc, char **argv)
+{
+ krb5_error_code ret;
+ int optind = 0;
+ const char *p;
+
+ while(getarg(args, num_args, argc, argv, &optind))
+ warnx("error at argument `%s'", argv[optind]);
+
+ if(help_flag)
+ usage (0);
+
+ if (version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage(1);
+
+ {
+ char **files;
+
+ if(config_file == NULL)
+ config_file = _PATH_KCM_CONF;
+
+ ret = krb5_prepend_config_files_default(config_file, &files);
+ if (ret)
+ krb5_err(kcm_context, 1, ret, "getting configuration files");
+
+ ret = krb5_set_config_files(kcm_context, files);
+ krb5_free_config_files(files);
+ if(ret)
+ krb5_err(kcm_context, 1, ret, "reading configuration files");
+ }
+
+ if(max_request_str)
+ max_request = parse_bytes(max_request_str, NULL);
+
+ if(max_request == 0){
+ p = krb5_config_get_string (kcm_context,
+ NULL,
+ "kcm",
+ "max-request",
+ NULL);
+ if(p)
+ max_request = parse_bytes(p, NULL);
+ }
+
+ if (system_principal == NULL) {
+ system_principal = kcm_system_config_get_string("principal");
+ }
+
+ if (system_principal != NULL) {
+ ret = ccache_init_system();
+ if (ret)
+ krb5_err(kcm_context, 1, ret, "initializing system ccache");
+ }
+
+ if(detach_from_console == -1)
+ detach_from_console = krb5_config_get_bool_default(kcm_context, NULL,
+ DETACH_IS_DEFAULT,
+ "kcm",
+ "detach", NULL);
+ kcm_openlog();
+ if(max_request == 0)
+ max_request = 64 * 1024;
+}
+
diff --git a/crypto/heimdal/kcm/connect.c b/crypto/heimdal/kcm/connect.c
new file mode 100644
index 0000000..b3a21aa
--- /dev/null
+++ b/crypto/heimdal/kcm/connect.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kcm_locl.h"
+
+RCSID("$Id: connect.c 16314 2005-11-29 19:03:50Z lha $");
+
+struct descr {
+ int s;
+ int type;
+ char *path;
+ unsigned char *buf;
+ size_t size;
+ size_t len;
+ time_t timeout;
+ struct sockaddr_storage __ss;
+ struct sockaddr *sa;
+ socklen_t sock_len;
+ kcm_client peercred;
+};
+
+static void
+init_descr(struct descr *d)
+{
+ memset(d, 0, sizeof(*d));
+ d->sa = (struct sockaddr *)&d->__ss;
+ d->s = -1;
+}
+
+/*
+ * re-initialize all `n' ->sa in `d'.
+ */
+
+static void
+reinit_descrs (struct descr *d, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ d[i].sa = (struct sockaddr *)&d[i].__ss;
+}
+
+/*
+ * Update peer credentials from socket.
+ *
+ * SCM_CREDS can only be updated the first time there is read data to
+ * read from the filedescriptor, so if we read do it before this
+ * point, the cred data might not be is not there yet.
+ */
+
+static int
+update_client_creds(int s, kcm_client *peer)
+{
+#ifdef GETPEERUCRED
+ /* Solaris 10 */
+ {
+ ucred_t *peercred;
+
+ if (getpeerucred(s, &peercred) != 0) {
+ peer->uid = ucred_geteuid(peercred);
+ peer->gid = ucred_getegid(peercred);
+ peer->pid = 0;
+ ucred_free(peercred);
+ return 0;
+ }
+ }
+#endif
+#ifdef GETPEEREID
+ /* FreeBSD, OpenBSD */
+ {
+ uid_t uid;
+ gid_t gid;
+
+ if (getpeereid(s, &uid, &gid) == 0) {
+ peer->uid = uid;
+ peer->gid = gid;
+ peer->pid = 0;
+ return 0;
+ }
+ }
+#endif
+#ifdef SO_PEERCRED
+ /* Linux */
+ {
+ struct ucred pc;
+ socklen_t pclen = sizeof(pc);
+
+ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
+ peer->uid = pc.uid;
+ peer->gid = pc.gid;
+ peer->pid = pc.pid;
+ return 0;
+ }
+ }
+#endif
+#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
+ {
+ struct xucred peercred;
+ socklen_t peercredlen = sizeof(peercred);
+
+ if (getsockopt(s, LOCAL_PEERCRED, 1,
+ (void *)&peercred, &peercredlen) == 0
+ && peercred.cr_version == XUCRED_VERSION)
+ {
+ peer->uid = peercred.cr_uid;
+ peer->gid = peercred.cr_gid;
+ peer->pid = 0;
+ return 0;
+ }
+ }
+#endif
+#if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
+ /* NetBSD */
+ if (peer->uid == -1) {
+ struct msghdr msg;
+ socklen_t crmsgsize;
+ void *crmsg;
+ struct cmsghdr *cmp;
+ struct sockcred *sc;
+
+ memset(&msg, 0, sizeof(msg));
+ crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
+ if (crmsgsize == 0)
+ return 1 ;
+
+ crmsg = malloc(crmsgsize);
+ if (crmsg == NULL)
+ goto failed_scm_creds;
+
+ memset(crmsg, 0, crmsgsize);
+
+ msg.msg_control = crmsg;
+ msg.msg_controllen = crmsgsize;
+
+ if (recvmsg(s, &msg, 0) < 0) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ cmp = CMSG_FIRSTHDR(&msg);
+ if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
+
+ peer->uid = sc->sc_euid;
+ peer->gid = sc->sc_egid;
+ peer->pid = 0;
+
+ free(crmsg);
+ return 0;
+ } else {
+ /* we already got the cred, just return it */
+ return 0;
+ }
+ failed_scm_creds:
+#endif
+ krb5_warn(kcm_context, errno, "failed to determine peer identity");
+ return 1;
+}
+
+
+/*
+ * Create the socket (family, type, port) in `d'
+ */
+
+static void
+init_socket(struct descr *d)
+{
+ struct sockaddr_un un;
+ struct sockaddr *sa = (struct sockaddr *)&un;
+ krb5_socklen_t sa_size = sizeof(un);
+
+ init_descr (d);
+
+ un.sun_family = AF_UNIX;
+
+ if (socket_path != NULL)
+ d->path = socket_path;
+ else
+ d->path = _PATH_KCM_SOCKET;
+
+ strlcpy(un.sun_path, d->path, sizeof(un.sun_path));
+
+ d->s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (d->s < 0){
+ krb5_warn(kcm_context, errno, "socket(%d, %d, 0)", AF_UNIX, SOCK_STREAM);
+ d->s = -1;
+ return;
+ }
+#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR)
+ {
+ int one = 1;
+ setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
+ }
+#endif
+#ifdef LOCAL_CREDS
+ {
+ int one = 1;
+ setsockopt(d->s, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
+ }
+#endif
+
+ d->type = SOCK_STREAM;
+
+ unlink(d->path);
+
+ if (bind(d->s, sa, sa_size) < 0) {
+ krb5_warn(kcm_context, errno, "bind %s", un.sun_path);
+ close(d->s);
+ d->s = -1;
+ return;
+ }
+
+ if (listen(d->s, SOMAXCONN) < 0) {
+ krb5_warn(kcm_context, errno, "listen %s", un.sun_path);
+ close(d->s);
+ d->s = -1;
+ return;
+ }
+
+ chmod(d->path, 0777);
+
+ return;
+}
+
+/*
+ * Allocate descriptors for all the sockets that we should listen on
+ * and return the number of them.
+ */
+
+static int
+init_sockets(struct descr **desc)
+{
+ struct descr *d;
+ size_t num = 0;
+
+ d = (struct descr *)malloc(sizeof(*d));
+ if (d == NULL) {
+ krb5_errx(kcm_context, 1, "malloc failed");
+ }
+
+ init_socket(d);
+ if (d->s != -1) {
+ kcm_log(5, "listening on domain socket %s", d->path);
+ num++;
+ }
+
+ reinit_descrs (d, num);
+ *desc = d;
+
+ return num;
+}
+
+/*
+ * handle the request in `buf, len', from `addr' (or `from' as a string),
+ * sending a reply in `reply'.
+ */
+
+static int
+process_request(unsigned char *buf,
+ size_t len,
+ krb5_data *reply,
+ kcm_client *client)
+{
+ krb5_data request;
+
+ if (len < 4) {
+ kcm_log(1, "malformed request from process %d (too short)",
+ client->pid);
+ return -1;
+ }
+
+ if (buf[0] != KCM_PROTOCOL_VERSION_MAJOR ||
+ buf[1] != KCM_PROTOCOL_VERSION_MINOR) {
+ kcm_log(1, "incorrect protocol version %d.%d from process %d",
+ buf[0], buf[1], client->pid);
+ return -1;
+ }
+
+ buf += 2;
+ len -= 2;
+
+ /* buf is now pointing at opcode */
+
+ request.data = buf;
+ request.length = len;
+
+ return kcm_dispatch(kcm_context, client, &request, reply);
+}
+
+/*
+ * Handle the request in `buf, len' to socket `d'
+ */
+
+static void
+do_request(void *buf, size_t len, struct descr *d)
+{
+ krb5_error_code ret;
+ krb5_data reply;
+
+ reply.length = 0;
+
+ ret = process_request(buf, len, &reply, &d->peercred);
+ if (reply.length != 0) {
+ unsigned char len[4];
+ struct msghdr msghdr;
+ struct iovec iov[2];
+
+ kcm_log(5, "sending %lu bytes to process %d",
+ (unsigned long)reply.length,
+ (int)d->peercred.pid);
+
+ memset (&msghdr, 0, sizeof(msghdr));
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
+#if 0
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+#endif
+
+ len[0] = (reply.length >> 24) & 0xff;
+ len[1] = (reply.length >> 16) & 0xff;
+ len[2] = (reply.length >> 8) & 0xff;
+ len[3] = reply.length & 0xff;
+
+ iov[0].iov_base = (void*)len;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = reply.data;
+ iov[1].iov_len = reply.length;
+
+ if (sendmsg (d->s, &msghdr, 0) < 0) {
+ kcm_log (0, "sendmsg(%d): %d %s", (int)d->peercred.pid,
+ errno, strerror(errno));
+ krb5_data_free(&reply);
+ return;
+ }
+
+ krb5_data_free(&reply);
+ }
+
+ if (ret) {
+ kcm_log(0, "Failed processing %lu byte request from process %d",
+ (unsigned long)len, d->peercred.pid);
+ }
+}
+
+static void
+clear_descr(struct descr *d)
+{
+ if(d->buf)
+ memset(d->buf, 0, d->size);
+ d->len = 0;
+ if(d->s != -1)
+ close(d->s);
+ d->s = -1;
+}
+
+#define STREAM_TIMEOUT 4
+
+/*
+ * accept a new stream connection on `d[parent]' and store it in `d[child]'
+ */
+
+static void
+add_new_stream (struct descr *d, int parent, int child)
+{
+ int s;
+
+ if (child == -1)
+ return;
+
+ d[child].peercred.pid = -1;
+ d[child].peercred.uid = -1;
+ d[child].peercred.gid = -1;
+
+ d[child].sock_len = sizeof(d[child].__ss);
+ s = accept(d[parent].s, d[child].sa, &d[child].sock_len);
+ if(s < 0) {
+ krb5_warn(kcm_context, errno, "accept");
+ return;
+ }
+
+ if (s >= FD_SETSIZE) {
+ krb5_warnx(kcm_context, "socket FD too large");
+ close (s);
+ return;
+ }
+
+ d[child].s = s;
+ d[child].timeout = time(NULL) + STREAM_TIMEOUT;
+ d[child].type = SOCK_STREAM;
+}
+
+/*
+ * Grow `d' to handle at least `n'.
+ * Return != 0 if fails
+ */
+
+static int
+grow_descr (struct descr *d, size_t n)
+{
+ if (d->size - d->len < n) {
+ unsigned char *tmp;
+ size_t grow;
+
+ grow = max(1024, d->len + n);
+ if (d->size + grow > max_request) {
+ kcm_log(0, "Request exceeds max request size (%lu bytes).",
+ (unsigned long)d->size + grow);
+ clear_descr(d);
+ return -1;
+ }
+ tmp = realloc (d->buf, d->size + grow);
+ if (tmp == NULL) {
+ kcm_log(0, "Failed to re-allocate %lu bytes.",
+ (unsigned long)d->size + grow);
+ clear_descr(d);
+ return -1;
+ }
+ d->size += grow;
+ d->buf = tmp;
+ }
+ return 0;
+}
+
+/*
+ * Handle incoming data to the stream socket in `d[index]'
+ */
+
+static void
+handle_stream(struct descr *d, int index, int min_free)
+{
+ unsigned char buf[1024];
+ int n;
+ int ret = 0;
+
+ if (d[index].timeout == 0) {
+ add_new_stream (d, index, min_free);
+ return;
+ }
+
+ if (update_client_creds(d[index].s, &d[index].peercred)) {
+ krb5_warnx(kcm_context, "failed to update peer identity");
+ clear_descr(d + index);
+ return;
+ }
+
+ if (d[index].peercred.uid == -1) {
+ krb5_warnx(kcm_context, "failed to determine peer identity");
+ clear_descr (d + index);
+ return;
+ }
+
+ n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL);
+ if (n < 0) {
+ krb5_warn(kcm_context, errno, "recvfrom");
+ return;
+ } else if (n == 0) {
+ krb5_warnx(kcm_context, "connection closed before end of data "
+ "after %lu bytes from process %ld",
+ (unsigned long) d[index].len, (long) d[index].peercred.pid);
+ clear_descr (d + index);
+ return;
+ }
+ if (grow_descr (&d[index], n))
+ return;
+ memcpy(d[index].buf + d[index].len, buf, n);
+ d[index].len += n;
+ if (d[index].len > 4) {
+ krb5_storage *sp;
+ int32_t len;
+
+ sp = krb5_storage_from_mem(d[index].buf, d[index].len);
+ if (sp == NULL) {
+ kcm_log (0, "krb5_storage_from_mem failed");
+ ret = -1;
+ } else {
+ krb5_ret_int32(sp, &len);
+ krb5_storage_free(sp);
+ if (d[index].len - 4 >= len) {
+ memmove(d[index].buf, d[index].buf + 4, d[index].len - 4);
+ ret = 1;
+ } else
+ ret = 0;
+ }
+ }
+ if (ret < 0)
+ return;
+ else if (ret == 1) {
+ do_request(d[index].buf, d[index].len, &d[index]);
+ clear_descr(d + index);
+ }
+}
+
+#ifdef HAVE_DOOR_CREATE
+
+static void
+kcm_door_server(void *cookie, char *argp, size_t arg_size,
+ door_desc_t *dp, uint_t n_desc)
+{
+ kcm_client peercred;
+ door_cred_t cred;
+ krb5_error_code ret;
+ krb5_data reply;
+ size_t length;
+ char *p;
+
+ reply.length = 0;
+
+ p = NULL;
+ length = 0;
+
+ if (door_cred(&cred) != 0) {
+ kcm_log(0, "door_cred failed with %s", strerror(errno));
+ goto out;
+ }
+
+ peercred.uid = cred.dc_euid;
+ peercred.gid = cred.dc_egid;
+ peercred.pid = cred.dc_pid;
+
+ ret = process_request((unsigned char*)argp, arg_size, &reply, &peercred);
+ if (reply.length != 0) {
+ p = alloca(reply.length); /* XXX don't use alloca */
+ if (p) {
+ memcpy(p, reply.data, reply.length);
+ length = reply.length;
+ }
+ krb5_data_free(&reply);
+ }
+
+ out:
+ door_return(p, length, NULL, 0);
+}
+
+static void
+kcm_setup_door(void)
+{
+ int fd, ret;
+ char *path;
+
+ fd = door_create(kcm_door_server, NULL, 0);
+ if (fd < 0)
+ krb5_err(kcm_context, 1, errno, "Failed to create door");
+
+ if (door_path != NULL)
+ path = door_path;
+ else
+ path = _PATH_KCM_DOOR;
+
+ unlink(path);
+ ret = open(path, O_RDWR | O_CREAT, 0666);
+ if (ret < 0)
+ krb5_err(kcm_context, 1, errno, "Failed to create/open door");
+ close(ret);
+
+ ret = fattach(fd, path);
+ if (ret < 0)
+ krb5_err(kcm_context, 1, errno, "Failed to attach door");
+
+}
+#endif /* HAVE_DOOR_CREATE */
+
+
+void
+kcm_loop(void)
+{
+ struct descr *d;
+ int ndescr;
+
+#ifdef HAVE_DOOR_CREATE
+ kcm_setup_door();
+#endif
+
+ ndescr = init_sockets(&d);
+ if (ndescr <= 0) {
+ krb5_warnx(kcm_context, "No sockets!");
+#ifndef HAVE_DOOR_CREATE
+ exit(1);
+#endif
+ }
+ while (exit_flag == 0){
+ struct timeval tmout;
+ fd_set fds;
+ int min_free = -1;
+ int max_fd = 0;
+ int i;
+
+ FD_ZERO(&fds);
+ for(i = 0; i < ndescr; i++) {
+ if (d[i].s >= 0){
+ if(d[i].type == SOCK_STREAM &&
+ d[i].timeout && d[i].timeout < time(NULL)) {
+ kcm_log(1, "Stream connection from %d expired after %lu bytes",
+ d[i].peercred.pid, (unsigned long)d[i].len);
+ clear_descr(&d[i]);
+ continue;
+ }
+ if (max_fd < d[i].s)
+ max_fd = d[i].s;
+ if (max_fd >= FD_SETSIZE)
+ krb5_errx(kcm_context, 1, "fd too large");
+ FD_SET(d[i].s, &fds);
+ } else if (min_free < 0 || i < min_free)
+ min_free = i;
+ }
+ if (min_free == -1) {
+ struct descr *tmp;
+ tmp = realloc(d, (ndescr + 4) * sizeof(*d));
+ if(tmp == NULL)
+ krb5_warnx(kcm_context, "No memory");
+ else {
+ d = tmp;
+ reinit_descrs (d, ndescr);
+ memset(d + ndescr, 0, 4 * sizeof(*d));
+ for(i = ndescr; i < ndescr + 4; i++)
+ init_descr (&d[i]);
+ min_free = ndescr;
+ ndescr += 4;
+ }
+ }
+
+ tmout.tv_sec = STREAM_TIMEOUT;
+ tmout.tv_usec = 0;
+ switch (select(max_fd + 1, &fds, 0, 0, &tmout)){
+ case 0:
+ kcm_run_events(kcm_context, time(NULL));
+ break;
+ case -1:
+ if (errno != EINTR)
+ krb5_warn(kcm_context, errno, "select");
+ break;
+ default:
+ for(i = 0; i < ndescr; i++) {
+ if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) {
+ if (d[i].type == SOCK_STREAM)
+ handle_stream(d, i, min_free);
+ }
+ }
+ kcm_run_events(kcm_context, time(NULL));
+ break;
+ }
+ }
+ if (d->path != NULL)
+ unlink(d->path);
+ free(d);
+}
+
diff --git a/crypto/heimdal/kcm/cursor.c b/crypto/heimdal/kcm/cursor.c
new file mode 100644
index 0000000..701f770
--- /dev/null
+++ b/crypto/heimdal/kcm/cursor.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: cursor.c 17447 2006-05-05 10:52:01Z lha $");
+
+krb5_error_code
+kcm_cursor_new(krb5_context context,
+ pid_t pid,
+ kcm_ccache ccache,
+ uint32_t *cursor)
+{
+ kcm_cursor **p;
+ krb5_error_code ret;
+
+ *cursor = 0;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ for (p = &ccache->cursors; *p != NULL; p = &(*p)->next)
+ ;
+
+ *p = (kcm_cursor *)malloc(sizeof(kcm_cursor));
+ if (*p == NULL) {
+ ret = KRB5_CC_NOMEM;
+ goto out;
+ }
+
+ (*p)->pid = pid;
+ (*p)->key = ++ccache->n_cursor;
+ (*p)->credp = ccache->creds;
+ (*p)->next = NULL;
+
+ *cursor = (*p)->key;
+
+ ret = 0;
+
+out:
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_cursor_find(krb5_context context,
+ pid_t pid,
+ kcm_ccache ccache,
+ uint32_t key,
+ kcm_cursor **cursor)
+{
+ kcm_cursor *p;
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ if (key == 0)
+ return KRB5_CC_NOTFOUND;
+
+ ret = KRB5_CC_END;
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ for (p = ccache->cursors; p != NULL; p = p->next) {
+ if (p->key == key) {
+ if (p->pid != pid)
+ ret = KRB5_FCC_PERM;
+ else
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret == 0)
+ *cursor = p;
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_cursor_delete(krb5_context context,
+ pid_t pid,
+ kcm_ccache ccache,
+ uint32_t key)
+{
+ kcm_cursor **p;
+ krb5_error_code ret;
+
+ KCM_ASSERT_VALID(ccache);
+
+ if (key == 0)
+ return KRB5_CC_NOTFOUND;
+
+ ret = KRB5_CC_END;
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ for (p = &ccache->cursors; *p != NULL; p = &(*p)->next) {
+ if ((*p)->key == key) {
+ if ((*p)->pid != pid)
+ ret = KRB5_FCC_PERM;
+ else
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ kcm_cursor *x = *p;
+
+ *p = x->next;
+ free(x);
+ }
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
diff --git a/crypto/heimdal/kcm/events.c b/crypto/heimdal/kcm/events.c
new file mode 100644
index 0000000..f1110d1
--- /dev/null
+++ b/crypto/heimdal/kcm/events.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: events.c 15294 2005-05-30 01:43:23Z lukeh $");
+
+/* thread-safe in case we multi-thread later */
+static HEIMDAL_MUTEX events_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static kcm_event *events_head = NULL;
+static time_t last_run = 0;
+
+static char *action_strings[] = {
+ "NONE", "ACQUIRE_CREDS", "RENEW_CREDS",
+ "DESTROY_CREDS", "DESTROY_EMPTY_CACHE" };
+
+krb5_error_code
+kcm_enqueue_event(krb5_context context,
+ kcm_event *event)
+{
+ krb5_error_code ret;
+
+ if (event->action == KCM_EVENT_NONE) {
+ return 0;
+ }
+
+ HEIMDAL_MUTEX_lock(&events_mutex);
+ ret = kcm_enqueue_event_internal(context, event);
+ HEIMDAL_MUTEX_unlock(&events_mutex);
+
+ return ret;
+}
+
+static void
+print_times(time_t time, char buf[64])
+{
+ if (time)
+ strftime(buf, 64, "%m-%dT%H:%M", gmtime(&time));
+ else
+ strlcpy(buf, "never", 64);
+}
+
+static void
+log_event(kcm_event *event, char *msg)
+{
+ char fire_time[64], expire_time[64];
+
+ print_times(event->fire_time, fire_time);
+ print_times(event->expire_time, expire_time);
+
+ kcm_log(7, "%s event %08x: fire_time %s fire_count %d expire_time %s "
+ "backoff_time %d action %s cache %s",
+ msg, event, fire_time, event->fire_count, expire_time,
+ event->backoff_time, action_strings[event->action],
+ event->ccache->name);
+}
+
+krb5_error_code
+kcm_enqueue_event_internal(krb5_context context,
+ kcm_event *event)
+{
+ kcm_event **e;
+
+ if (event->action == KCM_EVENT_NONE)
+ return 0;
+
+ for (e = &events_head; *e != NULL; e = &(*e)->next)
+ ;
+
+ *e = (kcm_event *)malloc(sizeof(kcm_event));
+ if (*e == NULL) {
+ return KRB5_CC_NOMEM;
+ }
+
+ (*e)->valid = 1;
+ (*e)->fire_time = event->fire_time;
+ (*e)->fire_count = 0;
+ (*e)->expire_time = event->expire_time;
+ (*e)->backoff_time = event->backoff_time;
+
+ (*e)->action = event->action;
+
+ kcm_retain_ccache(context, event->ccache);
+ (*e)->ccache = event->ccache;
+ (*e)->next = NULL;
+
+ log_event(*e, "enqueuing");
+
+ return 0;
+}
+
+/*
+ * Dump events list on SIGUSR2
+ */
+krb5_error_code
+kcm_debug_events(krb5_context context)
+{
+ kcm_event *e;
+
+ for (e = events_head; e != NULL; e = e->next)
+ log_event(e, "debug");
+
+ return 0;
+}
+
+krb5_error_code
+kcm_enqueue_event_relative(krb5_context context,
+ kcm_event *event)
+{
+ krb5_error_code ret;
+ kcm_event e;
+
+ e = *event;
+ e.backoff_time = e.fire_time;
+ e.fire_time += time(NULL);
+
+ ret = kcm_enqueue_event(context, &e);
+
+ return ret;
+}
+
+static krb5_error_code
+kcm_remove_event_internal(krb5_context context,
+ kcm_event **e)
+{
+ kcm_event *next;
+
+ next = (*e)->next;
+
+ (*e)->valid = 0;
+ (*e)->fire_time = 0;
+ (*e)->fire_count = 0;
+ (*e)->expire_time = 0;
+ (*e)->backoff_time = 0;
+ kcm_release_ccache(context, &(*e)->ccache);
+ (*e)->next = NULL;
+ free(*e);
+
+ *e = next;
+
+ return 0;
+}
+
+static int
+is_primary_credential_p(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds *newcred)
+{
+ krb5_flags whichfields;
+
+ if (ccache->client == NULL)
+ return 0;
+
+ if (newcred->client == NULL ||
+ !krb5_principal_compare(context, ccache->client, newcred->client))
+ return 0;
+
+ /* XXX just checks whether it's the first credential in the cache */
+ if (ccache->creds == NULL)
+ return 0;
+
+ whichfields = KRB5_TC_MATCH_KEYTYPE | KRB5_TC_MATCH_FLAGS_EXACT |
+ KRB5_TC_MATCH_TIMES_EXACT | KRB5_TC_MATCH_AUTHDATA |
+ KRB5_TC_MATCH_2ND_TKT | KRB5_TC_MATCH_IS_SKEY;
+
+ return krb5_compare_creds(context, whichfields, newcred, &ccache->creds->cred);
+}
+
+/*
+ * Setup default events for a new credential
+ */
+static krb5_error_code
+kcm_ccache_make_default_event(krb5_context context,
+ kcm_event *event,
+ krb5_creds *newcred)
+{
+ krb5_error_code ret = 0;
+ kcm_ccache ccache = event->ccache;
+
+ event->fire_time = 0;
+ event->expire_time = 0;
+ event->backoff_time = KCM_EVENT_DEFAULT_BACKOFF_TIME;
+
+ if (newcred == NULL) {
+ /* no creds, must be acquire creds request */
+ if ((ccache->flags & KCM_MASK_KEY_PRESENT) == 0) {
+ kcm_log(0, "Cannot acquire credentials without a key");
+ return KRB5_FCC_INTERNAL;
+ }
+
+ event->fire_time = time(NULL); /* right away */
+ event->action = KCM_EVENT_ACQUIRE_CREDS;
+ } else if (is_primary_credential_p(context, ccache, newcred)) {
+ if (newcred->flags.b.renewable) {
+ event->action = KCM_EVENT_RENEW_CREDS;
+ ccache->flags |= KCM_FLAGS_RENEWABLE;
+ } else {
+ if (ccache->flags & KCM_MASK_KEY_PRESENT)
+ event->action = KCM_EVENT_ACQUIRE_CREDS;
+ else
+ event->action = KCM_EVENT_NONE;
+ ccache->flags &= ~(KCM_FLAGS_RENEWABLE);
+ }
+ /* requeue with some slop factor */
+ event->fire_time = newcred->times.endtime - KCM_EVENT_QUEUE_INTERVAL;
+ } else {
+ event->action = KCM_EVENT_NONE;
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_ccache_enqueue_default(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds *newcred)
+{
+ kcm_event event;
+ krb5_error_code ret;
+
+ memset(&event, 0, sizeof(event));
+ event.ccache = ccache;
+
+ ret = kcm_ccache_make_default_event(context, &event, newcred);
+ if (ret)
+ return ret;
+
+ ret = kcm_enqueue_event_internal(context, &event);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+krb5_error_code
+kcm_remove_event(krb5_context context,
+ kcm_event *event)
+{
+ krb5_error_code ret;
+ kcm_event **e;
+ int found = 0;
+
+ log_event(event, "removing");
+
+ HEIMDAL_MUTEX_lock(&events_mutex);
+ for (e = &events_head; *e != NULL; e = &(*e)->next) {
+ if (event == *e) {
+ *e = event->next;
+ found++;
+ break;
+ }
+ }
+
+ if (!found) {
+ ret = KRB5_CC_NOTFOUND;
+ goto out;
+ }
+
+ ret = kcm_remove_event_internal(context, &event);
+
+out:
+ HEIMDAL_MUTEX_unlock(&events_mutex);
+
+ return ret;
+}
+
+krb5_error_code
+kcm_cleanup_events(krb5_context context,
+ kcm_ccache ccache)
+{
+ kcm_event **e;
+
+ KCM_ASSERT_VALID(ccache);
+
+ HEIMDAL_MUTEX_lock(&events_mutex);
+
+ for (e = &events_head; *e != NULL; e = &(*e)->next) {
+ if ((*e)->valid && (*e)->ccache == ccache) {
+ kcm_remove_event_internal(context, e);
+ }
+ if (*e == NULL)
+ break;
+ }
+
+ HEIMDAL_MUTEX_unlock(&events_mutex);
+
+ return 0;
+}
+
+static krb5_error_code
+kcm_fire_event(krb5_context context,
+ kcm_event **e)
+{
+ kcm_event *event;
+ krb5_error_code ret;
+ krb5_creds *credp = NULL;
+ int oneshot = 1;
+
+ event = *e;
+
+ switch (event->action) {
+ case KCM_EVENT_ACQUIRE_CREDS:
+ ret = kcm_ccache_acquire(context, event->ccache, &credp);
+ oneshot = 0;
+ break;
+ case KCM_EVENT_RENEW_CREDS:
+ ret = kcm_ccache_refresh(context, event->ccache, &credp);
+ if (ret == KRB5KRB_AP_ERR_TKT_EXPIRED) {
+ ret = kcm_ccache_acquire(context, event->ccache, &credp);
+ }
+ oneshot = 0;
+ break;
+ case KCM_EVENT_DESTROY_CREDS:
+ ret = kcm_ccache_destroy(context, event->ccache->name);
+ break;
+ case KCM_EVENT_DESTROY_EMPTY_CACHE:
+ ret = kcm_ccache_destroy_if_empty(context, event->ccache);
+ break;
+ default:
+ ret = KRB5_FCC_INTERNAL;
+ break;
+ }
+
+ event->fire_count++;
+
+ if (ret) {
+ /* Reschedule failed event for another time */
+ event->fire_time += event->backoff_time;
+ if (event->backoff_time < KCM_EVENT_MAX_BACKOFF_TIME)
+ event->backoff_time *= 2;
+
+ /* Remove it if it would never get executed */
+ if (event->expire_time &&
+ event->fire_time > event->expire_time)
+ kcm_remove_event_internal(context, e);
+ } else {
+ if (!oneshot) {
+ char *cpn;
+
+ if (krb5_unparse_name(context, event->ccache->client,
+ &cpn))
+ cpn = NULL;
+
+ kcm_log(0, "%s credentials in cache %s for principal %s",
+ (event->action == KCM_EVENT_ACQUIRE_CREDS) ?
+ "Acquired" : "Renewed",
+ event->ccache->name,
+ (cpn != NULL) ? cpn : "<none>");
+
+ if (cpn != NULL)
+ free(cpn);
+
+ /* Succeeded, but possibly replaced with another event */
+ ret = kcm_ccache_make_default_event(context, event, credp);
+ if (ret || event->action == KCM_EVENT_NONE)
+ oneshot = 1;
+ else
+ log_event(event, "requeuing");
+ }
+ if (oneshot)
+ kcm_remove_event_internal(context, e);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+kcm_run_events(krb5_context context,
+ time_t now)
+{
+ krb5_error_code ret;
+ kcm_event **e;
+
+ HEIMDAL_MUTEX_lock(&events_mutex);
+
+ /* Only run event queue every N seconds */
+ if (now < last_run + KCM_EVENT_QUEUE_INTERVAL) {
+ HEIMDAL_MUTEX_unlock(&events_mutex);
+ return 0;
+ }
+
+ /* go through events list, fire and expire */
+ for (e = &events_head; *e != NULL; e = &(*e)->next) {
+ if ((*e)->valid == 0)
+ continue;
+
+ if (now >= (*e)->fire_time) {
+ ret = kcm_fire_event(context, e);
+ if (ret) {
+ kcm_log(1, "Could not fire event for cache %s: %s",
+ (*e)->ccache->name, krb5_get_err_text(context, ret));
+ }
+ } else if ((*e)->expire_time && now >= (*e)->expire_time) {
+ ret = kcm_remove_event_internal(context, e);
+ if (ret) {
+ kcm_log(1, "Could not expire event for cache %s: %s",
+ (*e)->ccache->name, krb5_get_err_text(context, ret));
+ }
+ }
+
+ if (*e == NULL)
+ break;
+ }
+
+ last_run = now;
+
+ HEIMDAL_MUTEX_unlock(&events_mutex);
+
+ return 0;
+}
+
diff --git a/crypto/heimdal/kcm/glue.c b/crypto/heimdal/kcm/glue.c
new file mode 100644
index 0000000..be217f3
--- /dev/null
+++ b/crypto/heimdal/kcm/glue.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: glue.c 14566 2005-02-06 01:22:49Z lukeh $");
+
+/*
+ * Server-side loopback glue for credentials cache operations; this
+ * must be initialized with kcm_internal_ccache(), it is not for real
+ * use. This entire file assumes the cache is locked, it does not do
+ * any concurrency checking for multithread applications.
+ */
+
+#define KCMCACHE(X) ((kcm_ccache)(X)->data.data)
+#define CACHENAME(X) (KCMCACHE(X)->name)
+
+static const char *
+kcmss_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ return CACHENAME(id);
+}
+
+static krb5_error_code
+kcmss_resolve(krb5_context context, krb5_ccache *id, const char *res)
+{
+ return KRB5_FCC_INTERNAL;
+}
+
+static krb5_error_code
+kcmss_gen_new(krb5_context context, krb5_ccache *id)
+{
+ return KRB5_FCC_INTERNAL;
+}
+
+static krb5_error_code
+kcmss_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ ret = kcm_zero_ccache_data_internal(context, c);
+ if (ret)
+ return ret;
+
+ ret = krb5_copy_principal(context, primary_principal,
+ &c->client);
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_close(krb5_context context,
+ krb5_ccache id)
+{
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ id->data.data = NULL;
+ id->data.length = 0;
+
+ return 0;
+}
+
+static krb5_error_code
+kcmss_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ ret = kcm_ccache_destroy(context, CACHENAME(id));
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+ krb5_creds *tmp;
+
+ KCM_ASSERT_VALID(c);
+
+ ret = kcm_ccache_store_cred_internal(context, c, creds, 1, &tmp);
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_retrieve(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ const krb5_creds *mcred,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+ krb5_creds *credp;
+
+ KCM_ASSERT_VALID(c);
+
+ ret = kcm_ccache_retrieve_cred_internal(context, c, which,
+ mcred, &credp);
+ if (ret)
+ return ret;
+
+ ret = krb5_copy_creds_contents(context, credp, creds);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static krb5_error_code
+kcmss_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ ret = krb5_copy_principal(context, c->client,
+ principal);
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_get_first (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ *cursor = c->creds;
+
+ return (*cursor == NULL) ? KRB5_CC_END : 0;
+}
+
+static krb5_error_code
+kcmss_get_next (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ ret = krb5_copy_creds_contents(context,
+ &((struct kcm_creds *)cursor)->cred,
+ creds);
+ if (ret)
+ return ret;
+
+ *cursor = ((struct kcm_creds *)cursor)->next;
+ if (*cursor == 0)
+ ret = KRB5_CC_END;
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ *cursor = NULL;
+ return 0;
+}
+
+static krb5_error_code
+kcmss_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *cred)
+{
+ krb5_error_code ret;
+ kcm_ccache c = KCMCACHE(id);
+
+ KCM_ASSERT_VALID(c);
+
+ ret = kcm_ccache_remove_cred_internal(context, c, which, cred);
+
+ return ret;
+}
+
+static krb5_error_code
+kcmss_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ return 0;
+}
+
+static krb5_error_code
+kcmss_get_version(krb5_context context,
+ krb5_ccache id)
+{
+ return 0;
+}
+
+static const krb5_cc_ops krb5_kcmss_ops = {
+ "KCM",
+ kcmss_get_name,
+ kcmss_resolve,
+ kcmss_gen_new,
+ kcmss_initialize,
+ kcmss_destroy,
+ kcmss_close,
+ kcmss_store_cred,
+ kcmss_retrieve,
+ kcmss_get_principal,
+ kcmss_get_first,
+ kcmss_get_next,
+ kcmss_end_get,
+ kcmss_remove_cred,
+ kcmss_set_flags,
+ kcmss_get_version
+};
+
+krb5_error_code
+kcm_internal_ccache(krb5_context context,
+ kcm_ccache c,
+ krb5_ccache id)
+{
+ id->ops = &krb5_kcmss_ops;
+ id->data.length = sizeof(*c);
+ id->data.data = c;
+
+ return 0;
+}
+
diff --git a/crypto/heimdal/kcm/headers.h b/crypto/heimdal/kcm/headers.h
new file mode 100644
index 0000000..1042dd8
--- /dev/null
+++ b/crypto/heimdal/kcm/headers.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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.
+ */
+
+#ifndef __HEADERS_H__
+#define __HEADERS_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#ifdef HAVE_GETPEERUCRED
+#include <ucred.h>
+#endif
+#ifdef HAVE_DOOR_CREATE
+#include <door.h>
+#include <alloca.h>
+#endif
+#include <err.h>
+#include <roken.h>
+#include <getarg.h>
+#include <base64.h>
+#include <parse_units.h>
+#include <krb5.h>
+#include <krb5_locl.h>
+
+#endif /* __HEADERS_H__ */
+
diff --git a/crypto/heimdal/kcm/kcm.8 b/crypto/heimdal/kcm/kcm.8
new file mode 100644
index 0000000..4a72eb3
--- /dev/null
+++ b/crypto/heimdal/kcm/kcm.8
@@ -0,0 +1,224 @@
+.\" Copyright (c) 2005 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: kcm.8 15497 2005-06-20 13:32:44Z lha $
+.\"
+.Dd May 29, 2005
+.Dt KCM 8
+.Os Heimdal
+.Sh NAME
+.Nm kcm
+.Nd
+is a process based credential cache for Kerberos tickets.
+.Sh SYNOPSIS
+.Nm
+.Op Fl -cache-name= Ns Ar cachename
+.Oo Fl c Ar file \*(Ba Xo
+.Fl -config-file= Ns Ar file
+.Xc
+.Oc
+.Oo Fl g Ar group \*(Ba Xo
+.Fl -group= Ns Ar group
+.Xc
+.Oc
+.Op Fl -max-request= Ns Ar size
+.Op Fl -disallow-getting-krbtgt
+.Op Fl -detach
+.Op Fl h | Fl -help
+.Oo Fl k Ar principal \*(Ba Xo
+.Fl -system-principal= Ns Ar principal
+.Xc
+.Oc
+.Oo Fl l Ar time \*(Ba Xo
+.Fl -lifetime= Ns Ar time
+.Xc
+.Oc
+.Oo Fl m Ar mode \*(Ba Xo
+.Fl -mode= Ns Ar mode
+.Xc
+.Oc
+.Op Fl n | Fl -no-name-constraints
+.Oo Fl r Ar time \*(Ba Xo
+.Fl -renewable-life= Ns Ar time
+.Xc
+.Oc
+.Oo Fl s Ar path \*(Ba Xo
+.Fl -socket-path= Ns Ar path
+.Xc
+.Oc
+.Oo Xo
+.Fl -door-path= Ns Ar path
+.Xc
+.Oc
+.Oo Fl S Ar principal \*(Ba Xo
+.Fl -server= Ns Ar principal
+.Xc
+.Oc
+.Oo Fl t Ar keytab \*(Ba Xo
+.Fl -keytab= Ns Ar keytab
+.Xc
+.Oc
+.Oo Fl u Ar user \*(Ba Xo
+.Fl -user= Ns Ar user
+.Xc
+.Oc
+.Op Fl v | Fl -version
+.Sh DESCRIPTION
+.Nm
+is a process based credential cache.
+To use it, set the
+.Ev KRB5CCNAME
+enviroment variable to
+.Ql KCM: Ns Ar uid
+or add the stanza
+.Bd -literal
+
+[libdefaults]
+ default_cc_name = KCM:%{uid}
+
+.Ed
+to the
+.Pa /etc/krb5.conf
+configuration file and make sure
+.Nm kcm
+is started in the system startup files.
+.Pp
+The
+.Nm
+daemon can hold the credentials for all users in the system. Access
+control is done with Unix-like permissions. The daemon checks the
+access on all operations based on the uid and gid of the user. The
+tickets are renewed as long as is permitted by the KDC's policy.
+.Pp
+The
+.Nm
+daemon can also keep a SYSTEM credential that server processes can
+use to access services. One example of usage might be an nss_ldap
+module that quickly needs to get credentials and doesn't want to renew
+the ticket itself.
+.Pp
+Supported options:
+.Bl -tag -width Ds
+.It Xo
+.Fl -cache-name= Ns Ar cachename
+.Xc
+system cache name
+.It Xo
+.Fl c Ar file ,
+.Fl -config-file= Ns Ar file
+.Xc
+location of config file
+.It Xo
+.Fl g Ar group ,
+.Fl -group= Ns Ar group
+.Xc
+system cache group
+.It Xo
+.Fl -max-request= Ns Ar size
+.Xc
+max size for a kcm-request
+.It Xo
+.Fl -disallow-getting-krbtgt
+.Xc
+disallow extracting any krbtgt from the
+.Nm kcm
+daemon.
+.It Xo
+.Fl -detach
+.Xc
+detach from console
+.It Xo
+.Fl h ,
+.Fl -help
+.Xc
+.It Xo
+.Fl k Ar principal ,
+.Fl -system-principal= Ns Ar principal
+.Xc
+system principal name
+.It Xo
+.Fl l Ar time ,
+.Fl -lifetime= Ns Ar time
+.Xc
+lifetime of system tickets
+.It Xo
+.Fl m Ar mode ,
+.Fl -mode= Ns Ar mode
+.Xc
+octal mode of system cache
+.It Xo
+.Fl n ,
+.Fl -no-name-constraints
+.Xc
+disable credentials cache name constraints
+.It Xo
+.Fl r Ar time ,
+.Fl -renewable-life= Ns Ar time
+.Xc
+renewable lifetime of system tickets
+.It Xo
+.Fl s Ar path ,
+.Fl -socket-path= Ns Ar path
+.Xc
+path to kcm domain socket
+.It Xo
+.Fl -door-path= Ns Ar path
+.Xc
+path to kcm door socket
+.It Xo
+.Fl S Ar principal ,
+.Fl -server= Ns Ar principal
+.Xc
+server to get system ticket for
+.It Xo
+.Fl t Ar keytab ,
+.Fl -keytab= Ns Ar keytab
+.Xc
+system keytab name
+.It Xo
+.Fl u Ar user ,
+.Fl -user= Ns Ar user
+.Xc
+system cache owner
+.It Xo
+.Fl v ,
+.Fl -version
+.Xc
+.El
+.\".Sh ENVIRONMENT
+.\".Sh FILES
+.\".Sh EXAMPLES
+.\".Sh DIAGNOSTICS
+.\".Sh SEE ALSO
+.\".Sh STANDARDS
+.\".Sh HISTORY
+.\".Sh AUTHORS
+.\".Sh BUGS
diff --git a/crypto/heimdal/kcm/kcm_locl.h b/crypto/heimdal/kcm/kcm_locl.h
new file mode 100644
index 0000000..75e55ee
--- /dev/null
+++ b/crypto/heimdal/kcm/kcm_locl.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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.
+ */
+
+/*
+ * $Id: kcm_locl.h 20470 2007-04-20 10:41:11Z lha $
+ */
+
+#ifndef __KCM_LOCL_H__
+#define __KCM_LOCL_H__
+
+#include "headers.h"
+
+#include <kcm.h>
+
+#define KCM_LOG_REQUEST(_context, _client, _opcode) do { \
+ kcm_log(1, "%s request by process %d/uid %d", \
+ kcm_op2string(_opcode), (_client)->pid, (_client)->uid); \
+ } while (0)
+
+#define KCM_LOG_REQUEST_NAME(_context, _client, _opcode, _name) do { \
+ kcm_log(1, "%s request for cache %s by process %d/uid %d", \
+ kcm_op2string(_opcode), (_name), (_client)->pid, (_client)->uid); \
+ } while (0)
+
+/* Cache management */
+
+#define KCM_FLAGS_VALID 0x0001
+#define KCM_FLAGS_USE_KEYTAB 0x0002
+#define KCM_FLAGS_RENEWABLE 0x0004
+#define KCM_FLAGS_OWNER_IS_SYSTEM 0x0008
+#define KCM_FLAGS_USE_CACHED_KEY 0x0010
+
+#define KCM_MASK_KEY_PRESENT ( KCM_FLAGS_USE_KEYTAB | \
+ KCM_FLAGS_USE_CACHED_KEY )
+
+struct kcm_ccache_data;
+struct kcm_creds;
+
+typedef struct kcm_cursor {
+ pid_t pid;
+ uint32_t key;
+ struct kcm_creds *credp; /* pointer to next credential */
+ struct kcm_cursor *next;
+} kcm_cursor;
+
+typedef struct kcm_ccache_data {
+ char *name;
+ unsigned refcnt;
+ uint16_t flags;
+ uint16_t mode;
+ uid_t uid;
+ gid_t gid;
+ krb5_principal client; /* primary client principal */
+ krb5_principal server; /* primary server principal (TGS if NULL) */
+ struct kcm_creds {
+ krb5_creds cred; /* XXX would be useful for have ACLs on creds */
+ struct kcm_creds *next;
+ } *creds;
+ uint32_t n_cursor;
+ kcm_cursor *cursors;
+ krb5_deltat tkt_life;
+ krb5_deltat renew_life;
+ union {
+ krb5_keytab keytab;
+ krb5_keyblock keyblock;
+ } key;
+ HEIMDAL_MUTEX mutex;
+ struct kcm_ccache_data *next;
+} kcm_ccache_data;
+
+#define KCM_ASSERT_VALID(_ccache) do { \
+ if (((_ccache)->flags & KCM_FLAGS_VALID) == 0) \
+ krb5_abortx(context, "kcm_free_ccache_data: ccache invalid"); \
+ else if ((_ccache)->refcnt == 0) \
+ krb5_abortx(context, "kcm_free_ccache_data: ccache refcnt == 0"); \
+ } while (0)
+
+typedef kcm_ccache_data *kcm_ccache;
+
+/* Event management */
+
+typedef struct kcm_event {
+ int valid;
+ time_t fire_time;
+ unsigned fire_count;
+ time_t expire_time;
+ time_t backoff_time;
+ enum {
+ KCM_EVENT_NONE = 0,
+ KCM_EVENT_ACQUIRE_CREDS,
+ KCM_EVENT_RENEW_CREDS,
+ KCM_EVENT_DESTROY_CREDS,
+ KCM_EVENT_DESTROY_EMPTY_CACHE
+ } action;
+ kcm_ccache ccache;
+ struct kcm_event *next;
+} kcm_event;
+
+/* wakeup interval for event queue */
+#define KCM_EVENT_QUEUE_INTERVAL 60
+#define KCM_EVENT_DEFAULT_BACKOFF_TIME 5
+#define KCM_EVENT_MAX_BACKOFF_TIME (12 * 60 * 60)
+
+
+/* Request format is LENGTH | MAJOR | MINOR | OPERATION | request */
+/* Response format is LENGTH | STATUS | response */
+
+typedef struct kcm_client {
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+} kcm_client;
+
+#define CLIENT_IS_ROOT(client) ((client)->uid == 0)
+
+/* Dispatch table */
+/* passed in OPERATION | ... ; returns STATUS | ... */
+typedef krb5_error_code (*kcm_method)(krb5_context, kcm_client *, kcm_operation, krb5_storage *, krb5_storage *);
+
+struct kcm_op {
+ const char *name;
+ kcm_method method;
+};
+
+#define DEFAULT_LOG_DEST "0/FILE:" LOCALSTATEDIR "/log/kcmd.log"
+#define _PATH_KCM_CONF SYSCONFDIR "/kcm.conf"
+
+extern krb5_context kcm_context;
+extern char *socket_path;
+extern char *door_path;
+extern size_t max_request;
+extern sig_atomic_t exit_flag;
+extern int name_constraints;
+extern int detach_from_console;
+extern int disallow_getting_krbtgt;
+
+#if 0
+extern const krb5_cc_ops krb5_kcmss_ops;
+#endif
+
+#include <kcm_protos.h>
+
+#endif /* __KCM_LOCL_H__ */
+
diff --git a/crypto/heimdal/kcm/kcm_protos.h b/crypto/heimdal/kcm/kcm_protos.h
new file mode 100644
index 0000000..0fcea75
--- /dev/null
+++ b/crypto/heimdal/kcm/kcm_protos.h
@@ -0,0 +1,288 @@
+/* This is a generated file */
+#ifndef __kcm_protos_h__
+#define __kcm_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+krb5_error_code
+kcm_access (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ kcm_operation /*opcode*/,
+ kcm_ccache /*ccache*/);
+
+krb5_error_code
+kcm_ccache_acquire (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_creds **/*credp*/);
+
+krb5_error_code
+kcm_ccache_destroy (
+ krb5_context /*context*/,
+ const char */*name*/);
+
+krb5_error_code
+kcm_ccache_destroy_client (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ const char */*name*/);
+
+krb5_error_code
+kcm_ccache_destroy_if_empty (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/);
+
+krb5_error_code
+kcm_ccache_enqueue_default (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_creds */*newcred*/);
+
+krb5_error_code
+kcm_ccache_gen_new (
+ krb5_context /*context*/,
+ pid_t /*pid*/,
+ uid_t /*uid*/,
+ gid_t /*gid*/,
+ kcm_ccache */*ccache*/);
+
+krb5_error_code
+kcm_ccache_new (
+ krb5_context /*context*/,
+ const char */*name*/,
+ kcm_ccache */*ccache*/);
+
+krb5_error_code
+kcm_ccache_new_client (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ const char */*name*/,
+ kcm_ccache */*ccache_p*/);
+
+char *kcm_ccache_nextid (
+ pid_t /*pid*/,
+ uid_t /*uid*/,
+ gid_t /*gid*/);
+
+krb5_error_code
+kcm_ccache_refresh (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_creds **/*credp*/);
+
+krb5_error_code
+kcm_ccache_remove_cred (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds */*mcreds*/);
+
+krb5_error_code
+kcm_ccache_remove_cred_internal (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds */*mcreds*/);
+
+krb5_error_code
+kcm_ccache_remove_creds (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/);
+
+krb5_error_code
+kcm_ccache_remove_creds_internal (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/);
+
+krb5_error_code
+kcm_ccache_resolve (
+ krb5_context /*context*/,
+ const char */*name*/,
+ kcm_ccache */*ccache*/);
+
+krb5_error_code
+kcm_ccache_resolve_client (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ kcm_operation /*opcode*/,
+ const char */*name*/,
+ kcm_ccache */*ccache*/);
+
+krb5_error_code
+kcm_ccache_retrieve_cred (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds */*mcreds*/,
+ krb5_creds **/*credp*/);
+
+krb5_error_code
+kcm_ccache_retrieve_cred_internal (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds */*mcreds*/,
+ krb5_creds **/*creds*/);
+
+krb5_error_code
+kcm_ccache_store_cred (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_creds */*creds*/,
+ int /*copy*/);
+
+krb5_error_code
+kcm_ccache_store_cred_internal (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/,
+ krb5_creds */*creds*/,
+ int /*copy*/,
+ krb5_creds **/*credp*/);
+
+krb5_error_code
+kcm_chmod (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ kcm_ccache /*ccache*/,
+ uint16_t /*mode*/);
+
+krb5_error_code
+kcm_chown (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ kcm_ccache /*ccache*/,
+ uid_t /*uid*/,
+ gid_t /*gid*/);
+
+krb5_error_code
+kcm_cleanup_events (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/);
+
+void
+kcm_configure (
+ int /*argc*/,
+ char **/*argv*/);
+
+krb5_error_code
+kcm_cursor_delete (
+ krb5_context /*context*/,
+ pid_t /*pid*/,
+ kcm_ccache /*ccache*/,
+ uint32_t /*key*/);
+
+krb5_error_code
+kcm_cursor_find (
+ krb5_context /*context*/,
+ pid_t /*pid*/,
+ kcm_ccache /*ccache*/,
+ uint32_t /*key*/,
+ kcm_cursor **/*cursor*/);
+
+krb5_error_code
+kcm_cursor_new (
+ krb5_context /*context*/,
+ pid_t /*pid*/,
+ kcm_ccache /*ccache*/,
+ uint32_t */*cursor*/);
+
+krb5_error_code
+kcm_debug_ccache (krb5_context /*context*/);
+
+krb5_error_code
+kcm_debug_events (krb5_context /*context*/);
+
+krb5_error_code
+kcm_dispatch (
+ krb5_context /*context*/,
+ kcm_client */*client*/,
+ krb5_data */*req_data*/,
+ krb5_data */*resp_data*/);
+
+krb5_error_code
+kcm_enqueue_event (
+ krb5_context /*context*/,
+ kcm_event */*event*/);
+
+krb5_error_code
+kcm_enqueue_event_internal (
+ krb5_context /*context*/,
+ kcm_event */*event*/);
+
+krb5_error_code
+kcm_enqueue_event_relative (
+ krb5_context /*context*/,
+ kcm_event */*event*/);
+
+krb5_error_code
+kcm_internal_ccache (
+ krb5_context /*context*/,
+ kcm_ccache /*c*/,
+ krb5_ccache /*id*/);
+
+void
+kcm_log (
+ int /*level*/,
+ const char */*fmt*/,
+ ...);
+
+char*
+kcm_log_msg (
+ int /*level*/,
+ const char */*fmt*/,
+ ...);
+
+char*
+kcm_log_msg_va (
+ int /*level*/,
+ const char */*fmt*/,
+ va_list /*ap*/);
+
+void
+kcm_loop (void);
+
+const char *kcm_op2string (kcm_operation /*opcode*/);
+
+void
+kcm_openlog (void);
+
+krb5_error_code
+kcm_release_ccache (
+ krb5_context /*context*/,
+ kcm_ccache */*ccache*/);
+
+krb5_error_code
+kcm_remove_event (
+ krb5_context /*context*/,
+ kcm_event */*event*/);
+
+krb5_error_code
+kcm_retain_ccache (
+ krb5_context /*context*/,
+ kcm_ccache /*ccache*/);
+
+krb5_error_code
+kcm_run_events (
+ krb5_context /*context*/,
+ time_t /*now*/);
+
+krb5_error_code
+kcm_zero_ccache_data (
+ krb5_context /*context*/,
+ kcm_ccache /*cache*/);
+
+krb5_error_code
+kcm_zero_ccache_data_internal (
+ krb5_context /*context*/,
+ kcm_ccache_data */*cache*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __kcm_protos_h__ */
diff --git a/crypto/heimdal/kcm/log.c b/crypto/heimdal/kcm/log.c
new file mode 100644
index 0000000..351782e
--- /dev/null
+++ b/crypto/heimdal/kcm/log.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 1998, 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kcm_locl.h"
+
+RCSID("$Id: log.c 14566 2005-02-06 01:22:49Z lukeh $");
+
+static krb5_log_facility *logf;
+
+void
+kcm_openlog(void)
+{
+ char **s = NULL, **p;
+ krb5_initlog(kcm_context, "kcm", &logf);
+ s = krb5_config_get_strings(kcm_context, NULL, "kcm", "logging", NULL);
+ if(s == NULL)
+ s = krb5_config_get_strings(kcm_context, NULL, "logging", "kcm", NULL);
+ if(s){
+ for(p = s; *p; p++)
+ krb5_addlog_dest(kcm_context, logf, *p);
+ krb5_config_free_strings(s);
+ }else
+ krb5_addlog_dest(kcm_context, logf, DEFAULT_LOG_DEST);
+ krb5_set_warn_dest(kcm_context, logf);
+}
+
+char*
+kcm_log_msg_va(int level, const char *fmt, va_list ap)
+{
+ char *msg;
+ krb5_vlog_msg(kcm_context, logf, &msg, level, fmt, ap);
+ return msg;
+}
+
+char*
+kcm_log_msg(int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *s;
+ va_start(ap, fmt);
+ s = kcm_log_msg_va(level, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+void
+kcm_log(int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *s;
+ va_start(ap, fmt);
+ s = kcm_log_msg_va(level, fmt, ap);
+ if(s) free(s);
+ va_end(ap);
+}
diff --git a/crypto/heimdal/kcm/main.c b/crypto/heimdal/kcm/main.c
new file mode 100644
index 0000000..da88a2c
--- /dev/null
+++ b/crypto/heimdal/kcm/main.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kcm_locl.h"
+
+RCSID("$Id: main.c 15298 2005-05-30 10:58:14Z lha $");
+
+sig_atomic_t exit_flag = 0;
+
+krb5_context kcm_context = NULL;
+
+static RETSIGTYPE
+sigterm(int sig)
+{
+ exit_flag = 1;
+}
+
+static RETSIGTYPE
+sigusr1(int sig)
+{
+ kcm_debug_ccache(kcm_context);
+}
+
+static RETSIGTYPE
+sigusr2(int sig)
+{
+ kcm_debug_events(kcm_context);
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_error_code ret;
+ setprogname(argv[0]);
+
+ ret = krb5_init_context(&kcm_context);
+ if (ret) {
+ errx (1, "krb5_init_context failed: %d", ret);
+ return ret;
+ }
+
+ kcm_configure(argc, argv);
+
+#ifdef HAVE_SIGACTION
+ {
+ struct sigaction sa;
+
+ sa.sa_flags = 0;
+ sa.sa_handler = sigterm;
+ sigemptyset(&sa.sa_mask);
+
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ sa.sa_handler = sigusr1;
+ sigaction(SIGUSR1, &sa, NULL);
+
+ sa.sa_handler = sigusr2;
+ sigaction(SIGUSR2, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+ }
+#else
+ signal(SIGINT, sigterm);
+ signal(SIGTERM, sigterm);
+ signal(SIGUSR1, sigusr1);
+ signal(SIGUSR2, sigusr2);
+ signal(SIGPIPE, SIG_IGN);
+#endif
+ if (detach_from_console)
+ daemon(0, 0);
+ pidfile(NULL);
+ kcm_loop();
+ krb5_free_context(kcm_context);
+ return 0;
+}
diff --git a/crypto/heimdal/kcm/protocol.c b/crypto/heimdal/kcm/protocol.c
new file mode 100644
index 0000000..bb3c653
--- /dev/null
+++ b/crypto/heimdal/kcm/protocol.c
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: protocol.c 22112 2007-12-03 19:34:33Z lha $");
+
+static krb5_error_code
+kcm_op_noop(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ KCM_LOG_REQUEST(context, client, opcode);
+
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Response:
+ * NameZ
+ *
+ */
+static krb5_error_code
+kcm_op_get_name(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+
+{
+ krb5_error_code ret;
+ char *name = NULL;
+ kcm_ccache ccache;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_store_stringz(response, ccache->name);
+ if (ret) {
+ kcm_release_ccache(context, &ccache);
+ free(name);
+ return ret;
+ }
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+ return 0;
+}
+
+/*
+ * Request:
+ *
+ * Response:
+ * NameZ
+ */
+static krb5_error_code
+kcm_op_gen_new(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ char *name;
+
+ KCM_LOG_REQUEST(context, client, opcode);
+
+ name = kcm_ccache_nextid(client->pid, client->uid, client->gid);
+ if (name == NULL) {
+ return KRB5_CC_NOMEM;
+ }
+
+ ret = krb5_store_stringz(response, name);
+ free(name);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Principal
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_initialize(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ kcm_ccache ccache;
+ krb5_principal principal;
+ krb5_error_code ret;
+ char *name;
+#if 0
+ kcm_event event;
+#endif
+
+ KCM_LOG_REQUEST(context, client, opcode);
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ ret = krb5_ret_principal(request, &principal);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_new_client(context, client, name, &ccache);
+ if (ret) {
+ free(name);
+ krb5_free_principal(context, principal);
+ return ret;
+ }
+
+ ccache->client = principal;
+
+ free(name);
+
+#if 0
+ /*
+ * Create a new credentials cache. To mitigate DoS attacks we will
+ * expire it in 30 minutes unless it has some credentials added
+ * to it
+ */
+
+ event.fire_time = 30 * 60;
+ event.expire_time = 0;
+ event.backoff_time = 0;
+ event.action = KCM_EVENT_DESTROY_EMPTY_CACHE;
+ event.ccache = ccache;
+
+ ret = kcm_enqueue_event_relative(context, &event);
+#endif
+
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_destroy(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = kcm_ccache_destroy_client(context, client, name);
+
+ free(name);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Creds
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_store(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_creds creds;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_creds(request, &creds);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ krb5_free_cred_contents(context, &creds);
+ return ret;
+ }
+
+ ret = kcm_ccache_store_cred(context, ccache, &creds, 0);
+ if (ret) {
+ free(name);
+ krb5_free_cred_contents(context, &creds);
+ kcm_release_ccache(context, &ccache);
+ return ret;
+ }
+
+ kcm_ccache_enqueue_default(context, ccache, &creds);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ * WhichFields
+ * MatchCreds
+ *
+ * Response:
+ * Creds
+ *
+ */
+static krb5_error_code
+kcm_op_retrieve(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ uint32_t flags;
+ krb5_creds mcreds;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+ krb5_creds *credp;
+ int free_creds = 0;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &flags);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_ret_creds_tag(request, &mcreds);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ if (disallow_getting_krbtgt &&
+ mcreds.server->name.name_string.len == 2 &&
+ strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0)
+ {
+ free(name);
+ krb5_free_cred_contents(context, &mcreds);
+ return KRB5_FCC_PERM;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ krb5_free_cred_contents(context, &mcreds);
+ return ret;
+ }
+
+ ret = kcm_ccache_retrieve_cred(context, ccache, flags,
+ &mcreds, &credp);
+ if (ret && ((flags & KRB5_GC_CACHED) == 0)) {
+ krb5_ccache_data ccdata;
+
+ /* try and acquire */
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ /* Fake up an internal ccache */
+ kcm_internal_ccache(context, ccache, &ccdata);
+
+ /* glue cc layer will store creds */
+ ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp);
+ if (ret == 0)
+ free_creds = 1;
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+ }
+
+ if (ret == 0) {
+ ret = krb5_store_creds(response, credp);
+ }
+
+ free(name);
+ krb5_free_cred_contents(context, &mcreds);
+ kcm_release_ccache(context, &ccache);
+
+ if (free_creds)
+ krb5_free_cred_contents(context, credp);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ * Principal
+ */
+static krb5_error_code
+kcm_op_get_principal(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ if (ccache->client == NULL)
+ ret = KRB5_CC_NOTFOUND;
+ else
+ ret = krb5_store_principal(response, ccache->client);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ * Cursor
+ *
+ */
+static krb5_error_code
+kcm_op_get_first(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ uint32_t cursor;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_cursor_new(context, client->pid, ccache, &cursor);
+ if (ret) {
+ kcm_release_ccache(context, &ccache);
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_store_int32(response, cursor);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Cursor
+ *
+ * Response:
+ * Creds
+ */
+static krb5_error_code
+kcm_op_get_next(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+ uint32_t cursor;
+ kcm_cursor *c;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &cursor);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_cursor_find(context, client->pid, ccache, cursor, &c);
+ if (ret) {
+ kcm_release_ccache(context, &ccache);
+ free(name);
+ return ret;
+ }
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+ if (c->credp == NULL) {
+ ret = KRB5_CC_END;
+ } else {
+ ret = krb5_store_creds(response, &c->credp->cred);
+ c->credp = c->credp->next;
+ }
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Cursor
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_end_get(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ uint32_t cursor;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &cursor);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_cursor_delete(context, client->pid, ccache, cursor);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * WhichFields
+ * MatchCreds
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_remove_cred(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ uint32_t whichfields;
+ krb5_creds mcreds;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &whichfields);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_ret_creds_tag(request, &mcreds);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ krb5_free_cred_contents(context, &mcreds);
+ return ret;
+ }
+
+ ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
+
+ /* XXX need to remove any events that match */
+
+ free(name);
+ krb5_free_cred_contents(context, &mcreds);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Flags
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_set_flags(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ uint32_t flags;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &flags);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ /* we don't really support any flags yet */
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ * UID
+ * GID
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_chown(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ uint32_t uid;
+ uint32_t gid;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &uid);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_ret_uint32(request, &gid);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_chown(context, client, ccache, uid, gid);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Mode
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_op_chmod(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ uint16_t mode;
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint16(request, &mode);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_chmod(context, client, ccache, mode);
+
+ free(name);
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Protocol extensions for moving ticket acquisition responsibility
+ * from client to KCM follow.
+ */
+
+/*
+ * Request:
+ * NameZ
+ * ServerPrincipalPresent
+ * ServerPrincipal OPTIONAL
+ * Key
+ *
+ * Repsonse:
+ *
+ */
+static krb5_error_code
+kcm_op_get_initial_ticket(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+ int8_t not_tgt = 0;
+ krb5_principal server = NULL;
+ krb5_keyblock key;
+
+ krb5_keyblock_zero(&key);
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_int8(request, &not_tgt);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ if (not_tgt) {
+ ret = krb5_ret_principal(request, &server);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+ }
+
+ ret = krb5_ret_keyblock(request, &key);
+ if (ret) {
+ free(name);
+ if (server != NULL)
+ krb5_free_principal(context, server);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret == 0) {
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ if (ccache->server != NULL) {
+ krb5_free_principal(context, ccache->server);
+ ccache->server = NULL;
+ }
+
+ krb5_free_keyblock(context, &ccache->key.keyblock);
+
+ ccache->server = server;
+ ccache->key.keyblock = key;
+ ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
+
+ ret = kcm_ccache_enqueue_default(context, ccache, NULL);
+ if (ret) {
+ ccache->server = NULL;
+ krb5_keyblock_zero(&ccache->key.keyblock);
+ ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
+ }
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+ }
+
+ free(name);
+
+ if (ret != 0) {
+ krb5_free_principal(context, server);
+ krb5_free_keyblock(context, &key);
+ }
+
+ kcm_release_ccache(context, &ccache);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * ServerPrincipal
+ * KDCFlags
+ * EncryptionType
+ *
+ * Repsonse:
+ *
+ */
+static krb5_error_code
+kcm_op_get_ticket(krb5_context context,
+ kcm_client *client,
+ kcm_operation opcode,
+ krb5_storage *request,
+ krb5_storage *response)
+{
+ krb5_error_code ret;
+ kcm_ccache ccache;
+ char *name;
+ krb5_principal server = NULL;
+ krb5_ccache_data ccdata;
+ krb5_creds in, *out;
+ krb5_kdc_flags flags;
+
+ memset(&in, 0, sizeof(in));
+
+ ret = krb5_ret_stringz(request, &name);
+ if (ret)
+ return ret;
+
+ KCM_LOG_REQUEST_NAME(context, client, opcode, name);
+
+ ret = krb5_ret_uint32(request, &flags.i);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_ret_int32(request, &in.session.keytype);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = krb5_ret_principal(request, &server);
+ if (ret) {
+ free(name);
+ return ret;
+ }
+
+ ret = kcm_ccache_resolve_client(context, client, opcode,
+ name, &ccache);
+ if (ret) {
+ krb5_free_principal(context, server);
+ free(name);
+ return ret;
+ }
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ /* Fake up an internal ccache */
+ kcm_internal_ccache(context, ccache, &ccdata);
+
+ in.client = ccache->client;
+ in.server = server;
+ in.times.endtime = 0;
+
+ /* glue cc layer will store creds */
+ ret = krb5_get_credentials_with_flags(context, 0, flags,
+ &ccdata, &in, &out);
+
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ if (ret == 0)
+ krb5_free_cred_contents(context, out);
+
+ free(name);
+
+ return ret;
+}
+
+static struct kcm_op kcm_ops[] = {
+ { "NOOP", kcm_op_noop },
+ { "GET_NAME", kcm_op_get_name },
+ { "RESOLVE", kcm_op_noop },
+ { "GEN_NEW", kcm_op_gen_new },
+ { "INITIALIZE", kcm_op_initialize },
+ { "DESTROY", kcm_op_destroy },
+ { "STORE", kcm_op_store },
+ { "RETRIEVE", kcm_op_retrieve },
+ { "GET_PRINCIPAL", kcm_op_get_principal },
+ { "GET_FIRST", kcm_op_get_first },
+ { "GET_NEXT", kcm_op_get_next },
+ { "END_GET", kcm_op_end_get },
+ { "REMOVE_CRED", kcm_op_remove_cred },
+ { "SET_FLAGS", kcm_op_set_flags },
+ { "CHOWN", kcm_op_chown },
+ { "CHMOD", kcm_op_chmod },
+ { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket },
+ { "GET_TICKET", kcm_op_get_ticket }
+};
+
+
+const char *kcm_op2string(kcm_operation opcode)
+{
+ if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
+ return "Unknown operation";
+
+ return kcm_ops[opcode].name;
+}
+
+krb5_error_code
+kcm_dispatch(krb5_context context,
+ kcm_client *client,
+ krb5_data *req_data,
+ krb5_data *resp_data)
+{
+ krb5_error_code ret;
+ kcm_method method;
+ krb5_storage *req_sp = NULL;
+ krb5_storage *resp_sp = NULL;
+ uint16_t opcode;
+
+ resp_sp = krb5_storage_emem();
+ if (resp_sp == NULL) {
+ return ENOMEM;
+ }
+
+ if (client->pid == -1) {
+ kcm_log(0, "Client had invalid process number");
+ ret = KRB5_FCC_INTERNAL;
+ goto out;
+ }
+
+ req_sp = krb5_storage_from_data(req_data);
+ if (req_sp == NULL) {
+ kcm_log(0, "Process %d: failed to initialize storage from data",
+ client->pid);
+ ret = KRB5_CC_IO;
+ goto out;
+ }
+
+ ret = krb5_ret_uint16(req_sp, &opcode);
+ if (ret) {
+ kcm_log(0, "Process %d: didn't send a message", client->pid);
+ goto out;
+ }
+
+ if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
+ kcm_log(0, "Process %d: invalid operation code %d",
+ client->pid, opcode);
+ ret = KRB5_FCC_INTERNAL;
+ goto out;
+ }
+ method = kcm_ops[opcode].method;
+
+ /* seek past place for status code */
+ krb5_storage_seek(resp_sp, 4, SEEK_SET);
+
+ ret = (*method)(context, client, opcode, req_sp, resp_sp);
+
+out:
+ if (req_sp != NULL) {
+ krb5_storage_free(req_sp);
+ }
+
+ krb5_storage_seek(resp_sp, 0, SEEK_SET);
+ krb5_store_int32(resp_sp, ret);
+
+ ret = krb5_storage_to_data(resp_sp, resp_data);
+ krb5_storage_free(resp_sp);
+
+ return ret;
+}
+
diff --git a/crypto/heimdal/kcm/renew.c b/crypto/heimdal/kcm/renew.c
new file mode 100644
index 0000000..9450209
--- /dev/null
+++ b/crypto/heimdal/kcm/renew.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "kcm_locl.h"
+
+RCSID("$Id: renew.c 14566 2005-02-06 01:22:49Z lukeh $");
+
+krb5_error_code
+kcm_ccache_refresh(krb5_context context,
+ kcm_ccache ccache,
+ krb5_creds **credp)
+{
+ krb5_error_code ret;
+ krb5_creds in, *out;
+ krb5_kdc_flags flags;
+ krb5_const_realm realm;
+ krb5_ccache_data ccdata;
+
+ memset(&in, 0, sizeof(in));
+
+ KCM_ASSERT_VALID(ccache);
+
+ if (ccache->client == NULL) {
+ /* no primary principal */
+ kcm_log(0, "Refresh credentials requested but no client principal");
+ return KRB5_CC_NOTFOUND;
+ }
+
+ HEIMDAL_MUTEX_lock(&ccache->mutex);
+
+ /* Fake up an internal ccache */
+ kcm_internal_ccache(context, ccache, &ccdata);
+
+ /* Find principal */
+ in.client = ccache->client;
+
+ if (ccache->server != NULL) {
+ ret = krb5_copy_principal(context, ccache->server, &in.server);
+ if (ret) {
+ kcm_log(0, "Failed to copy service principal: %s",
+ krb5_get_err_text(context, ret));
+ goto out;
+ }
+ } else {
+ realm = krb5_principal_get_realm(context, in.client);
+ ret = krb5_make_principal(context, &in.server, realm,
+ KRB5_TGS_NAME, realm, NULL);
+ if (ret) {
+ kcm_log(0, "Failed to make TGS principal for realm %s: %s",
+ realm, krb5_get_err_text(context, ret));
+ goto out;
+ }
+ }
+
+ if (ccache->tkt_life)
+ in.times.endtime = time(NULL) + ccache->tkt_life;
+ if (ccache->renew_life)
+ in.times.renew_till = time(NULL) + ccache->renew_life;
+
+ flags.i = 0;
+ flags.b.renewable = TRUE;
+ flags.b.renew = TRUE;
+
+ ret = krb5_get_kdc_cred(context,
+ &ccdata,
+ flags,
+ NULL,
+ NULL,
+ &in,
+ &out);
+ if (ret) {
+ kcm_log(0, "Failed to renew credentials for cache %s: %s",
+ ccache->name, krb5_get_err_text(context, ret));
+ goto out;
+ }
+
+ /* Swap them in */
+ kcm_ccache_remove_creds_internal(context, ccache);
+
+ ret = kcm_ccache_store_cred_internal(context, ccache, out, 0, credp);
+ if (ret) {
+ kcm_log(0, "Failed to store credentials for cache %s: %s",
+ ccache->name, krb5_get_err_text(context, ret));
+ krb5_free_creds(context, out);
+ goto out;
+ }
+
+ free(out); /* but not contents */
+
+out:
+ HEIMDAL_MUTEX_unlock(&ccache->mutex);
+
+ return ret;
+}
+
OpenPOWER on IntegriCloud