diff options
Diffstat (limited to 'crypto/heimdal/kcm')
-rw-r--r-- | crypto/heimdal/kcm/Makefile.am | 44 | ||||
-rw-r--r-- | crypto/heimdal/kcm/Makefile.in | 868 | ||||
-rw-r--r-- | crypto/heimdal/kcm/acl.c | 180 | ||||
-rw-r--r-- | crypto/heimdal/kcm/acquire.c | 531 | ||||
-rw-r--r-- | crypto/heimdal/kcm/cache.c | 636 | ||||
-rw-r--r-- | crypto/heimdal/kcm/client.c | 185 | ||||
-rw-r--r-- | crypto/heimdal/kcm/config.c | 390 | ||||
-rw-r--r-- | crypto/heimdal/kcm/connect.c | 688 | ||||
-rw-r--r-- | crypto/heimdal/kcm/cursor.c | 151 | ||||
-rw-r--r-- | crypto/heimdal/kcm/events.c | 440 | ||||
-rw-r--r-- | crypto/heimdal/kcm/glue.c | 279 | ||||
-rw-r--r-- | crypto/heimdal/kcm/headers.h | 89 | ||||
-rw-r--r-- | crypto/heimdal/kcm/kcm.8 | 224 | ||||
-rw-r--r-- | crypto/heimdal/kcm/kcm_locl.h | 173 | ||||
-rw-r--r-- | crypto/heimdal/kcm/kcm_protos.h | 288 | ||||
-rw-r--r-- | crypto/heimdal/kcm/log.c | 85 | ||||
-rw-r--r-- | crypto/heimdal/kcm/main.c | 107 | ||||
-rw-r--r-- | crypto/heimdal/kcm/protocol.c | 1046 | ||||
-rw-r--r-- | crypto/heimdal/kcm/renew.c | 124 |
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, ¬_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; +} + |