From 4897093455a2bf08f3db3a1132cc2f6f5484d77c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 08:03:02 +0200 Subject: Adding upstream version 1:2.6.4. Signed-off-by: Daniel Baumann --- utils/gssd/.gitignore | 3 + utils/gssd/Makefile.am | 130 ++++ utils/gssd/Makefile.in | 1356 +++++++++++++++++++++++++++++++++ utils/gssd/context.c | 59 ++ utils/gssd/context.h | 49 ++ utils/gssd/context_heimdal.c | 275 +++++++ utils/gssd/context_lucid.c | 327 ++++++++ utils/gssd/context_mit.c | 280 +++++++ utils/gssd/err_util.c | 86 +++ utils/gssd/err_util.h | 39 + utils/gssd/gss_names.c | 141 ++++ utils/gssd/gss_names.h | 36 + utils/gssd/gss_oids.c | 40 + utils/gssd/gss_oids.h | 44 ++ utils/gssd/gss_util.c | 347 +++++++++ utils/gssd/gss_util.h | 56 ++ utils/gssd/gssd.c | 1320 ++++++++++++++++++++++++++++++++ utils/gssd/gssd.h | 124 +++ utils/gssd/gssd.man | 408 ++++++++++ utils/gssd/gssd_proc.c | 1075 ++++++++++++++++++++++++++ utils/gssd/krb5_util.c | 1649 ++++++++++++++++++++++++++++++++++++++++ utils/gssd/krb5_util.h | 47 ++ utils/gssd/svcgssd.c | 348 +++++++++ utils/gssd/svcgssd.h | 42 + utils/gssd/svcgssd.man | 88 +++ utils/gssd/svcgssd_krb5.c | 237 ++++++ utils/gssd/svcgssd_krb5.h | 37 + utils/gssd/svcgssd_mech2file.c | 74 ++ utils/gssd/svcgssd_proc.c | 444 +++++++++++ utils/gssd/write_bytes.h | 159 ++++ 30 files changed, 9320 insertions(+) create mode 100644 utils/gssd/.gitignore create mode 100644 utils/gssd/Makefile.am create mode 100644 utils/gssd/Makefile.in create mode 100644 utils/gssd/context.c create mode 100644 utils/gssd/context.h create mode 100644 utils/gssd/context_heimdal.c create mode 100644 utils/gssd/context_lucid.c create mode 100644 utils/gssd/context_mit.c create mode 100644 utils/gssd/err_util.c create mode 100644 utils/gssd/err_util.h create mode 100644 utils/gssd/gss_names.c create mode 100644 utils/gssd/gss_names.h create mode 100644 utils/gssd/gss_oids.c create mode 100644 utils/gssd/gss_oids.h create mode 100644 utils/gssd/gss_util.c create mode 100644 utils/gssd/gss_util.h create mode 100644 utils/gssd/gssd.c create mode 100644 utils/gssd/gssd.h create mode 100644 utils/gssd/gssd.man create mode 100644 utils/gssd/gssd_proc.c create mode 100644 utils/gssd/krb5_util.c create mode 100644 utils/gssd/krb5_util.h create mode 100644 utils/gssd/svcgssd.c create mode 100644 utils/gssd/svcgssd.h create mode 100644 utils/gssd/svcgssd.man create mode 100644 utils/gssd/svcgssd_krb5.c create mode 100644 utils/gssd/svcgssd_krb5.h create mode 100644 utils/gssd/svcgssd_mech2file.c create mode 100644 utils/gssd/svcgssd_proc.c create mode 100644 utils/gssd/write_bytes.h (limited to 'utils/gssd') diff --git a/utils/gssd/.gitignore b/utils/gssd/.gitignore new file mode 100644 index 0000000..aba7b13 --- /dev/null +++ b/utils/gssd/.gitignore @@ -0,0 +1,3 @@ +gss_clnt_send_err +gssd +svcgssd diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am new file mode 100644 index 0000000..21d3bb8 --- /dev/null +++ b/utils/gssd/Makefile.am @@ -0,0 +1,130 @@ +## Process this file with automake to produce Makefile.in + +man8_MANS = gssd.man +if CONFIG_SVCGSS +man8_MANS += svcgssd.man +endif + +AM_CPPFLAGS += -I ../../support/nfsidmap + +RPCPREFIX = rpc. +KPREFIX = @kprefix@ +sbin_PREFIXED = gssd +if CONFIG_SVCGSS +sbin_PREFIXED += svcgssd +endif + +sbin_PROGRAMS = $(sbin_PREFIXED) + +EXTRA_DIST = \ + $(man8_MANS) + +COMMON_SRCS = \ + context.c \ + context_mit.c \ + context_heimdal.c \ + context_lucid.c \ + gss_util.c \ + gss_oids.c \ + gss_names.c \ + err_util.c \ + \ + context.h \ + err_util.h \ + gss_oids.h \ + gss_names.h \ + gss_util.h + +gssd_SOURCES = \ + $(COMMON_SRCS) \ + gssd.c \ + gssd_proc.c \ + krb5_util.c \ + \ + gssd.h \ + krb5_util.h \ + write_bytes.h + +gssd_LDADD = \ + ../../support/nfs/libnfs.la \ + $(LIBEVENT) \ + $(RPCSECGSS_LIBS) \ + $(KRBLIBS) \ + $(GSSAPI_LIBS) \ + $(LIBTIRPC) \ + $(LIBPTHREAD) + +gssd_LDFLAGS = \ + $(KRBLDFLAGS) + +gssd_CFLAGS = \ + $(AM_CFLAGS) \ + $(CFLAGS) \ + $(RPCSECGSS_CFLAGS) \ + $(KRBCFLAGS) \ + $(GSSAPI_CFLAGS) + +svcgssd_SOURCES = \ + $(COMMON_SRCS) \ + svcgssd.c \ + svcgssd_mech2file.c \ + svcgssd_proc.c \ + svcgssd_krb5.c \ + \ + svcgssd_krb5.h \ + svcgssd.h + +svcgssd_LDADD = \ + ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la \ + $(LIBEVENT) \ + $(RPCSECGSS_LIBS) \ + $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC) + +svcgssd_LDFLAGS = $(KRBLDFLAGS) + +svcgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ + $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS) + +MAINTAINERCLEANFILES = Makefile.in + +####################################################################### +# The following allows the current practice of having +# daemons renamed during the install to include RPCPREFIX +# and the KPREFIX +# This could all be done much easier with program_transform_name +# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) +# but that also renames the man pages, which the current +# practice does not do. +install-exec-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PREFIXED); do \ + mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) +uninstall-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PREFIXED); do \ + rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) + + +# XXX This makes some assumptions about what automake does. +# XXX But there is no install-man-hook or install-man-local. +install-man: install-man8 install-man-links +uninstall-man: uninstall-man8 uninstall-man-links + +install-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ + done) + +uninstall-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + done) + diff --git a/utils/gssd/Makefile.in b/utils/gssd/Makefile.in new file mode 100644 index 0000000..75d69c3 --- /dev/null +++ b/utils/gssd/Makefile.in @@ -0,0 +1,1356 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@CONFIG_SVCGSS_TRUE@am__append_1 = svcgssd.man +@CONFIG_SVCGSS_TRUE@am__append_2 = svcgssd +sbin_PROGRAMS = $(am__EXEEXT_2) +subdir = utils/gssd +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@CONFIG_SVCGSS_TRUE@am__EXEEXT_1 = svcgssd$(EXEEXT) +am__EXEEXT_2 = gssd$(EXEEXT) $(am__EXEEXT_1) +am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)" +PROGRAMS = $(sbin_PROGRAMS) +am__objects_1 = gssd-context.$(OBJEXT) gssd-context_mit.$(OBJEXT) \ + gssd-context_heimdal.$(OBJEXT) gssd-context_lucid.$(OBJEXT) \ + gssd-gss_util.$(OBJEXT) gssd-gss_oids.$(OBJEXT) \ + gssd-gss_names.$(OBJEXT) gssd-err_util.$(OBJEXT) +am_gssd_OBJECTS = $(am__objects_1) gssd-gssd.$(OBJEXT) \ + gssd-gssd_proc.$(OBJEXT) gssd-krb5_util.$(OBJEXT) +gssd_OBJECTS = $(am_gssd_OBJECTS) +am__DEPENDENCIES_1 = +gssd_DEPENDENCIES = ../../support/nfs/libnfs.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +gssd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(gssd_CFLAGS) $(CFLAGS) \ + $(gssd_LDFLAGS) $(LDFLAGS) -o $@ +am__objects_2 = svcgssd-context.$(OBJEXT) \ + svcgssd-context_mit.$(OBJEXT) \ + svcgssd-context_heimdal.$(OBJEXT) \ + svcgssd-context_lucid.$(OBJEXT) svcgssd-gss_util.$(OBJEXT) \ + svcgssd-gss_oids.$(OBJEXT) svcgssd-gss_names.$(OBJEXT) \ + svcgssd-err_util.$(OBJEXT) +am_svcgssd_OBJECTS = $(am__objects_2) svcgssd-svcgssd.$(OBJEXT) \ + svcgssd-svcgssd_mech2file.$(OBJEXT) \ + svcgssd-svcgssd_proc.$(OBJEXT) svcgssd-svcgssd_krb5.$(OBJEXT) +svcgssd_OBJECTS = $(am_svcgssd_OBJECTS) +svcgssd_DEPENDENCIES = ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +svcgssd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(svcgssd_CFLAGS) \ + $(CFLAGS) $(svcgssd_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gssd-context.Po \ + ./$(DEPDIR)/gssd-context_heimdal.Po \ + ./$(DEPDIR)/gssd-context_lucid.Po \ + ./$(DEPDIR)/gssd-context_mit.Po ./$(DEPDIR)/gssd-err_util.Po \ + ./$(DEPDIR)/gssd-gss_names.Po ./$(DEPDIR)/gssd-gss_oids.Po \ + ./$(DEPDIR)/gssd-gss_util.Po ./$(DEPDIR)/gssd-gssd.Po \ + ./$(DEPDIR)/gssd-gssd_proc.Po ./$(DEPDIR)/gssd-krb5_util.Po \ + ./$(DEPDIR)/svcgssd-context.Po \ + ./$(DEPDIR)/svcgssd-context_heimdal.Po \ + ./$(DEPDIR)/svcgssd-context_lucid.Po \ + ./$(DEPDIR)/svcgssd-context_mit.Po \ + ./$(DEPDIR)/svcgssd-err_util.Po \ + ./$(DEPDIR)/svcgssd-gss_names.Po \ + ./$(DEPDIR)/svcgssd-gss_oids.Po \ + ./$(DEPDIR)/svcgssd-gss_util.Po ./$(DEPDIR)/svcgssd-svcgssd.Po \ + ./$(DEPDIR)/svcgssd-svcgssd_krb5.Po \ + ./$(DEPDIR)/svcgssd-svcgssd_mech2file.Po \ + ./$(DEPDIR)/svcgssd-svcgssd_proc.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(gssd_SOURCES) $(svcgssd_SOURCES) +DIST_SOURCES = $(gssd_SOURCES) $(svcgssd_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man8_MANS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ -I ../../support/nfsidmap +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +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@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +man8_MANS = gssd.man $(am__append_1) +RPCPREFIX = rpc. +KPREFIX = @kprefix@ +sbin_PREFIXED = gssd $(am__append_2) +EXTRA_DIST = \ + $(man8_MANS) + +COMMON_SRCS = \ + context.c \ + context_mit.c \ + context_heimdal.c \ + context_lucid.c \ + gss_util.c \ + gss_oids.c \ + gss_names.c \ + err_util.c \ + \ + context.h \ + err_util.h \ + gss_oids.h \ + gss_names.h \ + gss_util.h + +gssd_SOURCES = \ + $(COMMON_SRCS) \ + gssd.c \ + gssd_proc.c \ + krb5_util.c \ + \ + gssd.h \ + krb5_util.h \ + write_bytes.h + +gssd_LDADD = \ + ../../support/nfs/libnfs.la \ + $(LIBEVENT) \ + $(RPCSECGSS_LIBS) \ + $(KRBLIBS) \ + $(GSSAPI_LIBS) \ + $(LIBTIRPC) \ + $(LIBPTHREAD) + +gssd_LDFLAGS = \ + $(KRBLDFLAGS) + +gssd_CFLAGS = \ + $(AM_CFLAGS) \ + $(CFLAGS) \ + $(RPCSECGSS_CFLAGS) \ + $(KRBCFLAGS) \ + $(GSSAPI_CFLAGS) + +svcgssd_SOURCES = \ + $(COMMON_SRCS) \ + svcgssd.c \ + svcgssd_mech2file.c \ + svcgssd_proc.c \ + svcgssd_krb5.c \ + \ + svcgssd_krb5.h \ + svcgssd.h + +svcgssd_LDADD = \ + ../../support/nfs/libnfs.la \ + ../../support/nfsidmap/libnfsidmap.la \ + $(LIBEVENT) \ + $(RPCSECGSS_LIBS) \ + $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC) + +svcgssd_LDFLAGS = $(KRBLDFLAGS) +svcgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ + $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS) + +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu utils/gssd/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu utils/gssd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +gssd$(EXEEXT): $(gssd_OBJECTS) $(gssd_DEPENDENCIES) $(EXTRA_gssd_DEPENDENCIES) + @rm -f gssd$(EXEEXT) + $(AM_V_CCLD)$(gssd_LINK) $(gssd_OBJECTS) $(gssd_LDADD) $(LIBS) + +svcgssd$(EXEEXT): $(svcgssd_OBJECTS) $(svcgssd_DEPENDENCIES) $(EXTRA_svcgssd_DEPENDENCIES) + @rm -f svcgssd$(EXEEXT) + $(AM_V_CCLD)$(svcgssd_LINK) $(svcgssd_OBJECTS) $(svcgssd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-context_heimdal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-context_lucid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-context_mit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-err_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-gss_names.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-gss_oids.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-gss_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-gssd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-gssd_proc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gssd-krb5_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-context_heimdal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-context_lucid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-context_mit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-err_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-gss_names.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-gss_oids.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-gss_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-svcgssd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-svcgssd_krb5.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-svcgssd_mech2file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svcgssd-svcgssd_proc.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +gssd-context.o: context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context.o -MD -MP -MF $(DEPDIR)/gssd-context.Tpo -c -o gssd-context.o `test -f 'context.c' || echo '$(srcdir)/'`context.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context.Tpo $(DEPDIR)/gssd-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context.c' object='gssd-context.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context.o `test -f 'context.c' || echo '$(srcdir)/'`context.c + +gssd-context.obj: context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context.obj -MD -MP -MF $(DEPDIR)/gssd-context.Tpo -c -o gssd-context.obj `if test -f 'context.c'; then $(CYGPATH_W) 'context.c'; else $(CYGPATH_W) '$(srcdir)/context.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context.Tpo $(DEPDIR)/gssd-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context.c' object='gssd-context.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context.obj `if test -f 'context.c'; then $(CYGPATH_W) 'context.c'; else $(CYGPATH_W) '$(srcdir)/context.c'; fi` + +gssd-context_mit.o: context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_mit.o -MD -MP -MF $(DEPDIR)/gssd-context_mit.Tpo -c -o gssd-context_mit.o `test -f 'context_mit.c' || echo '$(srcdir)/'`context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_mit.Tpo $(DEPDIR)/gssd-context_mit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_mit.c' object='gssd-context_mit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_mit.o `test -f 'context_mit.c' || echo '$(srcdir)/'`context_mit.c + +gssd-context_mit.obj: context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_mit.obj -MD -MP -MF $(DEPDIR)/gssd-context_mit.Tpo -c -o gssd-context_mit.obj `if test -f 'context_mit.c'; then $(CYGPATH_W) 'context_mit.c'; else $(CYGPATH_W) '$(srcdir)/context_mit.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_mit.Tpo $(DEPDIR)/gssd-context_mit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_mit.c' object='gssd-context_mit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_mit.obj `if test -f 'context_mit.c'; then $(CYGPATH_W) 'context_mit.c'; else $(CYGPATH_W) '$(srcdir)/context_mit.c'; fi` + +gssd-context_heimdal.o: context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_heimdal.o -MD -MP -MF $(DEPDIR)/gssd-context_heimdal.Tpo -c -o gssd-context_heimdal.o `test -f 'context_heimdal.c' || echo '$(srcdir)/'`context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_heimdal.Tpo $(DEPDIR)/gssd-context_heimdal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_heimdal.c' object='gssd-context_heimdal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_heimdal.o `test -f 'context_heimdal.c' || echo '$(srcdir)/'`context_heimdal.c + +gssd-context_heimdal.obj: context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_heimdal.obj -MD -MP -MF $(DEPDIR)/gssd-context_heimdal.Tpo -c -o gssd-context_heimdal.obj `if test -f 'context_heimdal.c'; then $(CYGPATH_W) 'context_heimdal.c'; else $(CYGPATH_W) '$(srcdir)/context_heimdal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_heimdal.Tpo $(DEPDIR)/gssd-context_heimdal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_heimdal.c' object='gssd-context_heimdal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_heimdal.obj `if test -f 'context_heimdal.c'; then $(CYGPATH_W) 'context_heimdal.c'; else $(CYGPATH_W) '$(srcdir)/context_heimdal.c'; fi` + +gssd-context_lucid.o: context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_lucid.o -MD -MP -MF $(DEPDIR)/gssd-context_lucid.Tpo -c -o gssd-context_lucid.o `test -f 'context_lucid.c' || echo '$(srcdir)/'`context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_lucid.Tpo $(DEPDIR)/gssd-context_lucid.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_lucid.c' object='gssd-context_lucid.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_lucid.o `test -f 'context_lucid.c' || echo '$(srcdir)/'`context_lucid.c + +gssd-context_lucid.obj: context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-context_lucid.obj -MD -MP -MF $(DEPDIR)/gssd-context_lucid.Tpo -c -o gssd-context_lucid.obj `if test -f 'context_lucid.c'; then $(CYGPATH_W) 'context_lucid.c'; else $(CYGPATH_W) '$(srcdir)/context_lucid.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-context_lucid.Tpo $(DEPDIR)/gssd-context_lucid.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_lucid.c' object='gssd-context_lucid.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-context_lucid.obj `if test -f 'context_lucid.c'; then $(CYGPATH_W) 'context_lucid.c'; else $(CYGPATH_W) '$(srcdir)/context_lucid.c'; fi` + +gssd-gss_util.o: gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_util.o -MD -MP -MF $(DEPDIR)/gssd-gss_util.Tpo -c -o gssd-gss_util.o `test -f 'gss_util.c' || echo '$(srcdir)/'`gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_util.Tpo $(DEPDIR)/gssd-gss_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_util.c' object='gssd-gss_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_util.o `test -f 'gss_util.c' || echo '$(srcdir)/'`gss_util.c + +gssd-gss_util.obj: gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_util.obj -MD -MP -MF $(DEPDIR)/gssd-gss_util.Tpo -c -o gssd-gss_util.obj `if test -f 'gss_util.c'; then $(CYGPATH_W) 'gss_util.c'; else $(CYGPATH_W) '$(srcdir)/gss_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_util.Tpo $(DEPDIR)/gssd-gss_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_util.c' object='gssd-gss_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_util.obj `if test -f 'gss_util.c'; then $(CYGPATH_W) 'gss_util.c'; else $(CYGPATH_W) '$(srcdir)/gss_util.c'; fi` + +gssd-gss_oids.o: gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_oids.o -MD -MP -MF $(DEPDIR)/gssd-gss_oids.Tpo -c -o gssd-gss_oids.o `test -f 'gss_oids.c' || echo '$(srcdir)/'`gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_oids.Tpo $(DEPDIR)/gssd-gss_oids.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_oids.c' object='gssd-gss_oids.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_oids.o `test -f 'gss_oids.c' || echo '$(srcdir)/'`gss_oids.c + +gssd-gss_oids.obj: gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_oids.obj -MD -MP -MF $(DEPDIR)/gssd-gss_oids.Tpo -c -o gssd-gss_oids.obj `if test -f 'gss_oids.c'; then $(CYGPATH_W) 'gss_oids.c'; else $(CYGPATH_W) '$(srcdir)/gss_oids.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_oids.Tpo $(DEPDIR)/gssd-gss_oids.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_oids.c' object='gssd-gss_oids.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_oids.obj `if test -f 'gss_oids.c'; then $(CYGPATH_W) 'gss_oids.c'; else $(CYGPATH_W) '$(srcdir)/gss_oids.c'; fi` + +gssd-gss_names.o: gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_names.o -MD -MP -MF $(DEPDIR)/gssd-gss_names.Tpo -c -o gssd-gss_names.o `test -f 'gss_names.c' || echo '$(srcdir)/'`gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_names.Tpo $(DEPDIR)/gssd-gss_names.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_names.c' object='gssd-gss_names.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_names.o `test -f 'gss_names.c' || echo '$(srcdir)/'`gss_names.c + +gssd-gss_names.obj: gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gss_names.obj -MD -MP -MF $(DEPDIR)/gssd-gss_names.Tpo -c -o gssd-gss_names.obj `if test -f 'gss_names.c'; then $(CYGPATH_W) 'gss_names.c'; else $(CYGPATH_W) '$(srcdir)/gss_names.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gss_names.Tpo $(DEPDIR)/gssd-gss_names.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_names.c' object='gssd-gss_names.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gss_names.obj `if test -f 'gss_names.c'; then $(CYGPATH_W) 'gss_names.c'; else $(CYGPATH_W) '$(srcdir)/gss_names.c'; fi` + +gssd-err_util.o: err_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-err_util.o -MD -MP -MF $(DEPDIR)/gssd-err_util.Tpo -c -o gssd-err_util.o `test -f 'err_util.c' || echo '$(srcdir)/'`err_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-err_util.Tpo $(DEPDIR)/gssd-err_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='err_util.c' object='gssd-err_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-err_util.o `test -f 'err_util.c' || echo '$(srcdir)/'`err_util.c + +gssd-err_util.obj: err_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-err_util.obj -MD -MP -MF $(DEPDIR)/gssd-err_util.Tpo -c -o gssd-err_util.obj `if test -f 'err_util.c'; then $(CYGPATH_W) 'err_util.c'; else $(CYGPATH_W) '$(srcdir)/err_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-err_util.Tpo $(DEPDIR)/gssd-err_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='err_util.c' object='gssd-err_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-err_util.obj `if test -f 'err_util.c'; then $(CYGPATH_W) 'err_util.c'; else $(CYGPATH_W) '$(srcdir)/err_util.c'; fi` + +gssd-gssd.o: gssd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gssd.o -MD -MP -MF $(DEPDIR)/gssd-gssd.Tpo -c -o gssd-gssd.o `test -f 'gssd.c' || echo '$(srcdir)/'`gssd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gssd.Tpo $(DEPDIR)/gssd-gssd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gssd.c' object='gssd-gssd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gssd.o `test -f 'gssd.c' || echo '$(srcdir)/'`gssd.c + +gssd-gssd.obj: gssd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gssd.obj -MD -MP -MF $(DEPDIR)/gssd-gssd.Tpo -c -o gssd-gssd.obj `if test -f 'gssd.c'; then $(CYGPATH_W) 'gssd.c'; else $(CYGPATH_W) '$(srcdir)/gssd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gssd.Tpo $(DEPDIR)/gssd-gssd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gssd.c' object='gssd-gssd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gssd.obj `if test -f 'gssd.c'; then $(CYGPATH_W) 'gssd.c'; else $(CYGPATH_W) '$(srcdir)/gssd.c'; fi` + +gssd-gssd_proc.o: gssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gssd_proc.o -MD -MP -MF $(DEPDIR)/gssd-gssd_proc.Tpo -c -o gssd-gssd_proc.o `test -f 'gssd_proc.c' || echo '$(srcdir)/'`gssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gssd_proc.Tpo $(DEPDIR)/gssd-gssd_proc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gssd_proc.c' object='gssd-gssd_proc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gssd_proc.o `test -f 'gssd_proc.c' || echo '$(srcdir)/'`gssd_proc.c + +gssd-gssd_proc.obj: gssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-gssd_proc.obj -MD -MP -MF $(DEPDIR)/gssd-gssd_proc.Tpo -c -o gssd-gssd_proc.obj `if test -f 'gssd_proc.c'; then $(CYGPATH_W) 'gssd_proc.c'; else $(CYGPATH_W) '$(srcdir)/gssd_proc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-gssd_proc.Tpo $(DEPDIR)/gssd-gssd_proc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gssd_proc.c' object='gssd-gssd_proc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-gssd_proc.obj `if test -f 'gssd_proc.c'; then $(CYGPATH_W) 'gssd_proc.c'; else $(CYGPATH_W) '$(srcdir)/gssd_proc.c'; fi` + +gssd-krb5_util.o: krb5_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-krb5_util.o -MD -MP -MF $(DEPDIR)/gssd-krb5_util.Tpo -c -o gssd-krb5_util.o `test -f 'krb5_util.c' || echo '$(srcdir)/'`krb5_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-krb5_util.Tpo $(DEPDIR)/gssd-krb5_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='krb5_util.c' object='gssd-krb5_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-krb5_util.o `test -f 'krb5_util.c' || echo '$(srcdir)/'`krb5_util.c + +gssd-krb5_util.obj: krb5_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -MT gssd-krb5_util.obj -MD -MP -MF $(DEPDIR)/gssd-krb5_util.Tpo -c -o gssd-krb5_util.obj `if test -f 'krb5_util.c'; then $(CYGPATH_W) 'krb5_util.c'; else $(CYGPATH_W) '$(srcdir)/krb5_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gssd-krb5_util.Tpo $(DEPDIR)/gssd-krb5_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='krb5_util.c' object='gssd-krb5_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gssd_CFLAGS) $(CFLAGS) -c -o gssd-krb5_util.obj `if test -f 'krb5_util.c'; then $(CYGPATH_W) 'krb5_util.c'; else $(CYGPATH_W) '$(srcdir)/krb5_util.c'; fi` + +svcgssd-context.o: context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context.o -MD -MP -MF $(DEPDIR)/svcgssd-context.Tpo -c -o svcgssd-context.o `test -f 'context.c' || echo '$(srcdir)/'`context.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context.Tpo $(DEPDIR)/svcgssd-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context.c' object='svcgssd-context.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context.o `test -f 'context.c' || echo '$(srcdir)/'`context.c + +svcgssd-context.obj: context.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context.obj -MD -MP -MF $(DEPDIR)/svcgssd-context.Tpo -c -o svcgssd-context.obj `if test -f 'context.c'; then $(CYGPATH_W) 'context.c'; else $(CYGPATH_W) '$(srcdir)/context.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context.Tpo $(DEPDIR)/svcgssd-context.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context.c' object='svcgssd-context.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context.obj `if test -f 'context.c'; then $(CYGPATH_W) 'context.c'; else $(CYGPATH_W) '$(srcdir)/context.c'; fi` + +svcgssd-context_mit.o: context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_mit.o -MD -MP -MF $(DEPDIR)/svcgssd-context_mit.Tpo -c -o svcgssd-context_mit.o `test -f 'context_mit.c' || echo '$(srcdir)/'`context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_mit.Tpo $(DEPDIR)/svcgssd-context_mit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_mit.c' object='svcgssd-context_mit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_mit.o `test -f 'context_mit.c' || echo '$(srcdir)/'`context_mit.c + +svcgssd-context_mit.obj: context_mit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_mit.obj -MD -MP -MF $(DEPDIR)/svcgssd-context_mit.Tpo -c -o svcgssd-context_mit.obj `if test -f 'context_mit.c'; then $(CYGPATH_W) 'context_mit.c'; else $(CYGPATH_W) '$(srcdir)/context_mit.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_mit.Tpo $(DEPDIR)/svcgssd-context_mit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_mit.c' object='svcgssd-context_mit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_mit.obj `if test -f 'context_mit.c'; then $(CYGPATH_W) 'context_mit.c'; else $(CYGPATH_W) '$(srcdir)/context_mit.c'; fi` + +svcgssd-context_heimdal.o: context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_heimdal.o -MD -MP -MF $(DEPDIR)/svcgssd-context_heimdal.Tpo -c -o svcgssd-context_heimdal.o `test -f 'context_heimdal.c' || echo '$(srcdir)/'`context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_heimdal.Tpo $(DEPDIR)/svcgssd-context_heimdal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_heimdal.c' object='svcgssd-context_heimdal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_heimdal.o `test -f 'context_heimdal.c' || echo '$(srcdir)/'`context_heimdal.c + +svcgssd-context_heimdal.obj: context_heimdal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_heimdal.obj -MD -MP -MF $(DEPDIR)/svcgssd-context_heimdal.Tpo -c -o svcgssd-context_heimdal.obj `if test -f 'context_heimdal.c'; then $(CYGPATH_W) 'context_heimdal.c'; else $(CYGPATH_W) '$(srcdir)/context_heimdal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_heimdal.Tpo $(DEPDIR)/svcgssd-context_heimdal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_heimdal.c' object='svcgssd-context_heimdal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_heimdal.obj `if test -f 'context_heimdal.c'; then $(CYGPATH_W) 'context_heimdal.c'; else $(CYGPATH_W) '$(srcdir)/context_heimdal.c'; fi` + +svcgssd-context_lucid.o: context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_lucid.o -MD -MP -MF $(DEPDIR)/svcgssd-context_lucid.Tpo -c -o svcgssd-context_lucid.o `test -f 'context_lucid.c' || echo '$(srcdir)/'`context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_lucid.Tpo $(DEPDIR)/svcgssd-context_lucid.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_lucid.c' object='svcgssd-context_lucid.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_lucid.o `test -f 'context_lucid.c' || echo '$(srcdir)/'`context_lucid.c + +svcgssd-context_lucid.obj: context_lucid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-context_lucid.obj -MD -MP -MF $(DEPDIR)/svcgssd-context_lucid.Tpo -c -o svcgssd-context_lucid.obj `if test -f 'context_lucid.c'; then $(CYGPATH_W) 'context_lucid.c'; else $(CYGPATH_W) '$(srcdir)/context_lucid.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-context_lucid.Tpo $(DEPDIR)/svcgssd-context_lucid.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='context_lucid.c' object='svcgssd-context_lucid.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-context_lucid.obj `if test -f 'context_lucid.c'; then $(CYGPATH_W) 'context_lucid.c'; else $(CYGPATH_W) '$(srcdir)/context_lucid.c'; fi` + +svcgssd-gss_util.o: gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_util.o -MD -MP -MF $(DEPDIR)/svcgssd-gss_util.Tpo -c -o svcgssd-gss_util.o `test -f 'gss_util.c' || echo '$(srcdir)/'`gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_util.Tpo $(DEPDIR)/svcgssd-gss_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_util.c' object='svcgssd-gss_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_util.o `test -f 'gss_util.c' || echo '$(srcdir)/'`gss_util.c + +svcgssd-gss_util.obj: gss_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_util.obj -MD -MP -MF $(DEPDIR)/svcgssd-gss_util.Tpo -c -o svcgssd-gss_util.obj `if test -f 'gss_util.c'; then $(CYGPATH_W) 'gss_util.c'; else $(CYGPATH_W) '$(srcdir)/gss_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_util.Tpo $(DEPDIR)/svcgssd-gss_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_util.c' object='svcgssd-gss_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_util.obj `if test -f 'gss_util.c'; then $(CYGPATH_W) 'gss_util.c'; else $(CYGPATH_W) '$(srcdir)/gss_util.c'; fi` + +svcgssd-gss_oids.o: gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_oids.o -MD -MP -MF $(DEPDIR)/svcgssd-gss_oids.Tpo -c -o svcgssd-gss_oids.o `test -f 'gss_oids.c' || echo '$(srcdir)/'`gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_oids.Tpo $(DEPDIR)/svcgssd-gss_oids.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_oids.c' object='svcgssd-gss_oids.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_oids.o `test -f 'gss_oids.c' || echo '$(srcdir)/'`gss_oids.c + +svcgssd-gss_oids.obj: gss_oids.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_oids.obj -MD -MP -MF $(DEPDIR)/svcgssd-gss_oids.Tpo -c -o svcgssd-gss_oids.obj `if test -f 'gss_oids.c'; then $(CYGPATH_W) 'gss_oids.c'; else $(CYGPATH_W) '$(srcdir)/gss_oids.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_oids.Tpo $(DEPDIR)/svcgssd-gss_oids.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_oids.c' object='svcgssd-gss_oids.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_oids.obj `if test -f 'gss_oids.c'; then $(CYGPATH_W) 'gss_oids.c'; else $(CYGPATH_W) '$(srcdir)/gss_oids.c'; fi` + +svcgssd-gss_names.o: gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_names.o -MD -MP -MF $(DEPDIR)/svcgssd-gss_names.Tpo -c -o svcgssd-gss_names.o `test -f 'gss_names.c' || echo '$(srcdir)/'`gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_names.Tpo $(DEPDIR)/svcgssd-gss_names.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_names.c' object='svcgssd-gss_names.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_names.o `test -f 'gss_names.c' || echo '$(srcdir)/'`gss_names.c + +svcgssd-gss_names.obj: gss_names.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-gss_names.obj -MD -MP -MF $(DEPDIR)/svcgssd-gss_names.Tpo -c -o svcgssd-gss_names.obj `if test -f 'gss_names.c'; then $(CYGPATH_W) 'gss_names.c'; else $(CYGPATH_W) '$(srcdir)/gss_names.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-gss_names.Tpo $(DEPDIR)/svcgssd-gss_names.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gss_names.c' object='svcgssd-gss_names.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-gss_names.obj `if test -f 'gss_names.c'; then $(CYGPATH_W) 'gss_names.c'; else $(CYGPATH_W) '$(srcdir)/gss_names.c'; fi` + +svcgssd-err_util.o: err_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-err_util.o -MD -MP -MF $(DEPDIR)/svcgssd-err_util.Tpo -c -o svcgssd-err_util.o `test -f 'err_util.c' || echo '$(srcdir)/'`err_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-err_util.Tpo $(DEPDIR)/svcgssd-err_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='err_util.c' object='svcgssd-err_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-err_util.o `test -f 'err_util.c' || echo '$(srcdir)/'`err_util.c + +svcgssd-err_util.obj: err_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-err_util.obj -MD -MP -MF $(DEPDIR)/svcgssd-err_util.Tpo -c -o svcgssd-err_util.obj `if test -f 'err_util.c'; then $(CYGPATH_W) 'err_util.c'; else $(CYGPATH_W) '$(srcdir)/err_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-err_util.Tpo $(DEPDIR)/svcgssd-err_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='err_util.c' object='svcgssd-err_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-err_util.obj `if test -f 'err_util.c'; then $(CYGPATH_W) 'err_util.c'; else $(CYGPATH_W) '$(srcdir)/err_util.c'; fi` + +svcgssd-svcgssd.o: svcgssd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd.o -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd.Tpo -c -o svcgssd-svcgssd.o `test -f 'svcgssd.c' || echo '$(srcdir)/'`svcgssd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd.Tpo $(DEPDIR)/svcgssd-svcgssd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd.c' object='svcgssd-svcgssd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd.o `test -f 'svcgssd.c' || echo '$(srcdir)/'`svcgssd.c + +svcgssd-svcgssd.obj: svcgssd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd.obj -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd.Tpo -c -o svcgssd-svcgssd.obj `if test -f 'svcgssd.c'; then $(CYGPATH_W) 'svcgssd.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd.Tpo $(DEPDIR)/svcgssd-svcgssd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd.c' object='svcgssd-svcgssd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd.obj `if test -f 'svcgssd.c'; then $(CYGPATH_W) 'svcgssd.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd.c'; fi` + +svcgssd-svcgssd_mech2file.o: svcgssd_mech2file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_mech2file.o -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_mech2file.Tpo -c -o svcgssd-svcgssd_mech2file.o `test -f 'svcgssd_mech2file.c' || echo '$(srcdir)/'`svcgssd_mech2file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_mech2file.Tpo $(DEPDIR)/svcgssd-svcgssd_mech2file.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_mech2file.c' object='svcgssd-svcgssd_mech2file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_mech2file.o `test -f 'svcgssd_mech2file.c' || echo '$(srcdir)/'`svcgssd_mech2file.c + +svcgssd-svcgssd_mech2file.obj: svcgssd_mech2file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_mech2file.obj -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_mech2file.Tpo -c -o svcgssd-svcgssd_mech2file.obj `if test -f 'svcgssd_mech2file.c'; then $(CYGPATH_W) 'svcgssd_mech2file.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_mech2file.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_mech2file.Tpo $(DEPDIR)/svcgssd-svcgssd_mech2file.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_mech2file.c' object='svcgssd-svcgssd_mech2file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_mech2file.obj `if test -f 'svcgssd_mech2file.c'; then $(CYGPATH_W) 'svcgssd_mech2file.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_mech2file.c'; fi` + +svcgssd-svcgssd_proc.o: svcgssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_proc.o -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_proc.Tpo -c -o svcgssd-svcgssd_proc.o `test -f 'svcgssd_proc.c' || echo '$(srcdir)/'`svcgssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_proc.Tpo $(DEPDIR)/svcgssd-svcgssd_proc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_proc.c' object='svcgssd-svcgssd_proc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_proc.o `test -f 'svcgssd_proc.c' || echo '$(srcdir)/'`svcgssd_proc.c + +svcgssd-svcgssd_proc.obj: svcgssd_proc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_proc.obj -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_proc.Tpo -c -o svcgssd-svcgssd_proc.obj `if test -f 'svcgssd_proc.c'; then $(CYGPATH_W) 'svcgssd_proc.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_proc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_proc.Tpo $(DEPDIR)/svcgssd-svcgssd_proc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_proc.c' object='svcgssd-svcgssd_proc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_proc.obj `if test -f 'svcgssd_proc.c'; then $(CYGPATH_W) 'svcgssd_proc.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_proc.c'; fi` + +svcgssd-svcgssd_krb5.o: svcgssd_krb5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_krb5.o -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_krb5.Tpo -c -o svcgssd-svcgssd_krb5.o `test -f 'svcgssd_krb5.c' || echo '$(srcdir)/'`svcgssd_krb5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_krb5.Tpo $(DEPDIR)/svcgssd-svcgssd_krb5.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_krb5.c' object='svcgssd-svcgssd_krb5.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_krb5.o `test -f 'svcgssd_krb5.c' || echo '$(srcdir)/'`svcgssd_krb5.c + +svcgssd-svcgssd_krb5.obj: svcgssd_krb5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -MT svcgssd-svcgssd_krb5.obj -MD -MP -MF $(DEPDIR)/svcgssd-svcgssd_krb5.Tpo -c -o svcgssd-svcgssd_krb5.obj `if test -f 'svcgssd_krb5.c'; then $(CYGPATH_W) 'svcgssd_krb5.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_krb5.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/svcgssd-svcgssd_krb5.Tpo $(DEPDIR)/svcgssd-svcgssd_krb5.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svcgssd_krb5.c' object='svcgssd-svcgssd_krb5.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(svcgssd_CFLAGS) $(CFLAGS) -c -o svcgssd-svcgssd_krb5.obj `if test -f 'svcgssd_krb5.c'; then $(CYGPATH_W) 'svcgssd_krb5.c'; else $(CYGPATH_W) '$(srcdir)/svcgssd_krb5.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man8: $(man8_MANS) + @$(NORMAL_INSTALL) + @list1='$(man8_MANS)'; \ + list2=''; \ + test -n "$(man8dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.8[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(sbindir)" "$(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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gssd-context.Po + -rm -f ./$(DEPDIR)/gssd-context_heimdal.Po + -rm -f ./$(DEPDIR)/gssd-context_lucid.Po + -rm -f ./$(DEPDIR)/gssd-context_mit.Po + -rm -f ./$(DEPDIR)/gssd-err_util.Po + -rm -f ./$(DEPDIR)/gssd-gss_names.Po + -rm -f ./$(DEPDIR)/gssd-gss_oids.Po + -rm -f ./$(DEPDIR)/gssd-gss_util.Po + -rm -f ./$(DEPDIR)/gssd-gssd.Po + -rm -f ./$(DEPDIR)/gssd-gssd_proc.Po + -rm -f ./$(DEPDIR)/gssd-krb5_util.Po + -rm -f ./$(DEPDIR)/svcgssd-context.Po + -rm -f ./$(DEPDIR)/svcgssd-context_heimdal.Po + -rm -f ./$(DEPDIR)/svcgssd-context_lucid.Po + -rm -f ./$(DEPDIR)/svcgssd-context_mit.Po + -rm -f ./$(DEPDIR)/svcgssd-err_util.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_names.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_oids.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_util.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_krb5.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_mech2file.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_proc.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gssd-context.Po + -rm -f ./$(DEPDIR)/gssd-context_heimdal.Po + -rm -f ./$(DEPDIR)/gssd-context_lucid.Po + -rm -f ./$(DEPDIR)/gssd-context_mit.Po + -rm -f ./$(DEPDIR)/gssd-err_util.Po + -rm -f ./$(DEPDIR)/gssd-gss_names.Po + -rm -f ./$(DEPDIR)/gssd-gss_oids.Po + -rm -f ./$(DEPDIR)/gssd-gss_util.Po + -rm -f ./$(DEPDIR)/gssd-gssd.Po + -rm -f ./$(DEPDIR)/gssd-gssd_proc.Po + -rm -f ./$(DEPDIR)/gssd-krb5_util.Po + -rm -f ./$(DEPDIR)/svcgssd-context.Po + -rm -f ./$(DEPDIR)/svcgssd-context_heimdal.Po + -rm -f ./$(DEPDIR)/svcgssd-context_lucid.Po + -rm -f ./$(DEPDIR)/svcgssd-context_mit.Po + -rm -f ./$(DEPDIR)/svcgssd-err_util.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_names.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_oids.Po + -rm -f ./$(DEPDIR)/svcgssd-gss_util.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_krb5.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_mech2file.Po + -rm -f ./$(DEPDIR)/svcgssd-svcgssd_proc.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man uninstall-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: install-am install-exec-am install-strip uninstall-am + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-sbinPROGRAMS cscopelist-am \ + ctags ctags-am 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-dvi install-dvi-am install-exec \ + install-exec-am 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 \ + install-sbinPROGRAMS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-hook \ + uninstall-man uninstall-man8 uninstall-sbinPROGRAMS + +.PRECIOUS: Makefile + + +####################################################################### +# The following allows the current practice of having +# daemons renamed during the install to include RPCPREFIX +# and the KPREFIX +# This could all be done much easier with program_transform_name +# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) +# but that also renames the man pages, which the current +# practice does not do. +install-exec-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PREFIXED); do \ + mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) +uninstall-hook: + (cd $(DESTDIR)$(sbindir) && \ + for p in $(sbin_PREFIXED); do \ + rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ + done) + +# XXX This makes some assumptions about what automake does. +# XXX But there is no install-man-hook or install-man-local. +install-man: install-man8 install-man-links +uninstall-man: uninstall-man8 uninstall-man-links + +install-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ + done) + +uninstall-man-links: + (cd $(DESTDIR)$(man8dir) && \ + for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ + inst=`echo $$m | sed -e 's/man$$/8/'`; \ + rm -f $(RPCPREFIX)$$inst ; \ + done) + +# 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/utils/gssd/context.c b/utils/gssd/context.c new file mode 100644 index 0000000..7757a77 --- /dev/null +++ b/utils/gssd/context.c @@ -0,0 +1,59 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include "gss_util.h" +#include "gss_oids.h" +#include "err_util.h" +#include "context.h" + +int +serialize_context_for_kernel(gss_ctx_id_t *ctx, + gss_buffer_desc *buf, + gss_OID mech, + int32_t *endtime) +{ + if (g_OID_equal(&krb5oid, mech)) + return serialize_krb5_ctx(ctx, buf, endtime); + else { + printerr(0, "ERROR: attempting to serialize context with " + "unknown/unsupported mechanism oid\n"); + return -1; + } +} diff --git a/utils/gssd/context.h b/utils/gssd/context.h new file mode 100644 index 0000000..3b55c8e --- /dev/null +++ b/utils/gssd/context.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2004,2008 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _CONTEXT_H_ +#define _CONTEXT_H_ + +#include + +/* Hopefully big enough to hold any serialized context */ +#define MAX_CTX_LEN 4096 + +/* New context format flag values */ +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 +#define KRB5_CTX_FLAG_CFX 0x00000002 +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 + +int serialize_context_for_kernel(gss_ctx_id_t *ctx, gss_buffer_desc *buf, + gss_OID mech, int32_t *endtime); +int serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, + int32_t *endtime); + +#endif /* _CONTEXT_H_ */ diff --git a/utils/gssd/context_heimdal.c b/utils/gssd/context_heimdal.c new file mode 100644 index 0000000..d07103b --- /dev/null +++ b/utils/gssd/context_heimdal.c @@ -0,0 +1,275 @@ +/* + Copyright (c) 2004-2006 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef HAVE_LUCID_CONTEXT_SUPPORT +#ifdef HAVE_HEIMDAL + +#include +#include +#include +#include +#include +#include +#include /* Must use the heimdal copy! */ +#ifdef HAVE_COM_ERR_H +#include +#endif +#include "err_util.h" +#include "gss_oids.h" +#include "write_bytes.h" + +int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key) +{ + gss_buffer_desc tmp; + int code = -1; + + if (WRITE_BYTES(p, end, key->keytype)) goto out_err; + tmp.length = key->keyvalue.length; + tmp.value = key->keyvalue.data; + if (write_buffer(p, end, &tmp)) goto out_err; + code = 0; + out_err: + return(code); +} + +int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx) +{ + krb5_keyblock enc_key, *key; + krb5_context context; + krb5_error_code ret; + int i; + char *skd, *dkd, *k5err = NULL; + int code = -1; + + if ((ret = krb5_init_context(&context))) { + k5err = gssd_k5_err_msg(NULL, ret); + printerr(0, "ERROR: initializing krb5_context: %s\n", k5err); + goto out_err; + } + + if ((ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, &key))){ + k5err = gssd_k5_err_msg(context, ret); + printerr(0, "ERROR: getting auth_context key: %s\n", k5err); + goto out_err_free_context; + } + + memset(&enc_key, 0, sizeof(enc_key)); + enc_key.keytype = key->keytype; + /* XXX current kernel code only handles des-cbc-raw (4) */ + if (enc_key.keytype != 4) { + printerr(1, "WARN: write_heimdal_enc_key: " + "overriding heimdal keytype (%d => %d)\n", + enc_key.keytype, 4); + enc_key.keytype = 4; + } + enc_key.keyvalue.length = key->keyvalue.length; + if ((enc_key.keyvalue.data = + calloc(1, enc_key.keyvalue.length)) == NULL) { + k5err = gssd_k5_err_msg(context, ENOMEM); + printerr(0, "ERROR: allocating memory for enc key: %s\n", + k5err); + goto out_err_free_key; + } + skd = (char *) key->keyvalue.data; + dkd = (char *) enc_key.keyvalue.data; + for (i = 0; i < enc_key.keyvalue.length; i++) + dkd[i] = skd[i] ^ 0xf0; + if (write_heimdal_keyblock(p, end, &enc_key)) { + goto out_err_free_enckey; + } + + code = 0; + + out_err_free_enckey: + krb5_free_keyblock_contents(context, &enc_key); + out_err_free_key: + krb5_free_keyblock(context, key); + out_err_free_context: + krb5_free_context(context); + out_err: + free(k5err); + printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS"); + return(code); +} + +int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx) +{ + krb5_keyblock *key; + krb5_context context; + krb5_error_code ret; + char *k5err = NULL; + int code = -1; + + if ((ret = krb5_init_context(&context))) { + k5err = gssd_k5_err_msg(NULL, ret); + printerr(0, "ERROR: initializing krb5_context: %s\n", k5err); + goto out_err; + } + + if ((ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, &key))){ + k5err = gssd_k5_err_msg(context, ret); + printerr(0, "ERROR: getting auth_context key: %s\n", k5err); + goto out_err_free_context; + } + + /* XXX current kernel code only handles des-cbc-raw (4) */ + if (key->keytype != 4) { + printerr(1, "WARN: write_heimdal_seq_key: " + "overriding heimdal keytype (%d => %d)\n", + key->keytype, 4); + key->keytype = 4; + } + + if (write_heimdal_keyblock(p, end, key)) { + goto out_err_free_key; + } + + code = 0; + + out_err_free_key: + krb5_free_keyblock(context, key); + out_err_free_context: + krb5_free_context(context); + out_err: + free(k5err); + printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS"); + return(code); +} + +/* + * The following is the kernel structure that we are filling in: + * + * struct krb5_ctx { + * int initiate; + * int seed_init; + * unsigned char seed[16]; + * int signalg; + * int sealalg; + * struct crypto_tfm *enc; + * struct crypto_tfm *seq; + * s32 endtime; + * u32 seq_send; + * struct xdr_netobj mech_used; + * }; + * + * However, note that we do not send the data fields in the + * order they appear in the structure. The order they are + * sent down in is: + * + * initiate + * seed_init + * seed + * signalg + * sealalg + * endtime + * seq_send + * mech_used + * enc key + * seq key + * + */ + +int +serialize_krb5_ctx(gss_ctx_id_t *_ctx, gss_buffer_desc *buf, int32_t *endtime) +{ + gss_ctx_id_t ctx = *_ctx; + char *p, *end; + static int constant_one = 1; + static int constant_zero = 0; + unsigned char fakeseed[16]; + uint32_t algorithm; + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + + /* initiate: 1 => initiating 0 => accepting */ + if (ctx->more_flags & LOCAL) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + + /* seed_init: not used by kernel code */ + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + + /* seed: not used by kernel code */ + memset(&fakeseed, 0, sizeof(fakeseed)); + if (write_bytes(&p, end, &fakeseed, 16)) goto out_err; + + /* signalg */ + algorithm = 0; /* SGN_ALG_DES_MAC_MD5 XXX */ + if (WRITE_BYTES(&p, end, algorithm)) goto out_err; + + /* sealalg */ + algorithm = 0; /* SEAL_ALG_DES XXX */ + if (WRITE_BYTES(&p, end, algorithm)) goto out_err; + + /* endtime */ + if (WRITE_BYTES(&p, end, ctx->lifetime)) goto out_err; + + if (endtime) + *endtime = ctx->lifetime; + + /* seq_send */ + if (WRITE_BYTES(&p, end, ctx->auth_context->local_seqnumber)) + goto out_err; + /* mech_used */ + if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err; + + /* enc: derive the encryption key and copy it into buffer */ + if (write_heimdal_enc_key(&p, end, ctx)) goto out_err; + + /* seq: get the sequence number key and copy it into buffer */ + if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; + + buf->length = p - (char *)buf->value; + printerr(4, "serialize_krb5_ctx: returning buffer " + "with %d bytes\n", buf->length); + + return 0; +out_err: + printerr(0, "ERROR: failed exporting Heimdal krb5 ctx to kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; + return -1; +} + +#endif /* HAVE_HEIMDAL */ +#endif /* HAVE_LUCID_CONTEXT_SUPPORT */ diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c new file mode 100644 index 0000000..5d77c21 --- /dev/null +++ b/utils/gssd/context_lucid.c @@ -0,0 +1,327 @@ +/* + * COPYRIGHT (c) 2006 + * The Regents of the University of Michigan + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_LUCID_CONTEXT_SUPPORT + +/* + * Newer versions of MIT and Heimdal have lucid context support. + * We can use common code if it is supported. + */ + +#include +#include +#include +#include + +#include + +#include "gss_util.h" +#include "gss_oids.h" +#include "err_util.h" +#include "context.h" + +#ifndef OM_uint64 +typedef uint64_t OM_uint64; +#endif + +static int +write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key) +{ + gss_buffer_desc tmp; + + if (WRITE_BYTES(p, end, key->type)) return -1; + tmp.length = key->length; + tmp.value = key->data; + if (write_buffer(p, end, &tmp)) return -1; + return 0; +} + +static int +prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, + gss_buffer_desc *buf, int32_t *endtime) +{ +#define FAKESEED_SIZE 16 + char *p, *end; + static int constant_zero = 0; + unsigned char fakeseed[FAKESEED_SIZE]; + uint32_t word_send_seq; + gss_krb5_lucid_key_t enc_key; + uint32_t i; + char *skd, *dkd; + gss_buffer_desc fakeoid; + int err; + + /* + * The new Kerberos interface to get the gss context + * does not include the seed or seed_init fields + * because we never really use them. But for now, + * send down a fake buffer so we can use the same + * interface to the kernel. + */ + memset(&enc_key, 0, sizeof(enc_key)); + memset(&fakeoid, 0, sizeof(fakeoid)); + memset(fakeseed, 0, FAKESEED_SIZE); + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err; + + /* seed_init and seed not used by kernel anyway */ + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + if (write_bytes(&p, end, &fakeseed, FAKESEED_SIZE)) goto out_err; + + if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.sign_alg)) goto out_err; + if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.seal_alg)) goto out_err; + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; + if (endtime) + *endtime = lctx->endtime; + word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */ + if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err; + if (write_oid(&p, end, &krb5oid)) goto out_err; + +#ifdef HAVE_HEIMDAL + /* + * The kernel gss code expects des-cbc-raw for all flavors of des. + * The keytype from MIT has this type, but Heimdal does not. + * Force the Heimdal keytype to 4 (des-cbc-raw). + * Note that the rfc1964 version only supports DES enctypes. + */ + if (lctx->rfc1964_kd.ctx_key.type != 4) { + printerr(2, "%s: overriding heimdal keytype (%d => %d)\n", + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4); + lctx->rfc1964_kd.ctx_key.type = 4; + } +#endif + printerr(2, "%s: serializing keys with enctype %d and length %d\n", + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, + lctx->rfc1964_kd.ctx_key.length); + + /* derive the encryption key and copy it into buffer */ + enc_key.type = lctx->rfc1964_kd.ctx_key.type; + enc_key.length = lctx->rfc1964_kd.ctx_key.length; + if ((enc_key.data = calloc(1, enc_key.length)) == NULL) + goto out_err; + skd = (char *) lctx->rfc1964_kd.ctx_key.data; + dkd = (char *) enc_key.data; + for (i = 0; i < enc_key.length; i++) + dkd[i] = skd[i] ^ 0xf0; + err = write_lucid_keyblock(&p, end, &enc_key); + free(enc_key.data); + if (err) + goto out_err; + + if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) + goto out_err; + + buf->length = p - (char *)buf->value; + return 0; +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; + return -1; +} + +/* Flags for version 2 context flags */ +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 +#define KRB5_CTX_FLAG_CFX 0x00000002 +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 + +/* + * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx), + * to send to the kernel for newer encryption types -- or for DES3. + * + * The new format is: + * + * u32 flags; + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 + * #define KRB5_CTX_FLAG_CFX 0x00000002 + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 + * s32 endtime; + * u64 seq_send; + * u32 enctype; ( encrption type of key ) + * raw key; ( raw key bytes (kernel will derive)) + * + */ +static int +prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, + gss_buffer_desc *buf, int32_t *endtime) +{ + char *p, *end; + uint32_t v2_flags = 0; + uint32_t enctype; + uint32_t keysize; + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + /* Version 2 */ + if (lctx->initiate) + v2_flags |= KRB5_CTX_FLAG_INITIATOR; + if (lctx->protocol != 0) + v2_flags |= KRB5_CTX_FLAG_CFX; + if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1) + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY; + + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; + if (endtime) + *endtime = lctx->endtime; + if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; + + /* Protocol 0 here implies DES3 or RC4 */ + printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); + if (lctx->protocol == 0) { + enctype = lctx->rfc1964_kd.ctx_key.type; + keysize = lctx->rfc1964_kd.ctx_key.length; + } else { + if (lctx->cfx_kd.have_acceptor_subkey) { + enctype = lctx->cfx_kd.acceptor_subkey.type; + keysize = lctx->cfx_kd.acceptor_subkey.length; + } else { + enctype = lctx->cfx_kd.ctx_key.type; + keysize = lctx->cfx_kd.ctx_key.length; + } + } + printerr(4, "%s: serializing key with enctype %d and size %d\n", + __FUNCTION__, enctype, keysize); + + if (WRITE_BYTES(&p, end, enctype)) goto out_err; + + if (lctx->protocol == 0) { + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data, + lctx->rfc1964_kd.ctx_key.length)) + goto out_err; + } else { + if (lctx->cfx_kd.have_acceptor_subkey) { + if (write_bytes(&p, end, + lctx->cfx_kd.acceptor_subkey.data, + lctx->cfx_kd.acceptor_subkey.length)) + goto out_err; + } else { + if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data, + lctx->cfx_kd.ctx_key.length)) + goto out_err; + } + } + + buf->length = p - (char *)buf->value; + return 0; + +out_err: + printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n", + __FUNCTION__); + if (buf->value) { + free(buf->value); + buf->value = NULL; + } + buf->length = 0; + return -1; +} + + +int +serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime) +{ + OM_uint32 maj_stat, min_stat; + void *return_ctx = 0; + OM_uint32 vers; + gss_krb5_lucid_context_v1_t *lctx = 0; + int retcode = 0; + + printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__); + maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, + 1, &return_ctx); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_export_lucid_sec_context", + maj_stat, min_stat, &krb5oid); + goto out_err; + } + + /* Check the version returned, we only support v1 right now */ + vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version; + switch (vers) { + case 1: + lctx = (gss_krb5_lucid_context_v1_t *) return_ctx; + break; + default: + printerr(0, "ERROR: unsupported lucid sec context version %d\n", + vers); + goto out_err; + break; + } + + /* + * Now lctx points to a lucid context that we can send down to kernel + * + * Note: we send down different information to the kernel depending + * on the protocol version and the enctyption type. + * For protocol version 0 with all enctypes besides DES3, we use + * the original format. For protocol version != 0 or DES3, we + * send down the new style information. + */ + + if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4) + retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime); + else + retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime); + + maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_free_lucid_sec_context", + maj_stat, min_stat, &krb5oid); + printerr(0, "WARN: failed to free lucid sec context\n"); + } + + if (retcode) { + printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n", + __FUNCTION__, retcode); + goto out_err; + } + + return 0; + +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + return -1; +} + + + +#endif /* HAVE_LUCID_CONTEXT_SUPPORT */ diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c new file mode 100644 index 0000000..fad6756 --- /dev/null +++ b/utils/gssd/context_mit.c @@ -0,0 +1,280 @@ +/* + Copyright (c) 2004-2006 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef HAVE_LUCID_CONTEXT_SUPPORT +#ifdef HAVE_KRB5 + +#include +#include +#include +#include +#include +#include +#include +#include "gss_util.h" +#include "gss_oids.h" +#include "err_util.h" +#include "context.h" + +#include + +#if (KRB5_VERSION > 131) +/* XXX argggg, there's gotta be a better way than just duplicating this + * whole struct. Unfortunately, this is in a "private" header file, + * so this is our best choice at this point :-/ + */ + +typedef struct _krb5_gss_ctx_id_rec { + unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */ + unsigned int established : 1; + unsigned int big_endian : 1; + unsigned int have_acceptor_subkey : 1; + unsigned int seed_init : 1; /* XXX tested but never actually set */ +#ifdef CFX_EXERCISE + unsigned int testing_unknown_tokid : 1; /* for testing only */ +#endif + OM_uint32 gss_flags; + unsigned char seed[16]; + krb5_principal here; + krb5_principal there; + krb5_keyblock *subkey; + int signalg; + size_t cksum_size; + int sealalg; + krb5_keyblock *enc; + krb5_keyblock *seq; + krb5_timestamp endtime; + krb5_flags krb_flags; + /* XXX these used to be signed. the old spec is inspecific, and + the new spec specifies unsigned. I don't believe that the change + affects the wire encoding. */ + uint64_t seq_send; /* gssint_uint64 */ + uint64_t seq_recv; /* gssint_uint64 */ + void *seqstate; + krb5_auth_context auth_context; + gss_OID_desc *mech_used; /* gss_OID_desc */ + /* Protocol spec revision + 0 => RFC 1964 with 3DES and RC4 enhancements + 1 => draft-ietf-krb-wg-gssapi-cfx-01 + No others defined so far. */ + int proto; + krb5_cksumtype cksumtype; /* for "main" subkey */ + krb5_keyblock *acceptor_subkey; /* CFX only */ + krb5_cksumtype acceptor_subkey_cksumtype; +#ifdef CFX_EXERCISE + gss_buffer_desc init_token; +#endif +} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; + +#else /* KRB5_VERSION > 131 */ + +typedef struct _krb5_gss_ctx_id_rec { + int initiate; + u_int32_t gss_flags; + int seed_init; + unsigned char seed[16]; + krb5_principal here; + krb5_principal there; + krb5_keyblock *subkey; + int signalg; + int cksum_size; + int sealalg; + krb5_keyblock *enc; + krb5_keyblock *seq; + krb5_timestamp endtime; + krb5_flags krb_flags; + krb5_ui_4 seq_send; + krb5_ui_4 seq_recv; + void *seqstate; + int established; + int big_endian; + krb5_auth_context auth_context; + gss_OID_desc *mech_used; + int nctypes; + krb5_cksumtype *ctypes; +} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; + +#endif /* KRB5_VERSION */ + + +static int +write_keyblock(char **p, char *end, struct _krb5_keyblock *arg) +{ + gss_buffer_desc tmp; + + if (WRITE_BYTES(p, end, arg->enctype)) return -1; + tmp.length = arg->length; + tmp.value = arg->contents; + if (write_buffer(p, end, &tmp)) return -1; + return 0; +} + +/* + * We really shouldn't know about glue-layer context structure, but + * we need to get at the real krb5 context pointer. This should be + * removed as soon as we say there is no support for MIT Kerberos + * prior to 1.4 -- which gives us "legal" access to the context info. + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +int +serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime) +{ + krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)(*ctx))->internal_ctx_id; + char *p, *end; + static int constant_zero = 0; + static int constant_one = 1; + static int constant_two = 2; + uint32_t word_seq_send; + u_int64_t seq_send_64bit; + uint32_t v2_flags = 0; + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + switch (kctx->enc->enctype) { + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_DES_CBC_MD4: + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_RAW: + /* Old format of context to the kernel */ + if (kctx->initiate) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + if (kctx->seed_init) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) + goto out_err; + if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; + if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; + if (endtime) + *endtime = kctx->endtime; + word_seq_send = kctx->seq_send; + if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; + if (write_oid(&p, end, kctx->mech_used)) goto out_err; + + printerr(2, "serialize_krb5_ctx: serializing keys with " + "enctype %d and length %d\n", + kctx->enc->enctype, kctx->enc->length); + + if (write_keyblock(&p, end, kctx->enc)) goto out_err; + if (write_keyblock(&p, end, kctx->seq)) goto out_err; + break; + case ENCTYPE_DES3_CBC_RAW: + case ENCTYPE_DES3_CBC_SHA1: + case ENCTYPE_ARCFOUR_HMAC: + case ENCTYPE_ARCFOUR_HMAC_EXP: + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: + /* New format of context to the kernel */ + /* u32 flags; + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 + * #define KRB5_CTX_FLAG_CFX 0x00000002 + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 + * s32 endtime; + * u64 seq_send; + * u32 enctype; + * rawkey data + */ + + if (kctx->initiate) + v2_flags |= KRB5_CTX_FLAG_INITIATOR; + if (kctx->proto == 1) + v2_flags |= KRB5_CTX_FLAG_CFX; + if (kctx->have_acceptor_subkey) + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY; + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; + + seq_send_64bit = kctx->seq_send; + if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err; + + if (kctx->have_acceptor_subkey) { + if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype)) + goto out_err; + printerr(2, "serialize_krb5_ctx: serializing subkey " + "with enctype %d and size %d\n", + kctx->acceptor_subkey->enctype, + kctx->acceptor_subkey->length); + + if (write_bytes(&p, end, + kctx->acceptor_subkey->contents, + kctx->acceptor_subkey->length)) + goto out_err; + } else { + if (WRITE_BYTES(&p, end, kctx->enc->enctype)) + goto out_err; + printerr(2, "serialize_krb5_ctx: serializing key " + "with enctype %d and size %d\n", + kctx->enc->enctype, kctx->enc->length); + + if (write_bytes(&p, end, kctx->enc->contents, + kctx->enc->length)) + goto out_err; + } + break; + default: + printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption " + "algorithm %d\n", kctx->enc->enctype); + goto out_err; + } + + buf->length = p - (char *)buf->value; + return 0; + +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + if (buf->value) { + free(buf->value); + } + buf->value = NULL; + buf->length = 0; + return -1; +} + +#endif /* HAVE_KRB5 */ +#endif /* HAVE_LUCID_CONTEXT_SUPPORT */ diff --git a/utils/gssd/err_util.c b/utils/gssd/err_util.c new file mode 100644 index 0000000..27abd23 --- /dev/null +++ b/utils/gssd/err_util.c @@ -0,0 +1,86 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include "xlog.h" +#include "err_util.h" + +static int verbosity = 0; +static int fg = 0; + +void initerr(char *progname, int set_verbosity, int set_fg) +{ + verbosity = set_verbosity; + fg = set_fg; + if (!fg) + xlog_open(progname); +} + + +void printerr(int priority, char *format, ...) +{ + va_list args; + + /* Don't bother formatting a message we're never going to print! */ + if (priority > verbosity) + return; + + va_start(args, format); + if (fg) + vfprintf(stderr, format, args); + else + xlog_backend(L_ERROR, format, args); + va_end(args); +} + +int get_verbosity(void) +{ + return verbosity; +} + +char * +sec2time(int value) +{ + static char buf[BUFSIZ]; + int hr, min, sec; + + hr = (value / 3600); + min = (value - (3600*hr))/60; + sec = (value - (3600*hr) - (min*60)); + sprintf(buf, "%dh:%dm:%ds", hr, min, sec); + return(buf); +} + diff --git a/utils/gssd/err_util.h b/utils/gssd/err_util.h new file mode 100644 index 0000000..6fa9d3d --- /dev/null +++ b/utils/gssd/err_util.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _ERR_UTIL_H_ +#define _ERR_UTIL_H_ + +void initerr(char *progname, int verbosity, int fg); +void printerr(int priority, char *format, ...); +int get_verbosity(void); +char * sec2time(int); + +#endif /* _ERR_UTIL_H_ */ diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c new file mode 100644 index 0000000..982b96f --- /dev/null +++ b/utils/gssd/gss_names.c @@ -0,0 +1,141 @@ +/* + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2002 Bruce Fields + + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svcgssd.h" +#include "gss_util.h" +#include "gss_names.h" +#include "err_util.h" +#include "context.h" +#include "misc.h" +#include "gss_oids.h" +#include "svcgssd_krb5.h" + +static int +get_krb5_hostbased_name(gss_buffer_desc *name, char **hostbased_name) +{ + char *p, *sname = NULL; + if (strchr(name->value, '@') && strchr(name->value, '/')) { + if ((sname = calloc(name->length, 1)) == NULL) { + printerr(0, "ERROR: get_krb5_hostbased_name failed " + "to allocate %d bytes\n", name->length); + return -1; + } + /* read in name and instance and replace '/' with '@' */ + sscanf(name->value, "%[^@]", sname); + p = strrchr(sname, '/'); + if (p == NULL) { /* The '@' preceeded the '/' */ + free(sname); + return -1; + } + *p = '@'; + } + *hostbased_name = sname; + return 0; +} + +int +get_hostbased_client_name(gss_name_t client_name, gss_OID mech, + char **hostbased_name) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; + gss_OID name_type = GSS_C_NO_OID; + char *cname; + int res = -1; + + *hostbased_name = NULL; /* preset in case we fail */ + + /* Get the client's gss authenticated name */ + maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("get_hostbased_client_name: gss_display_name", + maj_stat, min_stat, mech); + goto out_err; + } + if (name.length >= 0xffff) { /* don't overflow */ + printerr(0, "ERROR: get_hostbased_client_name: " + "received gss_name is too long (%d bytes)\n", + name.length); + goto out_rel_buf; + } + + /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to + * an NT_HOSTBASED_SERVICE name */ + if (g_OID_equal(&krb5oid, mech)) { + if (get_krb5_hostbased_name(&name, &cname) != 0) + goto out_rel_buf; + *hostbased_name = cname; + } else { + printerr(1, "WARNING: unknown/unsupport mech OID\n"); + goto out_rel_buf; + } + + res = 0; +out_rel_buf: + gss_release_buffer(&min_stat, &name); +out_err: + return res; +} + +void +get_hostbased_client_buffer(gss_name_t client_name, gss_OID mech, + gss_buffer_t buf) +{ + char *hname; + + if (!get_hostbased_client_name(client_name, mech, &hname)) { + buf->length = strlen(hname) + 1; + buf->value = hname; + } else { + buf->length = 0; + buf->value = NULL; + } +} diff --git a/utils/gssd/gss_names.h b/utils/gssd/gss_names.h new file mode 100644 index 0000000..ce182f7 --- /dev/null +++ b/utils/gssd/gss_names.h @@ -0,0 +1,36 @@ +/* + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2002 Bruce Fields + + 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 University 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 ``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 REGENTS 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. +*/ + +extern int get_hostbased_client_name(gss_name_t client_name, gss_OID mech, + char **hostbased_name); +extern void get_hostbased_client_buffer(gss_name_t client_name, + gss_OID mech, gss_buffer_t buf); diff --git a/utils/gssd/gss_oids.c b/utils/gssd/gss_oids.c new file mode 100644 index 0000000..4362de2 --- /dev/null +++ b/utils/gssd/gss_oids.c @@ -0,0 +1,40 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/* from kerberos source, gssapi_krb5.c */ +gss_OID_desc krb5oid = + {9, "\052\206\110\206\367\022\001\002\002"}; diff --git a/utils/gssd/gss_oids.h b/utils/gssd/gss_oids.h new file mode 100644 index 0000000..fde8532 --- /dev/null +++ b/utils/gssd/gss_oids.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _GSS_OIDS_H_ +#define _GSS_OIDS_H_ + +#include + +extern gss_OID_desc krb5oid; + +#ifndef g_OID_equal +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0)) +#endif + +#endif /* _GSS_OIDS_H_ */ diff --git a/utils/gssd/gss_util.c b/utils/gssd/gss_util.c new file mode 100644 index 0000000..a4b2777 --- /dev/null +++ b/utils/gssd/gss_util.c @@ -0,0 +1,347 @@ +/* + * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from + * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson + * J. Bruce Fields + * Marius Aamodt Eriksen + */ + +/* + * slave/kprop.c + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Copyright 1994 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE) +#include +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif +#include "gss_util.h" +#include "err_util.h" +#include "gssd.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_COM_ERR_H +#include +#endif + +/* Global gssd_credentials handle */ +gss_cred_id_t gssd_creds; + +gss_OID g_mechOid = GSS_C_NULL_OID; + +#if 0 +static void +display_status_1(char *m, u_int32_t code, int type, const gss_OID mech) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; + u_int32_t msg_ctx = 0; + char *typestr; + + switch (type) { + case GSS_C_GSS_CODE: + typestr = "GSS"; + break; + case GSS_C_MECH_CODE: + typestr = "mechanism"; + break; + default: + return; + /* NOTREACHED */ + } + + for (;;) { + maj_stat = gss_display_status(&min_stat, code, + type, mech, &msg_ctx, &msg); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "ERROR: in call to " + "gss_display_status called from %s\n", m); + break; + } else { + printerr(0, "ERROR: GSS-API: (%s) error in %s(): %s\n", + typestr, m, (char *)msg.value); + } + + if (msg.length != 0) + (void) gss_release_buffer(&min_stat, &msg); + + if (msg_ctx == 0) + break; + } +} +#endif +static char * +gss_display_error(OM_uint32 status) +{ + char *error = NULL; + + switch(status) { + case GSS_S_COMPLETE: + error = "GSS_S_COMPLETE"; + break; + case GSS_S_CALL_INACCESSIBLE_READ: + error = "GSS_S_CALL_INACCESSIBLE_READ"; + break; + case GSS_S_CALL_INACCESSIBLE_WRITE: + error = "GSS_S_CALL_INACCESSIBLE_WRITE"; + break; + case GSS_S_CALL_BAD_STRUCTURE: + error = "GSS_S_CALL_BAD_STRUCTURE"; + break; + case GSS_S_BAD_MECH: + error = "GSS_S_BAD_MECH"; + break; + case GSS_S_BAD_NAME: + error = "GSS_S_BAD_NAME"; + break; + case GSS_S_BAD_NAMETYPE: + error = "GSS_S_BAD_NAMETYPE"; + break; + case GSS_S_BAD_BINDINGS: + error = "GSS_S_BAD_BINDINGS"; + break; + case GSS_S_BAD_STATUS: + error = "GSS_S_BAD_STATUS"; + break; + case GSS_S_BAD_SIG: + error = "GSS_S_BAD_SIG"; + break; + case GSS_S_NO_CRED: + error = "GSS_S_NO_CRED"; + break; + case GSS_S_NO_CONTEXT: + error = "GSS_S_NO_CONTEXT"; + break; + case GSS_S_DEFECTIVE_TOKEN: + error = "GSS_S_DEFECTIVE_TOKEN"; + break; + case GSS_S_DEFECTIVE_CREDENTIAL: + error = "GSS_S_DEFECTIVE_CREDENTIAL"; + break; + case GSS_S_CREDENTIALS_EXPIRED: + error = "GSS_S_CREDENTIALS_EXPIRED"; + break; + case GSS_S_CONTEXT_EXPIRED: + error = "GSS_S_CONTEXT_EXPIRED"; + break; + case GSS_S_FAILURE: + error = "GSS_S_FAILURE"; + break; + case GSS_S_BAD_QOP: + error = "GSS_S_BAD_QOP"; + break; + case GSS_S_UNAUTHORIZED: + error = "GSS_S_UNAUTHORIZED"; + break; + case GSS_S_UNAVAILABLE: + error = "GSS_S_UNAVAILABLE"; + break; + case GSS_S_DUPLICATE_ELEMENT: + error = "GSS_S_DUPLICATE_ELEMENT"; + break; + case GSS_S_NAME_NOT_MN: + error = "GSS_S_NAME_NOT_MN"; + break; + default: + error = "Not defined"; + } + return error; +} + +static void +display_status_2(char *m, u_int32_t major, u_int32_t minor, const gss_OID mech) +{ + u_int32_t maj_stat1, min_stat1; + u_int32_t maj_stat2, min_stat2; + gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER; + gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER; + char maj_buf[30], min_buf[30]; + char *maj, *min; + u_int32_t msg_ctx = 0; + int msg_verbosity = 0; + + /* Get major status message */ + maj_stat1 = gss_display_status(&min_stat1, major, + GSS_C_GSS_CODE, mech, &msg_ctx, &maj_gss_buf); + + if (maj_stat1 != GSS_S_COMPLETE) { + snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major); + maj = &maj_buf[0]; + } else { + maj = maj_gss_buf.value; + } + + /* Get minor status message */ + maj_stat2 = gss_display_status(&min_stat2, minor, + GSS_C_MECH_CODE, mech, &msg_ctx, &min_gss_buf); + + if (maj_stat2 != GSS_S_COMPLETE) { + snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor); + min = &min_buf[0]; + } else { + min = min_gss_buf.value; + } + + if (major == GSS_S_CREDENTIALS_EXPIRED) + msg_verbosity = 1; + + printerr(msg_verbosity, "ERROR: GSS-API: error in %s(): %s (%s) - %s\n", + m, gss_display_error(major), maj, min); + + if (maj_gss_buf.length != 0) + (void) gss_release_buffer(&min_stat1, &maj_gss_buf); + if (min_gss_buf.length != 0) + (void) gss_release_buffer(&min_stat2, &min_gss_buf); +} + +void +pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, const gss_OID mech) +{ + display_status_2(msg, maj_stat, min_stat, mech); +} + +int +gssd_acquire_cred(char *server_name, const gss_OID oid) +{ + gss_buffer_desc name; + gss_name_t target_name; + u_int32_t maj_stat, min_stat; + u_int32_t ignore_maj_stat, ignore_min_stat; + gss_buffer_desc pbuf; + + /* If server_name is NULL, get cred for GSS_C_NO_NAME */ + if (server_name == NULL) { + target_name = GSS_C_NO_NAME; + } else { + name.value = (void *)server_name; + name.length = strlen(server_name); + + maj_stat = gss_import_name(&min_stat, &name, + oid, + &target_name); + + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); + return (FALSE); + } + } + + maj_stat = gss_acquire_cred(&min_stat, target_name, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, + &gssd_creds, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_acquire_cred", maj_stat, min_stat, g_mechOid); + ignore_maj_stat = gss_display_name(&ignore_min_stat, + target_name, &pbuf, NULL); + if (ignore_maj_stat == GSS_S_COMPLETE) { + printerr(1, "Unable to obtain credentials for '%.*s'\n", + pbuf.length, pbuf.value); + ignore_maj_stat = gss_release_buffer(&ignore_min_stat, + &pbuf); + } + } + + ignore_maj_stat = gss_release_name(&ignore_min_stat, &target_name); + + return (maj_stat == GSS_S_COMPLETE); +} + +int gssd_check_mechs(void) +{ + u_int32_t maj_stat, min_stat; + gss_OID_set supported_mechs = GSS_C_NO_OID_SET; + int retval = -1; + + maj_stat = gss_indicate_mechs(&min_stat, &supported_mechs); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "Unable to obtain list of supported mechanisms. " + "Check that gss library is properly configured.\n"); + goto out; + } + if (supported_mechs == GSS_C_NO_OID_SET || + supported_mechs->count == 0) { + printerr(0, "Unable to obtain list of supported mechanisms. " + "Check that gss library is properly configured.\n"); + goto out; + } + maj_stat = gss_release_oid_set(&min_stat, &supported_mechs); + retval = 0; +out: + return retval; +} + +void +gssd_cleanup(void) +{ + u_int32_t min_stat; + gss_release_cred(&min_stat, &gssd_creds); +} diff --git a/utils/gssd/gss_util.h b/utils/gssd/gss_util.h new file mode 100644 index 0000000..4da64e3 --- /dev/null +++ b/utils/gssd/gss_util.h @@ -0,0 +1,56 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _GSS_UTIL_H_ +#define _GSS_UTIL_H_ + +#include +#include +#include "write_bytes.h" + +extern gss_cred_id_t gssd_creds; + +int gssd_acquire_cred(char *server_name, const gss_OID oid); +void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, + const gss_OID mech); +int gssd_check_mechs(void); +void gssd_cleanup(void); + +#ifndef HAVE_LIBGSSGLUE +#include +#define gss_free_lucid_sec_context(min, ctx, ret) \ + gss_krb5_free_lucid_sec_context(min, ret) + +#define gss_export_lucid_sec_context gss_krb5_export_lucid_sec_context +#define gss_set_allowable_enctypes(min, cred, oid, num, types) \ + gss_krb5_set_allowable_enctypes(min, cred, num, types) +#endif + +#endif /* _GSS_UTIL_H_ */ diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c new file mode 100644 index 0000000..ca9b326 --- /dev/null +++ b/utils/gssd/gssd.c @@ -0,0 +1,1320 @@ +/* + gssd.c + + Copyright (c) 2000, 2004 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2002 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + All rights reserved, all wrongs reversed. + + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "krb5_util.h" +#include "nfslib.h" +#include "conffile.h" + +static char *pipefs_path = GSSD_PIPEFS_DIR; +static DIR *pipefs_dir; +static int pipefs_fd; +static int inotify_fd; +struct event *inotify_ev; + +char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; +char **ccachesearch; +int use_memcache = 0; +int root_uses_machine_creds = 1; +unsigned int context_timeout = 0; +unsigned int rpc_timeout = 5; +char *preferred_realm = NULL; +char *ccachedir = NULL; +/* set $HOME to "/" by default */ +static bool set_home = true; +/* Avoid DNS reverse lookups on server names */ +static bool avoid_dns = true; +static bool use_gssproxy = false; +pthread_mutex_t clp_lock = PTHREAD_MUTEX_INITIALIZER; +static bool signal_received = false; +static struct event_base *evbase = NULL; + +int upcall_timeout = DEF_UPCALL_TIMEOUT; +static bool cancel_timed_out_upcalls = false; + +TAILQ_HEAD(topdir_list_head, topdir) topdir_list; + +/* + * active_thread_list: + * + * used to track upcalls for timeout purposes. + * + * protected by the active_thread_list_lock mutex. + * + * upcall_thread_info structures are added to the tail of the list + * by start_upcall_thread(), so entries closer to the head of the list + * will be closer to hitting the upcall timeout. + * + * upcall_thread_info structures are removed from the list upon a + * sucessful join of the upcall thread by the watchdog thread (via + * scan_active_thread_list(). + */ +TAILQ_HEAD(active_thread_list_head, upcall_thread_info) active_thread_list; +pthread_mutex_t active_thread_list_lock = PTHREAD_MUTEX_INITIALIZER; + +struct topdir { + TAILQ_ENTRY(topdir) list; + TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; + int wd; + char name[]; +}; + +/* + * topdir_list: + * linked list of struct topdir with basic data about a topdir. + * + * clnt_list: + * linked list of struct clnt_info with basic data about a clntXXX dir, + * one per topdir. + * + * Directory structure: created by the kernel + * {rpc_pipefs}/{topdir}/clntXX : one per rpc_clnt struct in the kernel + * {rpc_pipefs}/{topdir}/clntXX/krb5 : read uid for which kernel wants + * a context, write the resulting context + * {rpc_pipefs}/{topdir}/clntXX/info : stores info such as server name + * {rpc_pipefs}/{topdir}/clntXX/gssd : pipe for all gss mechanisms using + * a text-based string of parameters + * + * Algorithm: + * Poll all {rpc_pipefs}/{topdir}/clntXX/YYYY files. When data is ready, + * read and process; performs rpcsec_gss context initialization protocol to + * get a cred for that user. Writes result to corresponding krb5 file + * in a form the kernel code will understand. + * In addition, we make sure we are notified whenever anything is + * created or destroyed in {rpc_pipefs} or in any of the clntXX directories, + * and rescan the whole {rpc_pipefs} when this happens. + */ + +/* + * convert a presentation address string to a sockaddr_storage struct. Returns + * true on success or false on failure. + * + * Note that we do not populate the sin6_scope_id field here for IPv6 addrs. + * gssd nececessarily relies on hostname resolution and DNS AAAA records + * do not generally contain scope-id's. This means that GSSAPI auth really + * can't work with IPv6 link-local addresses. + * + * We *could* consider changing this if we did something like adopt the + * Microsoft "standard" of using the ipv6-literal.net domainname, but it's + * not really feasible at present. + */ +static bool +gssd_addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port) +{ + int rc; + struct addrinfo *res; + struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV }; + +#ifndef IPV6_SUPPORTED + hints.ai_family = AF_INET; +#endif /* IPV6_SUPPORTED */ + + rc = getaddrinfo(node, port, &hints, &res); + if (rc) { + printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n", + node, port, + rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc)); + return false; + } + +#ifdef IPV6_SUPPORTED + /* + * getnameinfo ignores the scopeid. If the address turns out to have + * a non-zero scopeid, we can't use it -- the resolved host might be + * completely different from the one intended. + */ + if (res->ai_addr->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr; + if (sin6->sin6_scope_id) { + printerr(0, "ERROR: address %s has non-zero " + "sin6_scope_id!\n", node); + nfs_freeaddrinfo(res); + return false; + } + } +#endif /* IPV6_SUPPORTED */ + + memcpy(sa, res->ai_addr, res->ai_addrlen); + nfs_freeaddrinfo(res); + return true; +} + +/* + * convert a sockaddr to a hostname + */ +static char * +gssd_get_servername(const char *name, const struct sockaddr *sa, const char *addr) +{ + socklen_t addrlen; + int err; + char hbuf[NI_MAXHOST]; + unsigned char buf[sizeof(struct in6_addr)]; + + while (avoid_dns) { + /* + * Determine if this is a server name, or an IP address. + * If it is an IP address, do the DNS lookup otherwise + * skip the DNS lookup. + */ + if (strchr(name, '.') == NULL) + break; /* local name */ + else if (inet_pton(AF_INET, name, buf) == 1) + break; /* IPv4 address */ + else if (inet_pton(AF_INET6, name, buf) == 1) + break; /* IPv6 addrss */ + + return strdup(name); + } + + switch (sa->sa_family) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; +#ifdef IPV6_SUPPORTED + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; +#endif /* IPV6_SUPPORTED */ + default: + printerr(0, "ERROR: unrecognized addr family %d\n", + sa->sa_family); + return NULL; + } + + err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0, + NI_NAMEREQD); + if (err) { + printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", + addr, err == EAI_SYSTEM ? strerror(errno) : + gai_strerror(err)); + return NULL; + } + + return strdup(hbuf); +} + +static void +gssd_read_service_info(int dirfd, struct clnt_info *clp) +{ + int fd; + FILE *info = NULL; + int numfields; + char *server = NULL; + char *service = NULL; + int program; + int version; + char *address = NULL; + char *protoname = NULL; + char *port = NULL; + char *servername = NULL; + + fd = openat(dirfd, "info", O_RDONLY); + if (fd < 0) { + printerr(0, "ERROR: can't open %s/info: %s\n", + clp->relpath, strerror(errno)); + goto fail; + } + + info = fdopen(fd, "r"); + if (!info) { + printerr(0, "ERROR: can't fdopen %s/info: %s\n", + clp->relpath, strerror(errno)); + close(fd); + goto fail; + } + + /* + * Some history: + * + * The first three lines were added with rpc_pipefs in 2003-01-13. + * (commit af2f003391786fb632889c02142c941b212ba4ff) + * + * The 'protocol' line was added in 2003-06-11. + * (commit 9bd741ae48785d0c0e75cf906ff66f893d600c2d) + * + * The 'port' line was added in 2007-09-26. + * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe) + */ + numfields = fscanf(info, + "RPC server: %ms\n" + "service: %ms (%d) version %d\n" + "address: %ms\n" + "protocol: %ms\n" + "port: %ms\n", + &server, + &service, &program, &version, + &address, + &protoname, + &port); + + + switch (numfields) { + case 5: + protoname = strdup("tcp"); + if (!protoname) + goto fail; + /* fall through */ + case 6: + /* fall through */ + case 7: + break; + default: + goto fail; + } + + /* + * The user space RPC library has no support for + * RPC-over-RDMA at this time, so change 'rdma' + * to 'tcp', and '20049' to '2049'. + */ + if (strcmp(protoname, "rdma") == 0) { + free(protoname); + protoname = strdup("tcp"); + if (!protoname) + goto fail; + free(port); + port = strdup("2049"); + if (!port) + goto fail; + } + + if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr, + address, port ? port : "")) + goto fail; + + servername = gssd_get_servername(server, (struct sockaddr *)&clp->addr, address); + if (!servername) + goto fail; + + if (asprintf(&clp->servicename, "%s@%s", service, servername) < 0) + goto fail; + + clp->servername = servername; + clp->prog = program; + clp->vers = version; + clp->protocol = protoname; + + goto out; + +fail: + printerr(0, "ERROR: failed to parse %s/info\n", clp->relpath); + clp->upcall_address = strdup(address); + clp->upcall_port = strdup(port); + clp->upcall_program = program; + clp->upcall_vers = version; + clp->upcall_protoname = strdup(protoname); + clp->upcall_service = strdup(service); + free(servername); + free(protoname); + clp->servicename = NULL; + clp->servername = NULL; + clp->prog = 0; + clp->vers = 0; + clp->protocol = NULL; +out: + if (info) + fclose(info); + + free(server); + free(service); + free(address); + free(port); +} + +/* Actually frees clp and fields that might be used from other + * threads if was last reference. + */ +void +gssd_free_client(struct clnt_info *clp) +{ + int refcnt; + + pthread_mutex_lock(&clp_lock); + refcnt = --clp->refcount; + pthread_mutex_unlock(&clp_lock); + if (refcnt > 0) + return; + + printerr(4, "freeing client %s\n", clp->relpath); + + if (clp->krb5_fd >= 0) + close(clp->krb5_fd); + + if (clp->gssd_fd >= 0) + close(clp->gssd_fd); + + free(clp->relpath); + free(clp->servicename); + free(clp->servername); + free(clp->protocol); + if (!clp->servername) { + if (clp->upcall_address) + free(clp->upcall_address); + if (clp->upcall_port) + free(clp->upcall_port); + if (clp->upcall_protoname) + free(clp->upcall_protoname); + if (clp->upcall_service) + free(clp->upcall_service); + } + free(clp); +} + +/* Called when removing from clnt_list to tear down event handling. + * Will then free clp if was last reference. + */ +static void +gssd_destroy_client(struct clnt_info *clp) +{ + printerr(4, "destroying client %s\n", clp->relpath); + + if (clp->krb5_ev) { + event_del(clp->krb5_ev); + event_free(clp->krb5_ev); + clp->krb5_ev = NULL; + } + + if (clp->gssd_ev) { + event_del(clp->gssd_ev); + event_free(clp->gssd_ev); + clp->gssd_ev = NULL; + } + + inotify_rm_watch(inotify_fd, clp->wd); + gssd_free_client(clp); +} + +static void gssd_scan(void); + +/* For each upcall read the upcall info into the buffer, then create a + * thread in a detached state so that resources are released back into + * the system without the need for a join. + */ +static void +gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) +{ + struct clnt_info *clp = data; + + /* if there was a failure to translate IP to name for this server, + * try again + */ + if (!clp->servername) { + if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr, + clp->upcall_address, clp->upcall_port ? + clp->upcall_port : "")) { + goto do_upcall; + } + clp->servername = gssd_get_servername(clp->upcall_address, + (struct sockaddr *)&clp->addr, clp->upcall_address); + if (!clp->servername) + goto do_upcall; + + if (asprintf(&clp->servicename, "%s@%s", clp->upcall_service, + clp->servername) < 0) { + free(clp->servername); + clp->servername = NULL; + goto do_upcall; + } + clp->prog = clp->upcall_program; + clp->vers = clp->upcall_vers; + clp->protocol = strdup(clp->upcall_protoname); + } +do_upcall: + handle_gssd_upcall(clp); +} + +static void +gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) +{ + struct clnt_info *clp = data; + + handle_krb5_upcall(clp); +} + +/* + * scan_active_thread_list: + * + * Walks the active_thread_list, trying to join as many upcall threads as + * possible. For threads that have terminated, the corresponding + * upcall_thread_info will be removed from the list and freed. Threads that + * are still busy and have exceeded the upcall_timeout will cause an error to + * be logged and may be canceled (depending on the value of + * cancel_timed_out_upcalls). + * + * Returns the number of seconds that the watchdog thread should wait before + * calling scan_active_thread_list() again. + */ +static int +scan_active_thread_list(void) +{ + struct upcall_thread_info *info; + struct timespec now; + unsigned int sleeptime; + bool sleeptime_set = false; + int err; + void *tret, *saveprev; + + sleeptime = upcall_timeout; + pthread_mutex_lock(&active_thread_list_lock); + clock_gettime(CLOCK_MONOTONIC, &now); + TAILQ_FOREACH(info, &active_thread_list, list) { + err = pthread_tryjoin_np(info->tid, &tret); + switch (err) { + case 0: + /* + * The upcall thread has either completed successfully, or + * has been canceled _and_ has acted on the cancellation request + * (i.e. has hit a cancellation point). We can now remove the + * upcall_thread_info from the list and free it. + */ + if (tret == PTHREAD_CANCELED) + printerr(2, "watchdog: thread id 0x%lx cancelled successfully\n", + info->tid); + saveprev = info->list.tqe_prev; + TAILQ_REMOVE(&active_thread_list, info, list); + free(info); + info = saveprev; + break; + case EBUSY: + /* + * The upcall thread is still running. If the timeout has expired + * then we either cancel the thread, log an error, and do an error + * downcall to the kernel (cancel_timed_out_upcalls=true) or simply + * log an error (cancel_timed_out_upcalls=false). In either case, + * the error is logged only once. + */ + if (now.tv_sec >= info->timeout.tv_sec) { + if (cancel_timed_out_upcalls && !(info->flags & UPCALL_THREAD_CANCELED)) { + printerr(0, "watchdog: thread id 0x%lx timed out\n", + info->tid); + pthread_cancel(info->tid); + info->flags |= (UPCALL_THREAD_CANCELED|UPCALL_THREAD_WARNED); + do_error_downcall(info->fd, info->uid, -ETIMEDOUT); + } else { + if (!(info->flags & UPCALL_THREAD_WARNED)) { + printerr(0, "watchdog: thread id 0x%lx running for %ld seconds\n", + info->tid, + now.tv_sec - info->timeout.tv_sec + upcall_timeout); + info->flags |= UPCALL_THREAD_WARNED; + } + } + } else if (!sleeptime_set) { + /* + * The upcall thread is still running, but the timeout has not yet + * expired. Calculate the time remaining until the timeout will + * expire. This is the amount of time the watchdog thread will + * wait before running again. We only need to do this for the busy + * thread closest to the head of the list - entries appearing later + * in the list will time out later. + */ + sleeptime = info->timeout.tv_sec - now.tv_sec; + sleeptime_set = true; + } + break; + default: + /* EDEADLK, EINVAL, and ESRCH... none of which should happen! */ + printerr(0, "watchdog: attempt to join thread id 0x%lx returned %d (%s)!\n", + info->tid, err, strerror(err)); + break; + } + } + pthread_mutex_unlock(&active_thread_list_lock); + + return sleeptime; +} + +static void * +watchdog_thread_fn(void *UNUSED(arg)) +{ + unsigned int sleeptime; + + for (;;) { + sleeptime = scan_active_thread_list(); + printerr(4, "watchdog: sleeping %u secs\n", sleeptime); + sleep(sleeptime); + } + return (void *)0; +} + +static int +start_watchdog_thread(void) +{ + pthread_attr_t attr; + pthread_t th; + int ret; + + ret = pthread_attr_init(&attr); + if (ret != 0) { + printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n", + ret, strerror(errno)); + return ret; + } + ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (ret != 0) { + printerr(0, "ERROR: failed to create pthread attr: ret %d: %s\n", + ret, strerror(errno)); + return ret; + } + ret = pthread_create(&th, &attr, watchdog_thread_fn, NULL); + if (ret != 0) { + printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", + ret, strerror(errno)); + } + return ret; +} + +static struct clnt_info * +gssd_get_clnt(struct topdir *tdi, const char *name) +{ + struct clnt_info *clp; + + TAILQ_FOREACH(clp, &tdi->clnt_list, list) + if (!strcmp(clp->name, name)) + return clp; + + printerr(4, "creating client %s/%s\n", tdi->name, name); + + clp = calloc(1, sizeof(struct clnt_info)); + if (!clp) { + printerr(0, "ERROR: can't malloc clnt_info: %s\n", + strerror(errno)); + return NULL; + } + + if (asprintf(&clp->relpath, "%s/%s", tdi->name, name) < 0) { + clp->relpath = NULL; + goto out; + } + + clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE); + if (clp->wd < 0) { + if (errno != ENOENT) + printerr(0, "ERROR: %s: inotify_add_watch failed for %s: %s\n", + __FUNCTION__, clp->relpath, strerror(errno)); + goto out; + } + + clp->name = clp->relpath + strlen(tdi->name) + 1; + clp->krb5_fd = -1; + clp->gssd_fd = -1; + clp->refcount = 1; + + TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list); + return clp; + +out: + free(clp->relpath); + free(clp); + return NULL; +} + +static int +gssd_scan_clnt(struct clnt_info *clp) +{ + int clntfd; + + printerr(4, "scanning client %s\n", clp->relpath); + + clntfd = openat(pipefs_fd, clp->relpath, O_RDONLY); + if (clntfd < 0) { + if (errno != ENOENT) + printerr(0, "ERROR: %s: can't openat %s: %s\n", + __FUNCTION__, clp->relpath, strerror(errno)); + return -1; + } + + if (clp->gssd_fd == -1) + clp->gssd_fd = openat(clntfd, "gssd", O_RDWR | O_NONBLOCK); + + if (clp->gssd_fd == -1 && clp->krb5_fd == -1) + clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK); + + if (!clp->gssd_ev && clp->gssd_fd >= 0) { + clp->gssd_ev = event_new(evbase, clp->gssd_fd, EV_READ | EV_PERSIST, + gssd_clnt_gssd_cb, clp); + if (!clp->gssd_ev) { + printerr(0, "ERROR: %s: can't create gssd event for %s: %s\n", + __FUNCTION__, clp->relpath, strerror(errno)); + close(clp->gssd_fd); + clp->gssd_fd = -1; + } else { + event_add(clp->gssd_ev, NULL); + } + } + + if (!clp->krb5_ev && clp->krb5_fd >= 0) { + clp->krb5_ev = event_new(evbase, clp->krb5_fd, EV_READ | EV_PERSIST, + gssd_clnt_krb5_cb, clp); + if (!clp->krb5_ev) { + printerr(0, "ERROR: %s: can't create krb5 event for %s: %s\n", + __FUNCTION__, clp->relpath, strerror(errno)); + close(clp->krb5_fd); + clp->krb5_fd = -1; + } else { + event_add(clp->krb5_ev, NULL); + } + } + + if (clp->krb5_fd == -1 && clp->gssd_fd == -1) + /* not fatal, files might appear later */ + goto out; + + if (clp->prog == 0) + gssd_read_service_info(clntfd, clp); + +out: + close(clntfd); + clp->scanned = true; + return 0; +} + +static int +gssd_create_clnt(struct topdir *tdi, const char *name) +{ + struct clnt_info *clp; + + clp = gssd_get_clnt(tdi, name); + if (!clp) + return -1; + + return gssd_scan_clnt(clp); +} + +static struct topdir * +gssd_get_topdir(const char *name) +{ + struct topdir *tdi; + + TAILQ_FOREACH(tdi, &topdir_list, list) + if (!strcmp(tdi->name, name)) + return tdi; + + tdi = malloc(sizeof(*tdi) + strlen(name) + 1); + if (!tdi) { + printerr(0, "ERROR: Couldn't allocate struct topdir\n"); + return NULL; + } + + tdi->wd = inotify_add_watch(inotify_fd, name, IN_CREATE); + if (tdi->wd < 0) { + printerr(0, "ERROR: %s: inotify_add_watch failed for top dir %s: %s\n", + __FUNCTION__, tdi->name, strerror(errno)); + free(tdi); + return NULL; + } + + strcpy(tdi->name, name); + TAILQ_INIT(&tdi->clnt_list); + + TAILQ_INSERT_HEAD(&topdir_list, tdi, list); + return tdi; +} + +static void +gssd_scan_topdir(const char *name) +{ + struct topdir *tdi; + int dfd; + DIR *dir; + struct clnt_info *clp; + struct dirent *d; + + tdi = gssd_get_topdir(name); + if (!tdi) + return; + + dfd = openat(pipefs_fd, tdi->name, O_RDONLY); + if (dfd < 0) { + if (errno != ENOENT) + printerr(0, "ERROR: %s: can't openat %s: %s\n", + __FUNCTION__, tdi->name, strerror(errno)); + return; + } + + dir = fdopendir(dfd); + if (!dir) { + printerr(0, "ERROR: can't fdopendir %s: %s\n", + tdi->name, strerror(errno)); + return; + } + + TAILQ_FOREACH(clp, &tdi->clnt_list, list) + clp->scanned = false; + + while ((d = readdir(dir))) { + if (d->d_type != DT_DIR) + continue; + + if (strncmp(d->d_name, "clnt", strlen("clnt"))) + continue; + + gssd_create_clnt(tdi, d->d_name); + } + + closedir(dir); + + TAILQ_FOREACH(clp, &tdi->clnt_list, list) { + void *saveprev; + + if (clp->scanned) + continue; + + printerr(3, "orphaned client %s\n", clp->relpath); + saveprev = clp->list.tqe_prev; + TAILQ_REMOVE(&tdi->clnt_list, clp, list); + gssd_destroy_client(clp); + clp = saveprev; + } +} + +static void +gssd_scan(void) +{ + struct dirent *d; + + printerr(4, "doing a full rescan\n"); + rewinddir(pipefs_dir); + + while ((d = readdir(pipefs_dir))) { + if (d->d_type != DT_DIR) + continue; + + if (d->d_name[0] == '.') + continue; + + gssd_scan_topdir(d->d_name); + } + + if (TAILQ_EMPTY(&topdir_list)) { + printerr(0, "ERROR: the rpc_pipefs directory is empty!\n"); + exit(EXIT_FAILURE); + } +} + +static void +gssd_scan_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) +{ + gssd_scan(); +} + +static bool +gssd_inotify_topdir(struct topdir *tdi, const struct inotify_event *ev) +{ + printerr(5, "inotify event for topdir (%s) - " + "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", + tdi->name, ev->wd, ev->len > 0 ? ev->name : "", ev->mask); + + if (ev->mask & IN_IGNORED) { + printerr(0, "ERROR: topdir disappeared!\n"); + return false; + } + + if (ev->len == 0) + return false; + + if (ev->mask & IN_CREATE) { + if (!(ev->mask & IN_ISDIR)) + return true; + + if (strncmp(ev->name, "clnt", strlen("clnt"))) + return true; + + if (gssd_create_clnt(tdi, ev->name)) + return false; + + return true; + } + + return false; +} + +static bool +gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotify_event *ev) +{ + printerr(5, "inotify event for clntdir (%s) - " + "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", + clp->relpath, ev->wd, ev->len > 0 ? ev->name : "", ev->mask); + + if (ev->mask & IN_IGNORED) { + TAILQ_REMOVE(&tdi->clnt_list, clp, list); + gssd_destroy_client(clp); + return true; + } + + if (ev->len == 0) + return false; + + if (ev->mask & IN_CREATE) { + if (!strcmp(ev->name, "gssd") || + !strcmp(ev->name, "krb5") || + !strcmp(ev->name, "info")) + if (gssd_scan_clnt(clp)) + return false; + + return true; + + } else if (ev->mask & IN_DELETE) { + if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) { + close(clp->gssd_fd); + event_del(clp->gssd_ev); + event_free(clp->gssd_ev); + clp->gssd_ev = NULL; + clp->gssd_fd = -1; + + } else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) { + close(clp->krb5_fd); + event_del(clp->krb5_ev); + event_free(clp->krb5_ev); + clp->krb5_ev = NULL; + clp->krb5_fd = -1; + } + + return true; + } + + return false; +} + +static void +gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data)) +{ + bool rescan = false; + struct topdir *tdi; + struct clnt_info *clp; + + while (true) { + char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); + const struct inotify_event *ev; + ssize_t len; + char *ptr; + + len = read(ifd, buf, sizeof(buf)); + if (len == -1 && errno == EINTR) + continue; + + if (len <= 0) + break; + + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + ev->len) { + ev = (const struct inotify_event *)ptr; + + if (ev->mask & IN_Q_OVERFLOW) { + printerr(0, "ERROR: inotify queue overflow\n"); + rescan = true; + break; + } + + TAILQ_FOREACH(tdi, &topdir_list, list) { + if (tdi->wd == ev->wd) { + if (!gssd_inotify_topdir(tdi, ev)) + rescan = true; + goto found; + } + + TAILQ_FOREACH(clp, &tdi->clnt_list, list) { + if (clp->wd == ev->wd) { + if (!gssd_inotify_clnt(tdi, clp, ev)) + rescan = true; + goto found; + } + } + } + +found: + if (!tdi) { + printerr(5, "inotify event for unknown wd!!! - " + "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n", + ev->wd, ev->len > 0 ? ev->name : "", ev->mask); + rescan = true; + } + } + } + + if (rescan) + gssd_scan(); +} + +static void +sig_die(int signal) +{ + if (signal_received) { + gssd_destroy_krb5_principals(root_uses_machine_creds); + printerr(1, "forced exiting on signal %d\n", signal); + exit(0); + } + + signal_received = true; + printerr(1, "exiting on signal %d\n", signal); + event_base_loopexit(evbase, NULL); +} + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D] [-H] [-U upcall timeout] [-C]\n", + progname); + exit(1); +} + +inline static void +read_gss_conf(void) +{ + char *s; + + conf_init_file(NFS_CONFFILE); + use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache); + root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds", + root_uses_machine_creds); + avoid_dns = conf_get_bool("gssd", "avoid-dns", avoid_dns); +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + limit_to_legacy_enctypes = conf_get_bool("gssd", "limit-to-legacy-enctypes", + limit_to_legacy_enctypes); +#endif + context_timeout = conf_get_num("gssd", "context-timeout", context_timeout); + rpc_timeout = conf_get_num("gssd", "rpc-timeout", rpc_timeout); + upcall_timeout = conf_get_num("gssd", "upcall-timeout", upcall_timeout); + cancel_timed_out_upcalls = conf_get_bool("gssd", "cancel-timed-out-upcalls", + cancel_timed_out_upcalls); + s = conf_get_str("gssd", "pipefs-directory"); + if (!s) + s = conf_get_str("general", "pipefs-directory"); + else + printerr(0, "WARNING: Specifying pipefs-directory in the [gssd] " + "section of %s is deprecated. Use the [general] " + "section instead.", NFS_CONFFILE); + if (s) + pipefs_path = s; + s = conf_get_str("gssd", "keytab-file"); + if (s) + keytabfile = s; + s = conf_get_str("gssd", "cred-cache-directory"); + if (s) + ccachedir = strdup(s); + s = conf_get_str("gssd", "preferred-realm"); + if (s) + preferred_realm = s; + + use_gssproxy = conf_get_bool("gssd", "use-gss-proxy", use_gssproxy); + set_home = conf_get_bool("gssd", "set-home", set_home); +} + +int +main(int argc, char *argv[]) +{ + int fg = 0; + int verbosity = 0; + int rpc_verbosity = 0; + int opt; + int i; + int rc; + extern char *optarg; + char *progname; + struct event *sighup_ev; + + read_gss_conf(); + + verbosity = conf_get_num("gssd", "verbosity", verbosity); + rpc_verbosity = conf_get_num("gssd", "rpc-verbosity", rpc_verbosity); + + while ((opt = getopt(argc, argv, "HDfvrlmnMp:k:d:t:T:R:U:C")) != -1) { + switch (opt) { + case 'f': + fg = 1; + break; + case 'm': + /* Accept but ignore this. Now the default. */ + break; + case 'M': + use_memcache = 1; + break; + case 'n': + root_uses_machine_creds = 0; + break; + case 'v': + verbosity++; + break; + case 'r': + rpc_verbosity++; + break; + case 'p': + pipefs_path = optarg; + break; + case 'k': + keytabfile = optarg; + break; + case 'd': + free(ccachedir); + ccachedir = strdup(optarg); + break; + case 't': + context_timeout = atoi(optarg); + break; + case 'T': + rpc_timeout = atoi(optarg); + break; + case 'R': + preferred_realm = strdup(optarg); + break; + case 'l': +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + limit_to_legacy_enctypes = 1; +#else + errx(1, "Encryption type limits not supported by Kerberos libraries."); +#endif + break; + case 'D': + avoid_dns = false; + break; + case 'H': + set_home = false; + break; + case 'U': + upcall_timeout = atoi(optarg); + break; + case 'C': + cancel_timed_out_upcalls = true; + break; + default: + usage(argv[0]); + break; + } + } + + /* + * Some krb5 routines try to scrape info out of files in the user's + * home directory. This can easily deadlock when that homedir is on a + * kerberized NFS mount. By setting $HOME to "/" by default, we prevent + * this behavior in routines that use $HOME in preference to the results + * of getpw*. + * + * Some users do not use Kerberized home dirs and need $HOME to remain + * unchanged. Those users can leave $HOME unchanged by setting set_home + * to false. + */ + if (set_home) { + if (setenv("HOME", "/", 1)) { + printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno)); + exit(1); + } + } + + if (use_gssproxy) { + if (setenv("GSS_USE_PROXY", "yes", 1) < 0) { + printerr(0, "gssd: Unable to set $GSS_USE_PROXY: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + } + + if (ccachedir) { + char *ptr; + + for (ptr = ccachedir, i = 2; *ptr; ptr++) + if (*ptr == ':') + i++; + + ccachesearch = malloc(i * sizeof(char *)); + if (!ccachesearch) { + printerr(0, "malloc failure\n"); + exit(EXIT_FAILURE); + } + + i = 0; + ccachesearch[i++] = strtok(ccachedir, ":"); + while(ccachesearch[i - 1]) + ccachesearch[i++] = strtok(NULL, ":"); + + } else { + ccachesearch = malloc(3 * sizeof(char *)); + if (!ccachesearch) { + printerr(0, "malloc failure\n"); + exit(EXIT_FAILURE); + } + + ccachesearch[0] = GSSD_DEFAULT_CRED_DIR; + ccachesearch[1] = GSSD_USER_CRED_DIR; + ccachesearch[2] = NULL; + } + + if (preferred_realm == NULL) + gssd_k5_get_default_realm(&preferred_realm); + + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + + if (upcall_timeout > MAX_UPCALL_TIMEOUT) + upcall_timeout = MAX_UPCALL_TIMEOUT; + else if (upcall_timeout < MIN_UPCALL_TIMEOUT) + upcall_timeout = MIN_UPCALL_TIMEOUT; + + initerr(progname, verbosity, fg); +#ifdef HAVE_LIBTIRPC_SET_DEBUG + /* + * Only set the libtirpc debug level if explicitly requested via -r. + */ + if (rpc_verbosity > 0) + libtirpc_set_debug(progname, rpc_verbosity, fg); +#else + if (rpc_verbosity > 0) + printerr(0, "Warning: libtirpc does not " + "support setting debug levels\n"); +#endif + + daemon_init(fg); + + if (gssd_check_mechs() != 0) + errx(1, "Problem with gssapi library"); + + evbase = event_base_new(); + if (!evbase) { + printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + pipefs_dir = opendir(pipefs_path); + if (!pipefs_dir) { + printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno)); + exit(EXIT_FAILURE); + } + + pipefs_fd = dirfd(pipefs_dir); + if (fchdir(pipefs_fd)) { + printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno)); + exit(EXIT_FAILURE); + } + + inotify_fd = inotify_init1(IN_NONBLOCK); + if (inotify_fd == -1) { + printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + sighup_ev = evsignal_new(evbase, SIGHUP, gssd_scan_cb, NULL); + if (!sighup_ev) { + printerr(0, "ERROR: failed to create SIGHUP event: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + evsignal_add(sighup_ev, NULL); + inotify_ev = event_new(evbase, inotify_fd, EV_READ | EV_PERSIST, + gssd_inotify_cb, NULL); + if (!inotify_ev) { + printerr(0, "ERROR: failed to create inotify event: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + event_add(inotify_ev, NULL); + + TAILQ_INIT(&active_thread_list); + + rc = start_watchdog_thread(); + if (rc != 0) { + printerr(0, "ERROR: failed to start watchdog thread: %d\n", rc); + exit(EXIT_FAILURE); + } + + TAILQ_INIT(&topdir_list); + gssd_scan(); + daemon_ready(); + + rc = event_base_dispatch(evbase); + + printerr(0, "event_dispatch() returned %i!\n", rc); + + gssd_destroy_krb5_principals(root_uses_machine_creds); + + while (!TAILQ_EMPTY(&topdir_list)) { + struct topdir *tdi = TAILQ_FIRST(&topdir_list); + TAILQ_REMOVE(&topdir_list, tdi, list); + while (!TAILQ_EMPTY(&tdi->clnt_list)) { + struct clnt_info *clp = TAILQ_FIRST(&tdi->clnt_list); + TAILQ_REMOVE(&tdi->clnt_list, clp, list); + gssd_destroy_client(clp); + } + free(tdi); + } + + event_free(inotify_ev); + event_free(sighup_ev); + event_base_free(evbase); + + close(inotify_fd); + close(pipefs_fd); + closedir(pipefs_dir); + + free(preferred_realm); + free(ccachesearch); + free(ccachedir); + + return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h new file mode 100644 index 0000000..4e070ed --- /dev/null +++ b/utils/gssd/gssd.h @@ -0,0 +1,124 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _RPC_GSSD_H_ +#define _RPC_GSSD_H_ + +#include +#include +#include +#include +#include +#include + +#ifndef GSSD_PIPEFS_DIR +#define GSSD_PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs" +#endif +#define DNOTIFY_SIGNAL (SIGRTMIN + 3) + +#define GSSD_DEFAULT_CRED_DIR "/tmp" +#define GSSD_USER_CRED_DIR "/run/user/%U" +#define GSSD_DEFAULT_CRED_PREFIX "krb5cc" +#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" +#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" +#define GSSD_SERVICE_NAME "nfs" +#define RPC_CHAN_BUF_SIZE 32768 + +/* timeouts are in seconds */ +#define MIN_UPCALL_TIMEOUT 5 +#define DEF_UPCALL_TIMEOUT 30 +#define MAX_UPCALL_TIMEOUT 600 + +/* + * The gss mechanisms that we can handle + */ +enum {AUTHTYPE_KRB5, AUTHTYPE_LIPKEY}; + +extern char *keytabfile; +extern char **ccachesearch; +extern int use_memcache; +extern int root_uses_machine_creds; +extern unsigned int context_timeout; +extern unsigned int rpc_timeout; +extern char *preferred_realm; + +struct clnt_info { + TAILQ_ENTRY(clnt_info) list; + int refcount; + int wd; + bool scanned; + char *name; + char *relpath; + char *servicename; + char *servername; + int prog; + int vers; + char *protocol; + int krb5_fd; + struct event *krb5_ev; + int gssd_fd; + struct event *gssd_ev; + struct sockaddr_storage addr; + char *upcall_address; + char *upcall_port; + int upcall_program; + int upcall_vers; + char *upcall_protoname; + char *upcall_service; +}; + +struct clnt_upcall_info { + struct clnt_info *clp; + uid_t uid; + int fd; + char *srchost; + char *target; + char *service; +}; + +struct upcall_thread_info { + TAILQ_ENTRY(upcall_thread_info) list; + pthread_t tid; + struct timespec timeout; + uid_t uid; + int fd; + unsigned short flags; +#define UPCALL_THREAD_CANCELED 0x0001 +#define UPCALL_THREAD_WARNED 0x0002 +}; + +void handle_krb5_upcall(struct clnt_info *clp); +void handle_gssd_upcall(struct clnt_info *clp); +void free_upcall_info(struct clnt_upcall_info *info); +void gssd_free_client(struct clnt_info *clp); +int do_error_downcall(int k5_fd, uid_t uid, int err); + + +#endif /* _RPC_GSSD_H_ */ diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man new file mode 100644 index 0000000..2a5384d --- /dev/null +++ b/utils/gssd/gssd.man @@ -0,0 +1,408 @@ +.\" +.\" rpc.gssd(8) +.\" +.\" Copyright (C) 2003 J. Bruce Fields +.\" +.TH rpc.gssd 8 "20 Feb 2013" +.SH NAME +rpc.gssd \- RPCSEC_GSS daemon +.SH SYNOPSIS +.B rpc.gssd +.RB [ \-DfMnlvrHC ] +.RB [ \-k +.IR keytab ] +.RB [ \-p +.IR pipefsdir ] +.RB [ \-d +.IR ccachedir ] +.RB [ \-t +.IR timeout ] +.RB [ \-T +.IR timeout ] +.RB [ \-U +.IR timeout ] +.RB [ \-R +.IR realm ] +.SH INTRODUCTION +The RPCSEC_GSS protocol, defined in RFC 5403, is used to provide +strong security for RPC-based protocols such as NFS. +.P +Before exchanging RPC requests using RPCSEC_GSS, an RPC client must +establish a GSS +.IR "security context" . +A security context is shared state on each +end of a network transport that enables GSS-API security services. +.P +Security contexts are established using +.IR "security credentials" . +A credential grants temporary access to a secure network service, +much as a railway ticket grants temporary access to use a rail service. +.P +A user typically obtains a credential by providing a password to the +.BR kinit (1) +command, or via a PAM library at login time. +A credential acquired with a +.I user principal +is known as a +.I user credential +(see +.BR kerberos (1) +for more on principals). +.P +Certain operations require a credential that +represents no particular user +or +represents the host itself. +This kind of credential is called a +.IR "machine credential" . +.P +A host establishes its machine credential using a +.I "service principal" +whose encrypted password is stored in a local file known as a +.IR keytab . +A machine credential remains effective +without user intervention +as long as the host can renew it. +.P +Once obtained, credentials are typically stored in local temporary files +with well-known pathnames. +.SH DESCRIPTION +To establish GSS security contexts using these credential files, +the Linux kernel RPC client depends on a userspace daemon called +.BR rpc.gssd . +The +.B rpc.gssd +daemon uses the rpc_pipefs filesystem to communicate with the kernel. +.SS User Credentials +When a user authenticates using a command such as +.BR kinit (1), +the resulting credential is stored in a file with a well-known name +constructed using the user's UID. +.P +To interact with an NFS server +on behalf of a particular Kerberos-authenticated user, +the Linux kernel RPC client requests that +.B rpc.gssd +initialize a security context with the credential +in that user's credential file. +.P +Typically, credential files are placed in +.IR /tmp . +However, +.B rpc.gssd +can search for credential files in more than one directory. +See the description of the +.B -d +option for details. +.SS Machine Credentials +.B rpc.gssd +searches the default keytab, +.IR /etc/krb5.keytab , +in the following order for a principal and password to use +when establishing the machine credential. +For the search, rpc.gssd replaces and with the local +system's hostname and Kerberos realm. +.sp + $@ +.br + root/@ +.br + nfs/@ +.br + host/@ +.br + root/@ +.br + nfs/@ +.br + host/@ +.sp +rpc.gssd selects one of the entries if it does not find +a service principal matching the local hostname, +e.g. if DHCP assigns the local hostname dynamically. +The facility enables the use of the same keytab on multiple systems. +However, using the same service principal to establish a machine credential +on multiple hosts can create unwanted security exposures +and is therefore not recommended. +.P +Note that $@ is a user principal +that enables Kerberized NFS when the local system is joined +to an Active Directory domain using Samba. +The keytab provides the password for this principal. +.P +You can specify a different keytab by using the +.B -k +option if +.I /etc/krb5.keytab +does not exist or does not provide one of these principals. +.SS Credentials for UID 0 +UID 0 is a special case. +By default +.B rpc.gssd +uses the system's machine credentials for UID 0 accesses +that require GSS authentication. +This limits the privileges of the root user +when accessing network resources that require authentication. +.P +Specify the +.B -n +option when starting +.B rpc.gssd +if you'd like to force the root user to obtain a user credential +rather than use the local system's machine credential. +.P +When +.B -n +is specified, +the kernel continues to request a GSS context established +with a machine credential for NFSv4 operations, +such as SETCLIENTID or RENEW, that manage state. +If +.B rpc.gssd +cannot obtain a machine credential (say, the local system has +no keytab), NFSv4 operations that require machine credentials will fail. +.SS Encryption types +A realm administrator can choose to add keys encoded in a number of different +encryption types to the local system's keytab. +For instance, a host/ principal might have keys for the +.BR aes256-cts-hmac-sha1-96 , +.BR aes128-cts-hmac-sha1-96 , +.BR des3-cbc-sha1 ", and" +.BR arcfour-hmac " encryption types." +This permits +.B rpc.gssd +to choose an appropriate encryption type that the target NFS server +supports. +.P +These encryption types are stronger than legacy single-DES encryption types. +To interoperate in environments where servers support +only weak encryption types, +you can restrict your client to use only single-DES encryption types +by specifying the +.B -l +option when starting +.BR rpc.gssd . +.SH OPTIONS +.TP +.B \-D +The server name passed to GSSAPI for authentication is normally the +name exactly as requested. e.g. for NFS +it is the server name in the "servername:/path" mount request. Only if this +servername appears to be an IP address (IPv4 or IPv6) or an +unqualified name (no dots) will a reverse DNS lookup +will be performed to get the canoncial server name. + +If +.B \-D +is present, a reverse DNS lookup will +.I always +be used, even if the server name looks like a canonical name. So it +is needed if partially qualified, or non canonical names are regularly +used. + +Using +.B \-D +can introduce a security vulnerability, so it is recommended that +.B \-D +not be used, and that canonical names always be used when requesting +services. +.TP +.B -f +Runs +.B rpc.gssd +in the foreground and sends output to stderr (as opposed to syslogd) +.TP +.B -n +When specified, UID 0 is forced to obtain user credentials +which are used instead of the local system's machine credentials. +.TP +.BI "-k " keytab +Tells +.B rpc.gssd +to use the keys found in +.I keytab +to obtain machine credentials. +The default value is +.IR /etc/krb5.keytab . +.TP +.B -l +When specified, restricts +.B rpc.gssd +to sessions to weak encryption types such as +.BR des-cbc-crc . +This option is available only when the local system's Kerberos library +supports settable encryption types. +.TP +.BI "-p " path +Tells +.B rpc.gssd +where to look for the rpc_pipefs filesystem. The default value is +.IR /var/lib/nfs/rpc_pipefs . +.TP +.BI "-d " search-path +This option specifies a colon separated list of directories that +.B rpc.gssd +searches for credential files. The default value is +.IR /tmp:/run/user/%U . +The literal sequence "%U" can be specified to substitue the UID +of the user for whom credentials are being searched. +.TP +.B -M +By default, machine credentials are stored in files in the first +directory in the credential directory search path (see the +.B -d +option). When +.B -M +is set, +.B rpc.gssd +stores machine credentials in memory instead. +.TP +.B -v +Increases the verbosity of the output (can be specified multiple times). +.TP +.B -r +If the RPCSEC_GSS library supports setting debug level, +increases the verbosity of the output (can be specified multiple times). +.TP +.BI "-R " realm +Kerberos tickets from this +.I realm +will be preferred when scanning available credentials cache files to be +used to create a context. By default, the default realm, as configured +in the Kerberos configuration file, is preferred. +.TP +.BI "-t " timeout +Timeout, in seconds, for kernel GSS contexts. This option allows you to force +new kernel contexts to be negotiated after +.I timeout +seconds, which allows changing Kerberos tickets and identities frequently. +The default is no explicit timeout, which means the kernel context will live +the lifetime of the Kerberos service ticket used in its creation. +.TP +.BI "-T " timeout +Timeout, in seconds, to create an RPC connection with a server while +establishing an authenticated gss context for a user. +The default timeout is set to 5 seconds. +If you get messages like "WARNING: can't create tcp rpc_clnt to server +%servername% for user with uid %uid%: RPC: Remote system error - +Connection timed out", you should consider an increase of this timeout. +.TP +.BI "-U " timeout +Timeout, in seconds, for upcall threads. Threads executing longer than +.I timeout +seconds will cause an error message to be logged. The default +.I timeout +is 30 seconds. The minimum is 5 seconds. The maximum is 600 seconds. +.TP +.B -C +In addition to logging an error message for threads that have timed out, +the thread will be canceled and an error of -ETIMEDOUT will be reported +to the kernel. +.TP +.B -H +Avoids setting $HOME to "/". This allows rpc.gssd to read per user k5identity +files versus trying to read /.k5identity for each user. + +If +.B \-H +is not set, rpc.gssd will use the first match found in +/var/kerberos/krb5/user/$EUID/client.keytab and will not use a principal based on +host and/or service parameters listed in $HOME/.k5identity. +.SH CONFIGURATION FILE +Many of the options that can be set on the command line can also be +controlled through values set in the +.B [gssd] +section of the +.I /etc/nfs.conf +configuration file. Values recognized include: +.TP +.B verbosity +Value which is equivalent to the number of +.BR -v . +.TP +.B rpc-verbosity +Value which is equivalent to the number of +.BR -r . +.TP +.B use-memcache +A Boolean flag equivalent to +.BR -M . +.TP +.B use-machine-creds +A Boolean flag. Setting to +.B false +is equivalent to giving the +.B -n +flag. +.TP +.B avoid-dns +Setting to +.B false +is equivalent to providing the +.B -D +flag. +.TP +.B limit-to-legacy-enctypes +Equivalent to +.BR -l . +.TP +.B context-timeout +Equivalent to +.BR -t . +.TP +.B rpc-timeout +Equivalent to +.BR -T . +.TP +.B keytab-file +Equivalent to +.BR -k . +.TP +.BR cred-cache-directory +Equivalent to +.BR -d . +.TP +.B preferred-realm +Equivalent to +.BR -R . +.TP +.B upcall-timeout +Equivalent to +.BR -U . +.TP +.B cancel-timed-out-upcalls +Setting to +.B true +is equivalent to providing the +.B -C +flag. +.TP +.B set-home +Setting to +.B false +is equivalent to providing the +.B -H +flag. +.P +In addtion, the following value is recognized from the +.B [general] +section: +.TP +.B pipefs-directory +Equivalent to +.BR -p . + +.SH SEE ALSO +.BR rpc.svcgssd (8), +.BR kerberos (1), +.BR kinit (1), +.BR krb5.conf (5) +.SH AUTHORS +.br +Dug Song +.br +Andy Adamson +.br +Marius Aamodt Eriksen +.br +J. Bruce Fields diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c new file mode 100644 index 0000000..a96647d --- /dev/null +++ b/utils/gssd/gssd_proc.c @@ -0,0 +1,1075 @@ +/* + gssd_proc.c + + Copyright (c) 2000-2004 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2001 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + Copyright (c) 2002 Bruce Fields + Copyright (c) 2004 Kevin Coffman + Copyright (c) 2014 David H?rdeman + All rights reserved, all wrongs reversed. + + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "krb5_util.h" +#include "context.h" +#include "nfsrpc.h" +#include "nfslib.h" +#include "gss_names.h" + +extern pthread_mutex_t clp_lock; +extern pthread_mutex_t active_thread_list_lock; +extern int upcall_timeout; +extern TAILQ_HEAD(active_thread_list_head, upcall_thread_info) active_thread_list; + +/* Encryption types supported by the kernel rpcsec_gss code */ +int num_krb5_enctypes = 0; +krb5_enctype *krb5_enctypes = NULL; + +/* Args for the cleanup_handler() */ +struct cleanup_args { + OM_uint32 *min_stat; + gss_buffer_t acceptor; + gss_buffer_t token; + struct authgss_private_data *pd; + AUTH **auth; + CLIENT **rpc_clnt; +}; + +/* + * Parse the supported encryption type information + */ +static int +parse_enctypes(char *enctypes) +{ + int n = 0; + char *curr, *comma; + int i; + static char *cached_types; + + if (cached_types && strcmp(cached_types, enctypes) == 0) + return 0; + free(cached_types); + + if (krb5_enctypes != NULL) { + free(krb5_enctypes); + krb5_enctypes = NULL; + num_krb5_enctypes = 0; + } + + /* count the number of commas */ + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { + comma = strchr(curr, ','); + if (comma != NULL) + n++; + else + break; + } + /* If no more commas and we're not at the end, there's one more value */ + if (*curr != '\0') + n++; + + /* Empty string, return an error */ + if (n == 0) + return ENOENT; + + /* Allocate space for enctypes array */ + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { + return ENOMEM; + } + + /* Now parse each value into the array */ + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { + krb5_enctypes[i++] = atoi(curr); + comma = strchr(curr, ','); + if (comma == NULL) + break; + } + + num_krb5_enctypes = n; + if ((cached_types = malloc(strlen(enctypes)+1))) + strcpy(cached_types, enctypes); + + return 0; +} + +static void +do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, + gss_buffer_desc *context_token, OM_uint32 lifetime_rec, + gss_buffer_desc *acceptor) +{ + char *buf = NULL, *p = NULL, *end = NULL; + unsigned int timeout = context_timeout; + unsigned int buf_size = 0; + pthread_t tid = pthread_self(); + + if (get_verbosity() > 1) + printerr(2, "do_downcall(0x%lx): lifetime_rec=%s acceptor=%.*s\n", + tid, sec2time(lifetime_rec), acceptor->length, acceptor->value); + buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + + sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + + sizeof(context_token->length) + context_token->length + + sizeof(acceptor->length) + acceptor->length; + p = buf = malloc(buf_size); + if (!buf) + goto out_err; + + end = buf + buf_size; + + /* context_timeout set by -t option overrides context lifetime */ + if (timeout == 0) + timeout = lifetime_rec; + if (WRITE_BYTES(&p, end, uid)) goto out_err; + if (WRITE_BYTES(&p, end, timeout)) goto out_err; + if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err; + if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err; + if (write_buffer(&p, end, context_token)) goto out_err; + if (write_buffer(&p, end, acceptor)) goto out_err; + + if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; + free(buf); + return; +out_err: + free(buf); + printerr(1, "do_downcall(0x%lx): Failed to write downcall!\n", tid); + return; +} + +int +do_error_downcall(int k5_fd, uid_t uid, int err) +{ + char buf[1024]; + char *p = buf, *end = buf + 1024; + unsigned int timeout = 0; + int zero = 0; + pthread_t tid = pthread_self(); + + printerr(2, "do_error_downcall(0x%lx): uid %d err %d\n", tid, uid, err); + + if (WRITE_BYTES(&p, end, uid)) goto out_err; + if (WRITE_BYTES(&p, end, timeout)) goto out_err; + /* use seq_win = 0 to indicate an error: */ + if (WRITE_BYTES(&p, end, zero)) goto out_err; + if (WRITE_BYTES(&p, end, err)) goto out_err; + + if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; + return 0; +out_err: + printerr(1, "Failed to write error downcall!\n"); + return -1; +} + +/* + * If the port isn't already set, do an rpcbind query to the remote server + * using the program and version and get the port. + * + * Newer kernels send the value of the port= mount option in the "info" + * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value + * of the port= option or '2049'. The port field in a new sockaddr should + * reflect the value that was sent by the kernel. + */ +static int +populate_port(struct sockaddr *sa, const socklen_t salen, + const rpcprog_t program, const rpcvers_t version, + const unsigned short protocol) +{ + struct sockaddr_in *s4 = (struct sockaddr_in *) sa; +#ifdef IPV6_SUPPORTED + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; +#endif /* IPV6_SUPPORTED */ + unsigned short port; + + /* + * Newer kernels send the port in the upcall. If we already have + * the port, there's no need to look it up. + */ + switch (sa->sa_family) { + case AF_INET: + if (s4->sin_port != 0) { + printerr(4, "DEBUG: port already set to %d\n", + ntohs(s4->sin_port)); + return 1; + } + break; +#ifdef IPV6_SUPPORTED + case AF_INET6: + if (s6->sin6_port != 0) { + printerr(4, "DEBUG: port already set to %d\n", + ntohs(s6->sin6_port)); + return 1; + } + break; +#endif /* IPV6_SUPPORTED */ + default: + printerr(0, "ERROR: unsupported address family %d\n", + sa->sa_family); + return 0; + } + + /* + * Newer kernels that send the port in the upcall set the value to + * 2049 for NFSv4 mounts when one isn't specified. The check below is + * only for kernels that don't send the port in the upcall. For those + * we either have to do an rpcbind query or set it to the standard + * port. Doing a query could be problematic (firewalls, etc), so take + * the latter approach. + */ + if (program == 100003 && version == 4) { + port = 2049; + goto set_port; + } + + port = nfs_getport(sa, salen, program, version, protocol); + if (!port) { + printerr(0, "ERROR: unable to obtain port for prog %ld " + "vers %ld\n", program, version); + return 0; + } + +set_port: + printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port, + program, version); + + switch (sa->sa_family) { + case AF_INET: + s4->sin_port = htons(port); + break; +#ifdef IPV6_SUPPORTED + case AF_INET6: + s6->sin6_port = htons(port); + break; +#endif /* IPV6_SUPPORTED */ + } + + return 1; +} + +/* + * Create an RPC connection and establish an authenticated + * gss context with a server. + */ +static int +create_auth_rpc_client(struct clnt_info *clp, + char *tgtname, + CLIENT **clnt_return, + AUTH **auth_return, + uid_t uid, + int authtype, + gss_cred_id_t cred) +{ + CLIENT *rpc_clnt = NULL; + struct rpc_gss_sec sec; + AUTH *auth = NULL; + int retval = -1; + OM_uint32 min_stat; + char rpc_errmsg[1024]; + int protocol; + struct timeval timeout; + struct sockaddr *addr = (struct sockaddr *) &clp->addr; + socklen_t salen; + pthread_t tid = pthread_self(); + + sec.qop = GSS_C_QOP_DEFAULT; + sec.svc = RPCSEC_GSS_SVC_NONE; + sec.cred = cred; + sec.req_flags = 0; + if (authtype == AUTHTYPE_KRB5) { + sec.mech = (gss_OID)&krb5oid; + sec.req_flags = GSS_C_MUTUAL_FLAG; + } + else { + printerr(0, "ERROR: Invalid authentication type (%d) " + "in create_auth_rpc_client\n", authtype); + goto out_fail; + } + + + if (authtype == AUTHTYPE_KRB5) { +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + /* + * Do this before creating rpc connection since we won't need + * rpc connection if it fails! + */ + if (limit_krb5_enctypes(&sec)) { + printerr(1, "WARNING: Failed while limiting krb5 " + "encryption types for user with uid %d\n", + uid); + goto out_fail; + } +#endif + } + + /* create an rpc connection to the nfs server */ + + printerr(3, "create_auth_rpc_client(0x%lx): creating %s client for server %s\n", + tid, clp->protocol, clp->servername); + + protocol = IPPROTO_TCP; + if ((strcmp(clp->protocol, "udp")) == 0) + protocol = IPPROTO_UDP; + + switch (addr->sa_family) { + case AF_INET: + salen = sizeof(struct sockaddr_in); + break; +#ifdef IPV6_SUPPORTED + case AF_INET6: + salen = sizeof(struct sockaddr_in6); + break; +#endif /* IPV6_SUPPORTED */ + default: + printerr(1, "ERROR: Unknown address family %d\n", + addr->sa_family); + goto out_fail; + } + + if (!populate_port(addr, salen, clp->prog, clp->vers, protocol)) + goto out_fail; + + /* set the timeout according to the requested valued */ + timeout.tv_sec = (long) rpc_timeout; + timeout.tv_usec = (long) 0; + + rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog, + clp->vers, &timeout); + if (!rpc_clnt) { + snprintf(rpc_errmsg, sizeof(rpc_errmsg), + "WARNING: can't create %s rpc_clnt to server %s for " + "user with uid %d", + protocol == IPPROTO_TCP ? "tcp" : "udp", + clp->servername, uid); + printerr(0, "%s\n", + clnt_spcreateerror(rpc_errmsg)); + goto out_fail; + } + if (!tgtname) + tgtname = clp->servicename; + + printerr(3, "create_auth_rpc_client(0x%lx): creating context with server %s\n", + tid, tgtname); + auth = authgss_create_default(rpc_clnt, tgtname, &sec); + if (!auth) { + if (sec.minor_status == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + printerr(2, "WARNING: server=%s failed context " + "creation with KRB5_AP_ERR_BAD_INTEGRITY\n", + clp->servername); + if (cred == GSS_C_NO_CREDENTIAL) + retval = gssd_refresh_krb5_machine_credential(clp->servername, + "*", NULL, 1); + else + retval = gssd_k5_remove_bad_service_cred(clp->servername); + if (!retval) { + auth = authgss_create_default(rpc_clnt, tgtname, + &sec); + if (auth) + goto success; + } + } + /* Our caller should print appropriate message */ + printerr(2, "WARNING: Failed to create krb5 context for " + "user with uid %d for server %s\n", + uid, tgtname); + goto out_fail; + } +success: + /* Success !!! */ + rpc_clnt->cl_auth = auth; + *clnt_return = rpc_clnt; + *auth_return = auth; + retval = 0; + + out: + if (sec.cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &sec.cred); + return retval; + + out_fail: + /* Only destroy here if failure. Otherwise, caller is responsible */ + if (rpc_clnt) clnt_destroy(rpc_clnt); + + goto out; +} + +/* + * Create the context as the user (not as root). + * + * Note that we change the *real* uid here, as changing the effective uid is + * not sufficient. This is due to an unfortunate historical error in the MIT + * krb5 libs, where they used %{uid} in the default_ccache_name. Changing that + * now might break some applications so we're sort of stuck with it. + * + * Unfortunately, doing this leaves the forked child vulnerable to signals and + * renicing, but this is the best we can do. In the event that a child is + * signalled before downcalling, the kernel will just eventually time out the + * upcall attempt. + */ +static int +change_identity(uid_t uid) +{ + struct passwd *pw; + int res; + + /* drop list of supplimentary groups first */ +#ifdef __NR_setgroups32 + if (syscall(SYS_setgroups32, 0, 0) != 0) { +#else + if (syscall(SYS_setgroups, 0, 0) != 0) { +#endif + printerr(0, "WARNING: unable to drop supplimentary groups!"); + return errno; + } + + /* try to get pwent for user */ + pw = getpwuid(uid); + if (!pw) { + /* if that doesn't work, try to get one for "nobody" */ + errno = 0; + pw = getpwnam("nobody"); + if (!pw) { + printerr(0, "WARNING: unable to determine gid for uid %u\n", uid); + return errno ? errno : ENOENT; + } + } + + /* Switch the UIDs and GIDs. */ + /* For the threaded version we have to set uid,gid per thread instead + * of per process. glibc setresuid() when called from a thread, it'll + * send a signal to all other threads to synchronize the uid in all + * other threads. To bypass this, we have to call syscall() directly. + */ +#ifdef __NR_setresgid32 + res = syscall(SYS_setresgid32, pw->pw_gid, pw->pw_gid, pw->pw_gid); +#else + res = syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid); +#endif + if (res != 0) { + printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid); + return errno; + } + +#ifdef __NR_setresuid32 + res = syscall(SYS_setresuid32, uid, uid, uid); +#else + res = syscall(SYS_setresuid, uid, uid, uid); +#endif + if (res != 0) { + printerr(0, "WARNING: Failed to setuid for user with uid %u\n", uid); + return errno; + } + + return 0; +} + +static AUTH * +krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, + int *downcall_err, int *chg_err, CLIENT **rpc_clnt) +{ + AUTH *auth = NULL; + gss_cred_id_t gss_cred; + char **dname; + int err, resp = -1; + pthread_t tid = pthread_self(); + + printerr(2, "krb5_not_machine_creds(0x%lx): uid %d tgtname %s\n", + tid, uid, tgtname); + + *chg_err = change_identity(uid); + if (*chg_err) { + printerr(0, "WARNING: failed to change identity: %s", + strerror(*chg_err)); + goto out; + } + + /** Tell krb5 gss which credentials cache to use. + * Try first to acquire credentials directly via GSSAPI + */ + err = gssd_acquire_user_cred(&gss_cred); + if (err == 0) + resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, + &auth, uid, + AUTHTYPE_KRB5, gss_cred); + + /** if create_auth_rplc_client fails try the traditional + * method of trolling for credentials + */ + for (dname = ccachesearch; resp != 0 && *dname != NULL; dname++) { + err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, + *dname); + if (err == -EKEYEXPIRED) + *downcall_err = -EKEYEXPIRED; + else if (err == 0) + resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, + &auth, uid,AUTHTYPE_KRB5, + GSS_C_NO_CREDENTIAL); + } + +out: + return auth; +} + +static AUTH * +krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, + char *srchost, char *tgtname, char *service, + CLIENT **rpc_clnt) +{ + AUTH *auth = NULL; + char **credlist = NULL; + char **ccname; + int nocache = 0; + int success = 0; + pthread_t tid = pthread_self(); + + printerr(2, "krb5_use_machine_creds(0x%lx): uid %d tgtname %s\n", + tid, uid, tgtname); + + do { + gssd_refresh_krb5_machine_credential(clp->servername, + service, srchost, 0); + /* + * Get a list of credential cache names and try each + * of them until one works or we've tried them all + */ + if (gssd_get_krb5_machine_cred_list(&credlist)) { + printerr(0, "ERROR: No credentials found " + "for connection to server %s\n", + clp->servername); + goto out; + } + for (ccname = credlist; ccname && *ccname; ccname++) { + u_int min_stat; + + if (gss_krb5_ccache_name(&min_stat, *ccname, NULL) != + GSS_S_COMPLETE) { + printerr(1, "WARNING: gss_krb5_ccache_name " + "with name '%s' failed (%s)\n", + *ccname, error_message(min_stat)); + continue; + } + if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, + &auth, uid, + AUTHTYPE_KRB5, + GSS_C_NO_CREDENTIAL)) == 0) { + /* Success! */ + success++; + break; + } + printerr(2, "WARNING: Failed to create machine krb5 " + "context with cred cache %s for server %s\n", + *ccname, clp->servername); + } + gssd_free_krb5_machine_cred_list(credlist); + if (!success) { + if(nocache == 0) { + nocache++; + printerr(2, "WARNING: Machine cache prematurely " + "expired or corrupted trying to " + "recreate cache for server %s\n", + clp->servername); + } else { + printerr(1, "ERROR: Failed to create machine " + "krb5 context with any credentials " + "cache for server %s\n", + clp->servername); + goto out; + } + } + } while(!success); + +out: + return auth; +} + +/* + * cleanup_handler: + * + * Free any resources allocated by process_krb5_upcall(). + * + * Runs upon normal termination of process_krb5_upcall as well as if the + * thread is canceled. + */ +static void +cleanup_handler(void *arg) +{ + struct cleanup_args *args = (struct cleanup_args *)arg; + + gss_release_buffer(args->min_stat, args->acceptor); + if (args->token->value) + free(args->token->value); +#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA + if (args->pd->pd_ctx_hndl.length != 0 || args->pd->pd_ctx != 0) + authgss_free_private_data(args->pd); +#endif + if (*args->auth) + AUTH_DESTROY(*args->auth); + if (*args->rpc_clnt) + clnt_destroy(*args->rpc_clnt); +} + +/* + * process_krb5_upcall: + * + * this code uses the userland rpcsec gss library to create a krb5 + * context on behalf of the kernel + * + * This is the meat of the upcall thread. Note that cancelability is disabled + * and enabled at various points to ensure that any resources reserved by the + * lower level libraries are released safely. + */ +static void +process_krb5_upcall(struct clnt_upcall_info *info) +{ + struct clnt_info *clp = info->clp; + uid_t uid = info->uid; + int fd = info->fd; + char *srchost = info->srchost; + char *tgtname = info->target; + char *service = info->service; + CLIENT *rpc_clnt = NULL; + AUTH *auth = NULL; + struct authgss_private_data pd; + gss_buffer_desc token; + int err, downcall_err; + OM_uint32 maj_stat, min_stat, lifetime_rec; + gss_name_t gacceptor = GSS_C_NO_NAME; + gss_OID mech; + gss_buffer_desc acceptor = {0}; + struct cleanup_args cleanup_args = {&min_stat, &acceptor, &token, &pd, &auth, &rpc_clnt}; + + token.length = 0; + token.value = NULL; + memset(&pd, 0, sizeof(struct authgss_private_data)); + + pthread_cleanup_push(cleanup_handler, &cleanup_args); + /* + * If "service" is specified, then the kernel is indicating that + * we must use machine credentials for this request. (Regardless + * of the uid value or the setting of root_uses_machine_creds.) + * If the service value is "*", then any service name can be used. + * Otherwise, it specifies the service name that should be used. + * (For now, the values of service will only be "*" or "nfs".) + * + * Restricting gssd to use "nfs" service name is needed for when + * the NFS server is doing a callback to the NFS client. In this + * case, the NFS server has to authenticate itself as "nfs" -- + * even if there are other service keys such as "host" or "root" + * in the keytab. + * + * Another case when the kernel may specify the service attribute + * is when gssd is being asked to create the context for a + * SETCLIENT_ID operation. In this case, machine credentials + * must be used for the authentication. However, the service name + * used for this case is not important. + * + */ + downcall_err = -EACCES; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && + service == NULL)) { + + auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, + &err, &rpc_clnt); + if (err) + goto out_return_error; + } + if (auth == NULL) { + if (uid == 0 && (root_uses_machine_creds == 1 || + service != NULL)) { + auth = krb5_use_machine_creds(clp, uid, srchost, tgtname, + service, &rpc_clnt); + if (auth == NULL) + goto out_return_error; + } else { + /* krb5_not_machine_creds logs the error */ + goto out_return_error; + } + } + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (!authgss_get_private_data(auth, &pd)) { + printerr(1, "WARNING: Failed to obtain authentication " + "data for user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + /* Grab the context lifetime and acceptor name out of the ctx. */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor, + &lifetime_rec, &mech, NULL, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + printerr(1, "WARNING: Failed to inquire context " + "maj_stat (0x%x)\n", maj_stat); + lifetime_rec = 0; + } else { + get_hostbased_client_buffer(gacceptor, mech, &acceptor); + gss_release_name(&min_stat, &gacceptor); + } + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + /* + * The serialization can mean turning pd.pd_ctx into a lucid context. If + * that happens then the pd.pd_ctx will be unusable, so we must never + * try to use it after this point. + */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { + printerr(1, "WARNING: Failed to serialize krb5 context for " + "user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor); + +out: + pthread_cleanup_pop(1); + + return; + +out_return_error: + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + do_error_downcall(fd, uid, downcall_err); + goto out; +} + +static struct clnt_upcall_info * +alloc_upcall_info(struct clnt_info *clp, uid_t uid, int fd, char *srchost, + char *target, char *service) +{ + struct clnt_upcall_info *info; + + info = malloc(sizeof(struct clnt_upcall_info)); + if (info == NULL) + return NULL; + + memset(info, 0, sizeof(*info)); + pthread_mutex_lock(&clp_lock); + clp->refcount++; + pthread_mutex_unlock(&clp_lock); + info->clp = clp; + info->uid = uid; + info->fd = fd; + if (srchost) { + info->srchost = strdup(srchost); + if (info->srchost == NULL) + goto out_info; + } + if (target) { + info->target = strdup(target); + if (info->target == NULL) + goto out_srchost; + } + if (service) { + info->service = strdup(service); + if (info->service == NULL) + goto out_target; + } + +out: + return info; + +out_target: + if (info->target) + free(info->target); +out_srchost: + if (info->srchost) + free(info->srchost); +out_info: + free(info); + info = NULL; + goto out; +} + +void free_upcall_info(struct clnt_upcall_info *info) +{ + gssd_free_client(info->clp); + if (info->service) + free(info->service); + if (info->target) + free(info->target); + if (info->srchost) + free(info->srchost); + free(info); +} + +static void +cleanup_clnt_upcall_info(void *arg) +{ + struct clnt_upcall_info *info = (struct clnt_upcall_info *)arg; + + free_upcall_info(info); +} + +static void +gssd_work_thread_fn(struct clnt_upcall_info *info) +{ + pthread_cleanup_push(cleanup_clnt_upcall_info, info); + process_krb5_upcall(info); + pthread_cleanup_pop(1); +} + +static struct upcall_thread_info * +alloc_upcall_thread_info(void) +{ + struct upcall_thread_info *info; + + info = malloc(sizeof(struct upcall_thread_info)); + if (info == NULL) + return NULL; + memset(info, 0, sizeof(*info)); + return info; +} + +static int +start_upcall_thread(void (*func)(struct clnt_upcall_info *), struct clnt_upcall_info *info) +{ + pthread_attr_t attr; + pthread_t th; + struct upcall_thread_info *tinfo; + int ret; + pthread_t tid = pthread_self(); + + tinfo = alloc_upcall_thread_info(); + if (!tinfo) + return -ENOMEM; + tinfo->fd = info->fd; + tinfo->uid = info->uid; + + ret = pthread_attr_init(&attr); + if (ret != 0) { + printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n", + ret, strerror(errno)); + free(tinfo); + return ret; + } + + ret = pthread_create(&th, &attr, (void *)func, (void *)info); + if (ret != 0) { + printerr(0, "ERROR: pthread_create failed: ret %d: %s\n", + ret, strerror(errno)); + free(tinfo); + return ret; + } + printerr(2, "start_upcall_thread(0x%lx): created thread id 0x%lx\n", + tid, th); + + tinfo->tid = th; + pthread_mutex_lock(&active_thread_list_lock); + clock_gettime(CLOCK_MONOTONIC, &tinfo->timeout); + tinfo->timeout.tv_sec += upcall_timeout; + TAILQ_INSERT_TAIL(&active_thread_list, tinfo, list); + pthread_mutex_unlock(&active_thread_list_lock); + + return ret; +} + +void +handle_krb5_upcall(struct clnt_info *clp) +{ + uid_t uid; + struct clnt_upcall_info *info; + int err; + + if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { + printerr(0, "WARNING: failed reading uid from krb5 " + "upcall pipe: %s\n", strerror(errno)); + return; + } + printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath); + + info = alloc_upcall_info(clp, uid, clp->krb5_fd, NULL, NULL, NULL); + if (info == NULL) { + printerr(0, "%s: failed to allocate clnt_upcall_info\n", __func__); + do_error_downcall(clp->krb5_fd, uid, -EACCES); + return; + } + err = start_upcall_thread(gssd_work_thread_fn, info); + if (err != 0) { + do_error_downcall(clp->krb5_fd, uid, -EACCES); + free_upcall_info(info); + } +} + +void +handle_gssd_upcall(struct clnt_info *clp) +{ + uid_t uid; + char lbuf[RPC_CHAN_BUF_SIZE]; + int lbuflen = 0; + char *p; + char *mech = NULL; + char *uidstr = NULL; + char *target = NULL; + char *service = NULL; + char *srchost = NULL; + char *enctypes = NULL; + pthread_t tid = pthread_self(); + struct clnt_upcall_info *info; + int err; + + lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf)); + if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed reading request\n"); + return; + } + lbuf[lbuflen-1] = 0; + + printerr(2, "\n%s(0x%lx): '%s' (%s)\n", __func__, tid, + lbuf, clp->relpath); + + for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) { + if (!strncmp(p, "mech=", strlen("mech="))) + mech = p + strlen("mech="); + else if (!strncmp(p, "uid=", strlen("uid="))) + uidstr = p + strlen("uid="); + else if (!strncmp(p, "enctypes=", strlen("enctypes="))) + enctypes = p + strlen("enctypes="); + else if (!strncmp(p, "target=", strlen("target="))) + target = p + strlen("target="); + else if (!strncmp(p, "service=", strlen("service="))) + service = p + strlen("service="); + else if (!strncmp(p, "srchost=", strlen("srchost="))) + srchost = p + strlen("srchost="); + } + + if (!mech || strlen(mech) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find gss mechanism name " + "in upcall string '%s'\n", lbuf); + return; + } + + if (uidstr) { + uid = (uid_t)strtol(uidstr, &p, 10); + if (p == uidstr || *p != '\0') + uidstr = NULL; + } + + if (!uidstr) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to find uid " + "in upcall string '%s'\n", lbuf); + return; + } + + if (enctypes && parse_enctypes(enctypes) != 0) { + printerr(0, "WARNING: handle_gssd_upcall: " + "parsing encryption types failed: errno %d\n", errno); + return; + } + + if (target && strlen(target) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse target name " + "in upcall string '%s'\n", lbuf); + return; + } + + /* + * The presence of attribute "service=" indicates that machine + * credentials should be used for this request. If the value + * is "*", then any machine credentials available can be used. + * If the value is anything else, then machine credentials for + * the specified service name (always "nfs" for now) should be + * used. + */ + if (service && strlen(service) < 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse service type " + "in upcall string '%s'\n", lbuf); + return; + } + + if (strcmp(mech, "krb5") == 0 && clp->servername) { + info = alloc_upcall_info(clp, uid, clp->gssd_fd, srchost, target, service); + if (info == NULL) { + printerr(0, "%s: failed to allocate clnt_upcall_info\n", __func__); + do_error_downcall(clp->gssd_fd, uid, -EACCES); + return; + } + err = start_upcall_thread(gssd_work_thread_fn, info); + if (err != 0) { + do_error_downcall(clp->gssd_fd, uid, -EACCES); + free_upcall_info(info); + } + } else { + if (clp->servername) + printerr(0, "WARNING: handle_gssd_upcall: " + "received unknown gss mech '%s'\n", mech); + do_error_downcall(clp->gssd_fd, uid, -EACCES); + } +} diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c new file mode 100644 index 0000000..6f66ef4 --- /dev/null +++ b/utils/gssd/krb5_util.c @@ -0,0 +1,1649 @@ +/* + * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from + * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view + * + * Copyright (c) 2002-2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson + * J. Bruce Fields + * Marius Aamodt Eriksen + * Kevin Coffman + */ + +/* + * slave/kprop.c + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Copyright 1994 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* + krb5_util.c + + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_PRIVATE_KRB5_FUNCTIONS +#include +#endif +#include +#include + +#include +#include + +#include "nfslib.h" +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "krb5_util.h" + +/* + * List of principals from our keytab that we + * will try to use to obtain credentials + * (known as a principal list entry (ple)) + */ +struct gssd_k5_kt_princ { + struct gssd_k5_kt_princ *next; + // Only protect against deletion, not modification + int refcount; + // Only set during creation in new_ple() + krb5_principal princ; + char *realm; + // Modified during usage by gssd_get_single_krb5_cred() + char *ccname; + krb5_timestamp endtime; +}; + + +/* Global list of principals/cache file names for machine credentials */ +static struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; +/* This mutex protects list modification & ple->ccname */ +static pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; + +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES +int limit_to_legacy_enctypes = 0; +#endif + +/*==========================*/ +/*=== Internal routines ===*/ +/*==========================*/ + +static int select_krb5_ccache(const struct dirent *d); +static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, + const char **cctype, struct dirent **d); +static int gssd_get_single_krb5_cred(krb5_context context, + krb5_keytab kt, struct gssd_k5_kt_princ *ple, int force_renew); +static int query_krb5_ccache(const char* cred_cache, char **ret_princname, + char **ret_realm); + +static void release_ple_locked(krb5_context context, + struct gssd_k5_kt_princ *ple) +{ + if (--ple->refcount) + return; + + printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", + ple->ccname, ple->realm); + krb5_free_principal(context, ple->princ); + free(ple->ccname); + free(ple->realm); + free(ple); +} + +static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple) +{ + pthread_mutex_lock(&ple_lock); + release_ple_locked(context, ple); + pthread_mutex_unlock(&ple_lock); +} + + +/* + * Called from the scandir function to weed out potential krb5 + * credentials cache files + * + * Returns: + * 0 => don't select this one + * 1 => select this one + */ +static int +select_krb5_ccache(const struct dirent *d) +{ + /* + * Note: We used to check d->d_type for DT_REG here, + * but apparenlty reiser4 always has DT_UNKNOWN. + * Check for IS_REG after stat() call instead. + */ + if (strstr(d->d_name, GSSD_DEFAULT_CRED_PREFIX)) + return 1; + else + return 0; +} + +/* + * Look in directory "dirname" for files that look like they + * are Kerberos Credential Cache files for a given UID. + * + * Returns 0 if a valid-looking entry is found. "*cctype" is + * set to the name of the cache type. A pointer to the dirent + * is planted in "*d". Caller must free "*d" with free(3). + * + * Otherwise, a negative errno is returned. + */ +static int +gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, + const char **cctype, struct dirent **d) +{ + struct dirent **namelist; + int n; + int i; + int found = 0; + struct dirent *best_match_dir = NULL; + struct stat best_match_stat, tmp_stat; + /* dirname + cctype + d_name + NULL */ + char buf[PATH_MAX+5+256+1]; + char *princname = NULL; + char *realm = NULL; + int score, best_match_score = 0, err = -EACCES; + + memset(&best_match_stat, 0, sizeof(best_match_stat)); + *cctype = NULL; + *d = NULL; + n = scandir(dirname, &namelist, select_krb5_ccache, 0); + if (n < 0) { + printerr(1, "Error doing scandir on directory '%s': %s\n", + dirname, strerror(errno)); + } + else if (n > 0) { + for (i = 0; i < n; i++) { + snprintf(buf, sizeof(buf), + "%s/%s", dirname, namelist[i]->d_name); + printerr(3, "CC '%s' being considered, " + "with preferred realm '%s'\n", + buf, preferred_realm ? + preferred_realm : ""); + if (lstat(buf, &tmp_stat)) { + printerr(0, "Error doing stat on '%s'\n", buf); + free(namelist[i]); + continue; + } + /* Only pick caches owned by the user (uid) */ + if (tmp_stat.st_uid != uid) { + printerr(3, "CC '%s' owned by %u, not %u\n", + buf, tmp_stat.st_uid, uid); + free(namelist[i]); + continue; + } + if (!S_ISREG(tmp_stat.st_mode) && + !S_ISDIR(tmp_stat.st_mode)) { + printerr(3, "CC '%s' is not a regular " + "file or directory\n", buf); + free(namelist[i]); + continue; + } + if (uid == 0 && !root_uses_machine_creds && + strstr(namelist[i]->d_name, "machine_")) { + printerr(3, "CC '%s' not available to root\n", buf); + free(namelist[i]); + continue; + } + if (S_ISDIR(tmp_stat.st_mode)) { + *cctype = "DIR"; + } else + if (S_ISREG(tmp_stat.st_mode)) { + *cctype = "FILE"; + } else { + continue; + } + snprintf(buf, sizeof(buf), "%s:%s/%s", *cctype, + dirname, namelist[i]->d_name); + if (!query_krb5_ccache(buf, &princname, &realm)) { + printerr(3, "CC '%s' is expired or corrupt\n", + buf); + free(namelist[i]); + err = -EKEYEXPIRED; + continue; + } + + score = 0; + if (preferred_realm && + strcmp(realm, preferred_realm) == 0) + score++; + + printerr(3, "CC '%s'(%s@%s) passed all checks and" + " has mtime of %u\n", + buf, princname, realm, + tmp_stat.st_mtime); + /* + * if more than one match is found, return the most + * recent (the one with the latest mtime), and + * don't free the dirent + */ + if (!found) { + best_match_dir = namelist[i]; + best_match_stat = tmp_stat; + best_match_score = score; + found++; + } + else { + /* + * If current score is higher than best match + * score, we use the current match. Otherwise, + * if the current match has an mtime later + * than the one we are looking at, then use + * the current match. Otherwise, we still + * have the best match. + */ + if (best_match_score < score || + (best_match_score == score && + tmp_stat.st_mtime > + best_match_stat.st_mtime)) { + free(best_match_dir); + best_match_dir = namelist[i]; + best_match_stat = tmp_stat; + best_match_score = score; + } + else { + free(namelist[i]); + } + printerr(3, "CC '%s:%s/%s' is our " + "current best match " + "with mtime of %u\n", + cctype, dirname, + best_match_dir->d_name, + best_match_stat.st_mtime); + } + free(princname); + free(realm); + } + free(namelist); + } + if (found) { + *d = best_match_dir; + return 0; + } + + return err; +} + +/* check if the ticket cache exists, if not set nocache=1 so that new + * tgt is gotten + */ +static int +gssd_check_if_cc_exists(struct gssd_k5_kt_princ *ple) +{ + int fd; + char cc_name[BUFSIZ]; + + snprintf(cc_name, sizeof(cc_name), "%s/%s%s_%s", + ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, + GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); + fd = open(cc_name, O_RDONLY); + if (fd < 0) + return 1; + close(fd); + return 0; +} + +/* + * Obtain credentials via a key in the keytab given + * a keytab handle and a gssd_k5_kt_princ structure. + * Checks to see if current credentials are expired, + * if not, uses the keytab to obtain new credentials. + * + * Returns: + * 0 => success (or credentials have not expired) + * nonzero => error + */ +static int +gssd_get_single_krb5_cred(krb5_context context, + krb5_keytab kt, + struct gssd_k5_kt_princ *ple, + int force_renew) +{ +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + krb5_get_init_creds_opt *init_opts = NULL; +#else + krb5_get_init_creds_opt options; +#endif + krb5_get_init_creds_opt *opts; + krb5_creds my_creds; + krb5_ccache ccache = NULL; + char kt_name[BUFSIZ]; + char cc_name[BUFSIZ]; + int code; + time_t now = time(0); + char *cache_type; + char *pname = NULL; + char *k5err = NULL; + int nocache = 0; + pthread_t tid = pthread_self(); + + memset(&my_creds, 0, sizeof(my_creds)); + + if (!use_memcache) + nocache = gssd_check_if_cc_exists(ple); + /* + * Workaround for clock skew among NFS server, NFS client and KDC + * 300 because clock skew must be within 300sec for kerberos + */ + now += 300; + pthread_mutex_lock(&ple_lock); + if (ple->ccname && ple->endtime > now && !nocache && !force_renew) { + printerr(3, "%s(0x%lx): Credentials in CC '%s' are good until %s", + __func__, tid, ple->ccname, ctime((time_t *)&ple->endtime)); + code = 0; + pthread_mutex_unlock(&ple_lock); + goto out; + } + pthread_mutex_unlock(&ple_lock); + + if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { + printerr(0, "ERROR: Unable to get keytab name in " + "gssd_get_single_krb5_cred\n"); + goto out; + } + + if ((krb5_unparse_name(context, ple->princ, &pname))) + pname = NULL; + +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + code = krb5_get_init_creds_opt_alloc(context, &init_opts); + if (code) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s allocating gic options\n", k5err); + goto out; + } + if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1)) + printerr(1, "WARNING: Unable to set option for addressless " + "tickets. May have problems behind a NAT.\n"); +#ifdef TEST_SHORT_LIFETIME + /* set a short lifetime (for debugging only!) */ + printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n"); + krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); +#endif + opts = init_opts; + +#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */ + + krb5_get_init_creds_opt_init(&options); + krb5_get_init_creds_opt_set_address_list(&options, NULL); +#ifdef TEST_SHORT_LIFETIME + /* set a short lifetime (for debugging only!) */ + printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); + krb5_get_init_creds_opt_set_tkt_life(&options, 5*60); +#endif + opts = &options; +#endif + + if ((code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, + kt, 0, NULL, opts))) { + k5err = gssd_k5_err_msg(context, code); + printerr(1, "WARNING: %s while getting initial ticket for " + "principal '%s' using keytab '%s'\n", k5err, + pname ? pname : "", kt_name); + goto out; + } + + /* + * Initialize cache file which we're going to be using + */ + + pthread_mutex_lock(&ple_lock); + if (use_memcache) + cache_type = "MEMORY"; + else + cache_type = "FILE"; + snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", + cache_type, + ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, + GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); + ple->endtime = my_creds.times.endtime; + if (ple->ccname == NULL || strcmp(ple->ccname, cc_name) != 0) { + free(ple->ccname); + ple->ccname = strdup(cc_name); + if (ple->ccname == NULL) { + printerr(0, "ERROR: no storage to duplicate credentials " + "cache name '%s'\n", cc_name); + code = ENOMEM; + pthread_mutex_unlock(&ple_lock); + goto out; + } + } + pthread_mutex_unlock(&ple_lock); + if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while opening credential cache '%s'\n", + k5err, cc_name); + goto out; + } + if ((code = krb5_cc_initialize(context, ccache, ple->princ))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while initializing credential " + "cache '%s'\n", k5err, cc_name); + goto out; + } + if ((code = krb5_cc_store_cred(context, ccache, &my_creds))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while storing credentials in '%s'\n", + k5err, cc_name); + goto out; + } + + code = 0; + printerr(2, "%s(0x%lx): principal '%s' ccache:'%s'\n", + __func__, tid, pname, cc_name); + out: +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + if (init_opts) + krb5_get_init_creds_opt_free(context, init_opts); +#endif + if (pname) + k5_free_unparsed_name(context, pname); + if (ccache) + krb5_cc_close(context, ccache); + krb5_free_cred_contents(context, &my_creds); + free(k5err); + return (code); +} + +/* + * Given a principal, find a matching ple structure + * Called with mutex held + */ +static struct gssd_k5_kt_princ * +find_ple_by_princ(krb5_context context, krb5_principal princ) +{ + struct gssd_k5_kt_princ *ple; + + for (ple = gssd_k5_kt_princ_list; ple != NULL; ple = ple->next) { + if (krb5_principal_compare(context, ple->princ, princ)) + return ple; + } + /* no match found */ + return NULL; +} + +/* + * Create, initialize, and add a new ple structure to the global list + * Called with mutex held + */ +static struct gssd_k5_kt_princ * +new_ple(krb5_context context, krb5_principal princ) +{ + struct gssd_k5_kt_princ *ple = NULL, *p; + krb5_error_code code; + char *default_realm; + int is_default_realm = 0; + + ple = malloc(sizeof(struct gssd_k5_kt_princ)); + if (ple == NULL) + goto outerr; + memset(ple, 0, sizeof(*ple)); + +#ifdef HAVE_KRB5 + ple->realm = strndup(princ->realm.data, + princ->realm.length); +#else + ple->realm = strdup(princ->realm); +#endif + if (ple->realm == NULL) + goto outerr; + code = krb5_copy_principal(context, princ, &ple->princ); + if (code) + goto outerr; + + /* + * Add new entry onto the list (if this is the default + * realm, always add to the front of the list) + */ + + code = krb5_get_default_realm(context, &default_realm); + if (code == 0) { + if (strcmp(ple->realm, default_realm) == 0) + is_default_realm = 1; + k5_free_default_realm(context, default_realm); + } + + if (is_default_realm) { + ple->next = gssd_k5_kt_princ_list; + gssd_k5_kt_princ_list = ple; + } else { + p = gssd_k5_kt_princ_list; + while (p != NULL && p->next != NULL) + p = p->next; + if (p == NULL) + gssd_k5_kt_princ_list = ple; + else + p->next = ple; + } + + ple->refcount = 1; + return ple; +outerr: + if (ple) { + if (ple->realm) + free(ple->realm); + free(ple); + } + return NULL; +} + +/* + * Given a principal, find an existing ple structure, or create one + */ +static struct gssd_k5_kt_princ * +get_ple_by_princ(krb5_context context, krb5_principal princ) +{ + struct gssd_k5_kt_princ *ple; + + pthread_mutex_lock(&ple_lock); + ple = find_ple_by_princ(context, princ); + if (ple == NULL) { + ple = new_ple(context, princ); + } + if (ple != NULL) { + ple->refcount++; + } + pthread_mutex_unlock(&ple_lock); + + return ple; +} + +/* + * Given a (possibly unqualified) hostname, + * return the fully qualified (lower-case!) hostname + */ +static int +get_full_hostname(const char *inhost, char *outhost, int outhostlen) +{ + struct addrinfo *addrs = NULL; + struct addrinfo hints; + int retval; + char *c; + pthread_t tid = pthread_self(); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + /* Get full target hostname */ + retval = getaddrinfo(inhost, NULL, &hints, &addrs); + if (retval) { + printerr(1, "%s(0x%lx): getaddrinfo(%s) failed: %s\n", + __func__, tid, inhost, gai_strerror(retval)); + goto out; + } + strncpy(outhost, addrs->ai_canonname, outhostlen); + nfs_freeaddrinfo(addrs); + for (c = outhost; *c != '\0'; c++) + *c = tolower(*c); + + if (get_verbosity() && strcmp(inhost, outhost)) + printerr(1, "%s(0x%0lx): inhost '%s' different than outhost '%s'\n", + __func__, tid, inhost, outhost); + + retval = 0; +out: + return retval; +} + +/* + * If principal matches the given realm and service name, + * and has *any* instance (hostname), return 1. + * Otherwise return 0, indicating no match. + */ +#ifdef HAVE_KRB5 +static int +realm_and_service_match(krb5_principal p, const char *realm, const char *service) +{ + /* Must have two components */ + if (p->length != 2) + return 0; + + if ((strlen(realm) == p->realm.length) + && (strncmp(realm, p->realm.data, p->realm.length) == 0) + && (strlen(service) == p->data[0].length) + && (strncmp(service, p->data[0].data, p->data[0].length) == 0)) + return 1; + + return 0; +} +#else +static int +realm_and_service_match(krb5_context context, krb5_principal p, + const char *realm, const char *service) +{ + const char *name, *inst; + + if (p->name.name_string.len != 2) + return 0; + + name = krb5_principal_get_comp_string(context, p, 0); + inst = krb5_principal_get_comp_string(context, p, 1); + if (name == NULL || inst == NULL) + return 0; + if ((strcmp(realm, p->realm) == 0) + && (strcmp(service, name) == 0)) + return 1; + + return 0; +} +#endif + +/* + * Search the given keytab file looking for an entry with the given + * service name and realm, ignoring hostname (instance). + * + * Returns: + * 0 => No error + * non-zero => An error occurred + * + * If a keytab entry is found, "found" is set to one, and the keytab + * entry is returned in "kte". Otherwise, "found" is zero, and the + * value of "kte" is unpredictable. + */ +static int +gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, + const char *realm, const char *service, + int *found, krb5_keytab_entry *kte) +{ + krb5_kt_cursor cursor; + krb5_error_code code; + struct gssd_k5_kt_princ *ple; + int retval = -1, status; + char kt_name[BUFSIZ]; + char *pname; + char *k5err = NULL; + + if (found == NULL) { + retval = EINVAL; + goto out; + } + *found = 0; + + /* + * Look through each entry in the keytab file and determine + * if we might want to use it as machine credentials. If so, + * save info in the global principal list (gssd_k5_kt_princ_list). + */ + if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s attempting to get keytab name\n", k5err); + retval = code; + goto out; + } + if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while beginning keytab scan " + "for keytab '%s'\n", k5err, kt_name); + retval = code; + goto out; + } + + printerr(4, "Scanning keytab for %s/*@%s\n", service, realm); + while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) { + if ((code = krb5_unparse_name(context, kte->principal, + &pname))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "WARNING: Skipping keytab entry because " + "we failed to unparse principal name: %s\n", + k5err); + k5_free_kt_entry(context, kte); + free(k5err); + k5err = NULL; + continue; + } + printerr(4, "Processing keytab entry for principal '%s'\n", + pname); + /* Use the first matching keytab entry found */ +#ifdef HAVE_KRB5 + status = realm_and_service_match(kte->principal, realm, service); +#else + status = realm_and_service_match(context, kte->principal, realm, service); +#endif + if (status) { + printerr(4, "We WILL use this entry (%s)\n", pname); + ple = get_ple_by_princ(context, kte->principal); + /* + * Return, don't free, keytab entry if + * we were successful! + */ + if (ple == NULL) { + retval = ENOMEM; + k5_free_kt_entry(context, kte); + } else { + release_ple(context, ple); + ple = NULL; + retval = 0; + *found = 1; + } + k5_free_unparsed_name(context, pname); + break; + } + else { + printerr(4, "We will NOT use this entry (%s)\n", + pname); + } + k5_free_unparsed_name(context, pname); + k5_free_kt_entry(context, kte); + } + + if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "WARNING: %s while ending keytab scan for " + "keytab '%s'\n", k5err, kt_name); + } + + /* Only clear the retval if has not been set */ + if (retval < 0) + retval = 0; + out: + free(k5err); + return retval; +} + +/* + * Find a keytab entry to use for a given target realm. + * Tries to find the most appropriate keytab to use given the + * name of the host we are trying to connect with. + * + * Note: the tgtname contains a hostname in the realm that we + * are authenticating to. It may, or may not be the same as + * the server hostname. + */ +static int +find_keytab_entry(krb5_context context, krb5_keytab kt, + const char *srchost, const char *tgtname, + krb5_keytab_entry *kte, const char **svcnames) +{ + krb5_error_code code; + char **realmnames = NULL; + char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; + char myhostad[NI_MAXHOST+1]; + int i, j, k, retval; + char *default_realm = NULL; + char *realm; + char *k5err = NULL; + int tried_all = 0, tried_default = 0, tried_upper = 0; + krb5_principal princ; + const char *notsetstr = "not set"; + char *adhostoverride = NULL; + pthread_t tid = pthread_self(); + + + /* Get full target hostname */ + retval = get_full_hostname(tgtname, targethostname, + sizeof(targethostname)); + if (retval) + goto out; + + /* Get full local hostname */ + if (srchost) { + strcpy(myhostname, srchost); + strcpy(myhostad, myhostname); + } else { + /* Borrow myhostad for gethostname(), we need it later anyways */ + if (gethostname(myhostad, sizeof(myhostad)-1) == -1) { + retval = errno; + k5err = gssd_k5_err_msg(context, retval); + printerr(1, "%s while getting local hostname\n", k5err); + goto out; + } + retval = get_full_hostname(myhostad, myhostname, sizeof(myhostname)); + if (retval) { + /* Don't use myhostname */ + myhostname[0] = 0; + } + } + + /* Compute the active directory machine name HOST$ */ + krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", + notsetstr, &adhostoverride); + if (adhostoverride && strcmp(adhostoverride, notsetstr) != 0) { + printerr(1, + "AD host string overridden with \"%s\" from appdefaults\n", + adhostoverride); + /* No overflow: Windows cannot handle strings longer than 19 chars */ + strcpy(myhostad, adhostoverride); + } else { + /* In this case, it's been pre-filled above */ + for (i = 0; myhostad[i] != 0; ++i) { + if (myhostad[i] == '.') break; + } + myhostad[i] = '$'; + myhostad[i+1] = 0; + } + if (adhostoverride) + krb5_free_string(context, adhostoverride); + + code = krb5_get_default_realm(context, &default_realm); + if (code) { + retval = code; + k5err = gssd_k5_err_msg(context, code); + printerr(1, "%s while getting default realm name\n", k5err); + goto out; + } + + /* + * Get the realm name(s) for the target hostname. + * In reality, this function currently only returns a + * single realm, but we code with the assumption that + * someday it may actually return a list. + */ + code = krb5_get_host_realm(context, targethostname, &realmnames); + if (code) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n", + k5err, targethostname); + retval = code; + goto out; + } + + /* + * Make sure the preferred_realm, which may have been explicitly set + * on the command line, is tried first. If nothing is found go on with + * the host and local default realm (if that hasn't already been tried). + */ + i = 0; + realm = realmnames[i]; + + if (preferred_realm && strcmp (realm, preferred_realm) != 0) { + realm = preferred_realm; + /* resetting the realmnames index */ + i = -1; + } + + while (1) { + if (realm == NULL) { + tried_all = 1; + if (!tried_default) + realm = default_realm; + } + if (tried_all && tried_default) + break; + if (strcmp(realm, default_realm) == 0) + tried_default = 1; + for (j = 0; svcnames[j] != NULL; j++) { + char spn[NI_MAXHOST+2]; + + /* + * The special svcname "$" means 'try the active + * directory machine account' + */ + if (strcmp(svcnames[j],"$") == 0) { + snprintf(spn, sizeof(spn), "%s@%s", myhostad, realm); + code = krb5_build_principal_ext(context, &princ, + strlen(realm), + realm, + strlen(myhostad), + myhostad, + NULL); + } else { + if (!myhostname[0]) + continue; + snprintf(spn, sizeof(spn), "%s/%s@%s", + svcnames[j], myhostname, realm); + code = krb5_build_principal_ext(context, &princ, + strlen(realm), + realm, + strlen(svcnames[j]), + svcnames[j], + strlen(myhostname), + myhostname, + NULL); + } + + if (code) { + k5err = gssd_k5_err_msg(context, code); + printerr(1, "%s while building principal for '%s'\n", + k5err, spn); + free(k5err); + k5err = NULL; + continue; + } + code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte); + krb5_free_principal(context, princ); + if (code) { + k5err = gssd_k5_err_msg(context, code); + printerr(3, "%s while getting keytab entry for '%s'\n", + k5err, spn); + free(k5err); + k5err = NULL; + /* + * We tried the active directory machine account + * with the hostname part as-is and failed... + * convert it to uppercase and try again before + * moving on to the svcname + */ + if (strcmp(svcnames[j],"$") == 0 && !tried_upper) { + for (k = 0; myhostad[k] != '$'; ++k) { + myhostad[k] = toupper(myhostad[k]); + } + j--; + tried_upper = 1; + } + } else { + printerr(2, "find_keytab_entry(0x%lx): Success getting keytab entry for '%s'\n",tid, spn); + retval = 0; + goto out; + } + retval = code; + } + /* + * Nothing found with our hostname instance, now look for + * names with any instance (they must have an instance) + */ + for (j = 0; svcnames[j] != NULL; j++) { + int found = 0; + if (strcmp(svcnames[j],"$") == 0) + continue; + code = gssd_search_krb5_keytab(context, kt, realm, + svcnames[j], &found, kte); + if (!code && found) { + printerr(3, "Success getting keytab entry for " + "%s/*@%s\n", svcnames[j], realm); + retval = 0; + goto out; + } + } + if (!tried_all) { + i++; + realm = realmnames[i]; + } + } +out: + if (default_realm) + k5_free_default_realm(context, default_realm); + if (realmnames) + krb5_free_host_realm(context, realmnames); + free(k5err); + return retval; +} + + +static inline int data_is_equal(krb5_data d1, krb5_data d2) +{ + return (d1.length == d2.length + && memcmp(d1.data, d2.data, d1.length) == 0); +} + +static int +check_for_tgt(krb5_context context, krb5_ccache ccache, + krb5_principal principal) +{ + krb5_error_code ret; + krb5_creds creds; + krb5_cc_cursor cur; + int found = 0; + + ret = krb5_cc_start_seq_get(context, ccache, &cur); + if (ret) + return 0; + + while (!found && + (ret = krb5_cc_next_cred(context, ccache, &cur, &creds)) == 0) { + if (creds.server->length == 2 && + data_is_equal(creds.server->realm, + principal->realm) && + creds.server->data[0].length == 6 && + memcmp(creds.server->data[0].data, + "krbtgt", 6) == 0 && + data_is_equal(creds.server->data[1], + principal->realm) && + creds.times.endtime > time(NULL)) + found = 1; + krb5_free_cred_contents(context, &creds); + } + krb5_cc_end_seq_get(context, ccache, &cur); + + return found; +} + +static int +query_krb5_ccache(const char* cred_cache, char **ret_princname, + char **ret_realm) +{ + krb5_error_code ret; + krb5_context context; + krb5_ccache ccache; + krb5_principal principal; + int found = 0; + char *str = NULL; + char *princstring; + + *ret_princname = *ret_realm = NULL; + + ret = krb5_init_context(&context); + if (ret) + return 0; + + if(!cred_cache || krb5_cc_resolve(context, cred_cache, &ccache)) + goto err_cache; + + if (krb5_cc_set_flags(context, ccache, 0)) + goto err_princ; + + ret = krb5_cc_get_principal(context, ccache, &principal); + if (ret) + goto err_princ; + + found = check_for_tgt(context, ccache, principal); + if (found) { + ret = krb5_unparse_name(context, principal, &princstring); + if (ret == 0) { + if ((str = strchr(princstring, '@')) != NULL) { + *str = '\0'; + *ret_princname = strdup(princstring); + *ret_realm = strdup(str+1); + if (!*ret_princname || !*ret_realm) { + free(*ret_princname); + free(*ret_realm); + *ret_princname = NULL; + *ret_realm = NULL; + } + } + k5_free_unparsed_name(context, princstring); + } + } + krb5_free_principal(context, principal); +err_princ: + krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); + krb5_cc_close(context, ccache); +err_cache: + krb5_free_context(context); + return (*ret_princname && *ret_realm); +} + +/* + * Obtain (or refresh if necessary) Kerberos machine credentials + * If a ple is passed in, it's reference will be released + */ +static int +gssd_refresh_krb5_machine_credential_internal(char *hostname, + struct gssd_k5_kt_princ *ple, + char *service, char *srchost, + int force_renew) +{ + krb5_error_code code = 0; + krb5_context context; + krb5_keytab kt = NULL;; + int retval = 0; + char *k5err = NULL; + const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; + + /* + * If a specific service name was specified, use it. + * Otherwise, use the default list. + */ + if (service != NULL && strcmp(service, "*") != 0) { + svcnames[0] = service; + svcnames[1] = NULL; + } + if (hostname == NULL && ple == NULL) { + printerr(0, "ERROR: %s: Invalid args\n", __func__); + return EINVAL; + } + code = krb5_init_context(&context); + if (code) { + k5err = gssd_k5_err_msg(NULL, code); + printerr(0, "ERROR: %s: %s while initializing krb5 context\n", + __func__, k5err); + retval = code; + goto out; + } + + if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", + __func__, k5err, keytabfile); + goto out_free_context; + } + + if (ple == NULL) { + krb5_keytab_entry kte; + + code = find_keytab_entry(context, kt, srchost, hostname, + &kte, svcnames); + if (code) { + printerr(0, "ERROR: %s: no usable keytab entry found " + "in keytab %s for connection with host %s\n", + __FUNCTION__, keytabfile, hostname); + retval = code; + goto out_free_kt; + } + + ple = get_ple_by_princ(context, kte.principal); + k5_free_kt_entry(context, &kte); + if (ple == NULL) { + char *pname; + if ((krb5_unparse_name(context, kte.principal, &pname))) { + pname = NULL; + } + printerr(0, "ERROR: %s: Could not locate or create " + "ple struct for principal %s for connection " + "with host %s\n", + __FUNCTION__, pname ? pname : "", + hostname); + if (pname) k5_free_unparsed_name(context, pname); + goto out_free_kt; + } + } + retval = gssd_get_single_krb5_cred(context, kt, ple, force_renew); +out_free_kt: + krb5_kt_close(context, kt); +out_free_context: + if (ple) + release_ple(context, ple); + krb5_free_context(context); +out: + free(k5err); + return retval; +} + +/*==========================*/ +/*=== External routines ===*/ +/*==========================*/ + +/* + * Attempt to find the best match for a credentials cache file + * given only a UID. We really need more information, but we + * do the best we can. + * + * Returns 0 if a ccache was found, or a negative errno otherwise. + */ +int +gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern) +{ + /* dirname + cctype + d_name + NULL */ + char buf[PATH_MAX+5+256+1], dirname[PATH_MAX]; + const char *cctype; + struct dirent *d; + int err, i, j; + u_int maj_stat, min_stat; + + printerr(3, "looking for client creds with uid %u for " + "server %s in %s\n", uid, servername, dirpattern); + + for (i = 0, j = 0; dirpattern[i] != '\0'; i++) { + switch (dirpattern[i]) { + case '%': + switch (dirpattern[i + 1]) { + case '%': + dirname[j++] = dirpattern[i]; + i++; + break; + case 'U': + j += sprintf(dirname + j, "%lu", + (unsigned long) uid); + i++; + break; + } + break; + default: + dirname[j++] = dirpattern[i]; + break; + } + } + dirname[j] = '\0'; + + err = gssd_find_existing_krb5_ccache(uid, dirname, &cctype, &d); + if (err) + return err; + + snprintf(buf, sizeof(buf), "%s:%s/%s", cctype, dirname, d->d_name); + free(d); + + printerr(2, "using %s as credentials cache for client with " + "uid %u for server %s\n", buf, uid, servername); + + printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n", + buf); + maj_stat = gss_krb5_ccache_name(&min_stat, buf, NULL); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "ERROR: unable to get user cred cache '%s' " + "failed (%s)\n", buf, error_message(min_stat)); + return maj_stat; + } + return 0; +} + +/* + * Return an array of pointers to names of credential cache files + * which can be used to try to create gss contexts with a server. + * + * Returns: + * 0 => list is attached + * nonzero => error + */ +int +gssd_get_krb5_machine_cred_list(char ***list) +{ + char **l; + int listinc = 10; + int listsize = listinc; + int i = 0; + int retval; + struct gssd_k5_kt_princ *ple; + + /* Assume failure */ + retval = -1; + *list = (char **) NULL; + + if ((l = (char **) malloc(listsize * sizeof(char *))) == NULL) { + retval = ENOMEM; + goto out; + } + + pthread_mutex_lock(&ple_lock); + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { + if (!ple->ccname) + continue; + + /* Take advantage of the fact we only remove the ple + * from the list during shutdown. If it's modified + * concurrently at worst we'll just miss a new entry + * before the current ple + * + * gssd_refresh_krb5_machine_credential_internal() will + * release the ple refcount + */ + ple->refcount++; + pthread_mutex_unlock(&ple_lock); + /* Make sure cred is up-to-date before returning it */ + retval = gssd_refresh_krb5_machine_credential_internal(NULL, ple, + NULL, NULL, 0); + pthread_mutex_lock(&ple_lock); + if (gssd_k5_kt_princ_list == NULL) { + /* Looks like we did shutdown... abort */ + l[i] = NULL; + gssd_free_krb5_machine_cred_list(l); + retval = ENOMEM; + goto out_lock; + } + if (retval) + continue; + if (i + 1 > listsize) { + char **tmplist; + listsize += listinc; + tmplist = (char **) + realloc(l, listsize * sizeof(char *)); + if (tmplist == NULL) { + gssd_free_krb5_machine_cred_list(l); + retval = ENOMEM; + goto out_lock; + } + l = tmplist; + } + if ((l[i++] = strdup(ple->ccname)) == NULL) { + gssd_free_krb5_machine_cred_list(l); + retval = ENOMEM; + goto out_lock; + } + } + if (i > 0) { + l[i] = NULL; + *list = l; + retval = 0; + } else + free((void *)l); +out_lock: + pthread_mutex_unlock(&ple_lock); + out: + return retval; +} + +/* + * Frees the list of names returned in get_krb5_machine_cred_list() + */ +void +gssd_free_krb5_machine_cred_list(char **list) +{ + char **n; + + if (list == NULL) + return; + for (n = list; n && *n; n++) { + free(*n); + } + free(list); +} + +/* + * Called upon exit. Destroys machine credentials. + */ +void +gssd_destroy_krb5_principals(int destroy_machine_creds) +{ + krb5_context context; + krb5_error_code code = 0; + krb5_ccache ccache; + struct gssd_k5_kt_princ *ple; + char *k5err = NULL; + + code = krb5_init_context(&context); + if (code) { + k5err = gssd_k5_err_msg(NULL, code); + printerr(0, "ERROR: %s while initializing krb5\n", k5err); + free(k5err); + return; + } + + pthread_mutex_lock(&ple_lock); + while (gssd_k5_kt_princ_list) { + ple = gssd_k5_kt_princ_list; + gssd_k5_kt_princ_list = ple->next; + + if (destroy_machine_creds && ple->ccname) { + if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "WARNING: %s while resolving credential " + "cache '%s' for destruction\n", k5err, + ple->ccname); + free(k5err); + k5err = NULL; + } + + if (!code && (code = krb5_cc_destroy(context, ccache))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "WARNING: %s while destroying credential " + "cache '%s'\n", k5err, ple->ccname); + free(k5err); + k5err = NULL; + } + } + + release_ple_locked(context, ple); + } + pthread_mutex_unlock(&ple_lock); + krb5_free_context(context); +} + +/* + * Obtain (or refresh if necessary) Kerberos machine credentials + */ +int +gssd_refresh_krb5_machine_credential(char *hostname, + char *service, char *srchost, + int force_renew) +{ + return gssd_refresh_krb5_machine_credential_internal(hostname, NULL, + service, srchost, + force_renew); +} + +/* + * A common routine for getting the Kerberos error message + */ +char * +gssd_k5_err_msg(krb5_context context, krb5_error_code code) +{ + const char *origmsg; + char *msg = NULL; + +#if HAVE_KRB5_GET_ERROR_MESSAGE + if (context != NULL) { + origmsg = krb5_get_error_message(context, code); + msg = strdup(origmsg); + krb5_free_error_message(context, origmsg); + } +#endif + if (msg != NULL) + return msg; +#if HAVE_KRB5 + return strdup(error_message(code)); +#else + if (context != NULL) + return strdup(krb5_get_err_text(context, code)); + else + return strdup(error_message(code)); +#endif +} + +/* + * Return default Kerberos realm + */ +void +gssd_k5_get_default_realm(char **def_realm) +{ + krb5_context context; + + if (krb5_init_context(&context)) + return; + + krb5_get_default_realm(context, def_realm); + + krb5_free_context(context); +} + +static int +gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred) +{ + OM_uint32 maj_stat, min_stat; + gss_OID_set_desc desired_mechs = { 1, &krb5oid }; + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE, + &desired_mechs, GSS_C_INITIATE, + gss_cred, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + if (get_verbosity() > 0) + pgsserr("gss_acquire_cred", + maj_stat, min_stat, &krb5oid); + return -1; + } + + return 0; +} + +int +gssd_acquire_user_cred(gss_cred_id_t *gss_cred) +{ + OM_uint32 maj_stat, min_stat; + int ret; + + ret = gssd_acquire_krb5_cred(gss_cred); + if (ret) + return ret; + + /* force validation of cred to check for expiry */ + maj_stat = gss_inquire_cred(&min_stat, *gss_cred, + NULL, NULL, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) { + if (get_verbosity() > 0) + pgsserr("gss_inquire_cred", + maj_stat, min_stat, &krb5oid); + ret = -1; + } + + return ret; +} + +/* Removed a service ticket for nfs/ from the ticket cache + */ +int +gssd_k5_remove_bad_service_cred(char *name) +{ + krb5_creds in_creds, out_creds; + krb5_error_code ret; + krb5_context context; + krb5_ccache cache; + krb5_principal principal; + int retflags = KRB5_TC_MATCH_SRV_NAMEONLY; + char srvname[1024]; + + ret = krb5_init_context(&context); + if (ret) + goto out_cred; + ret = krb5_cc_default(context, &cache); + if (ret) + goto out_free_context; + ret = krb5_cc_get_principal(context, cache, &principal); + if (ret) + goto out_close_cache; + memset(&in_creds, 0, sizeof(in_creds)); + in_creds.client = principal; + sprintf(srvname, "nfs/%s", name); + ret = krb5_parse_name(context, srvname, &in_creds.server); + if (ret) + goto out_free_principal; + ret = krb5_cc_retrieve_cred(context, cache, retflags, &in_creds, &out_creds); + if (ret) + goto out_free_principal; + ret = krb5_cc_remove_cred(context, cache, 0, &out_creds); +out_free_principal: + krb5_free_principal(context, principal); +out_close_cache: + krb5_cc_close(context, cache); +out_free_context: + krb5_free_context(context); +out_cred: + return ret; +} + +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES +/* + * this routine obtains a credentials handle via gss_acquire_cred() + * then calls gss_krb5_set_allowable_enctypes() to limit the encryption + * types negotiated. + * + * XXX Should call some function to determine the enctypes supported + * by the kernel. (Only need to do that once!) + * + * Returns: + * 0 => all went well + * -1 => there was an error + */ + +int +limit_krb5_enctypes(struct rpc_gss_sec *sec) +{ + u_int maj_stat, min_stat; + krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC, + ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_MD4 }; + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); + extern int num_krb5_enctypes; + extern krb5_enctype *krb5_enctypes; + int err = -1; + + if (sec->cred == GSS_C_NO_CREDENTIAL) { + err = gssd_acquire_krb5_cred(&sec->cred); + if (err) + return -1; + } + + /* + * If we failed for any reason to produce global + * list of supported enctypes, use local default here. + */ + if (krb5_enctypes == NULL || limit_to_legacy_enctypes) + maj_stat = gss_set_allowable_enctypes(&min_stat, sec->cred, + &krb5oid, num_enctypes, enctypes); + else + maj_stat = gss_set_allowable_enctypes(&min_stat, sec->cred, + &krb5oid, num_krb5_enctypes, krb5_enctypes); + + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_set_allowable_enctypes", + maj_stat, min_stat, &krb5oid); + return -1; + } + + return 0; +} +#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h new file mode 100644 index 0000000..7ef8701 --- /dev/null +++ b/utils/gssd/krb5_util.h @@ -0,0 +1,47 @@ +#ifndef KRB5_UTIL_H +#define KRB5_UTIL_H + +#include + +#ifdef HAVE_LIBTIRPC +#include +#else +#include "gss_oids.h" +#endif + + +int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, + char *dirname); +int gssd_get_krb5_machine_cred_list(char ***list); +void gssd_free_krb5_machine_cred_list(char **list); +void gssd_destroy_krb5_principals(int destroy_machine_creds); +int gssd_refresh_krb5_machine_credential(char *hostname, + char *service, char *srchost, + int force_renew); +char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); +void gssd_k5_get_default_realm(char **def_realm); + +int gssd_acquire_user_cred(gss_cred_id_t *gss_cred); +int gssd_k5_remove_bad_service_cred(char *srvname); + +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES +extern int limit_to_legacy_enctypes; +int limit_krb5_enctypes(struct rpc_gss_sec *sec); +#endif + +/* + * Hide away some of the MIT vs. Heimdal differences + * here with macros... + */ + +#ifdef HAVE_KRB5 +#define k5_free_unparsed_name(ctx, name) krb5_free_unparsed_name((ctx), (name)) +#define k5_free_default_realm(ctx, realm) krb5_free_default_realm((ctx), (realm)) +#define k5_free_kt_entry(ctx, kte) krb5_free_keytab_entry_contents((ctx),(kte)) +#else /* Heimdal */ +#define k5_free_unparsed_name(ctx, name) free(name) +#define k5_free_default_realm(ctx, realm) free(realm) +#define k5_free_kt_entry(ctx, kte) krb5_kt_free_entry((ctx),(kte)) +#endif + +#endif /* KRB5_UTIL_H */ diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c new file mode 100644 index 0000000..ce78d8f --- /dev/null +++ b/utils/gssd/svcgssd.c @@ -0,0 +1,348 @@ +/* + gssd.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2002 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + Copyright (c) 2002 J. Bruce Fields . + All rights reserved, all wrongs reversed. + + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfslib.h" +#include "svcgssd.h" +#include "gss_util.h" +#include "err_util.h" +#include "conffile.h" +#include "misc.h" +#include "svcgssd_krb5.h" + +static bool signal_received = false; +static struct event_base *evbase = NULL; +static int nullrpc_fd = -1; +static struct event *nullrpc_event = NULL; +static struct event *wait_event = NULL; + +#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" + +static void +sig_die(int signal) +{ + if (signal_received) { + /* destroy krb5 machine creds */ + printerr(1, "forced exiting on signal %d\n", signal); + exit(0); + } + signal_received = true; + printerr(1, "exiting on signal %d\n", signal); + event_base_loopexit(evbase, NULL); +} + +static void +sig_hup(int signal) +{ + /* don't exit on SIGHUP */ + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); + return; +} + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-i] [-p principal]\n", + progname); + exit(1); +} + +static void +svcgssd_nullrpc_cb(int fd, short UNUSED(which), void *UNUSED(data)) +{ + char lbuf[RPC_CHAN_BUF_SIZE]; + int lbuflen = 0; + + printerr(1, "reading null request\n"); + + lbuflen = read(fd, lbuf, sizeof(lbuf)); + if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') { + printerr(0, "WARNING: handle_nullreq: failed reading request\n"); + return; + } + lbuf[lbuflen-1] = 0; + + handle_nullreq(lbuf); +} + +static void +svcgssd_nullrpc_close(void) +{ + if (nullrpc_event) { + printerr(2, "closing nullrpc channel %s\n", NULLRPC_FILE); + event_free(nullrpc_event); + nullrpc_event = NULL; + } + if (nullrpc_fd != -1) { + close(nullrpc_fd); + nullrpc_fd = -1; + } +} + +static void +svcgssd_nullrpc_open(void) +{ + nullrpc_fd = open(NULLRPC_FILE, O_RDWR); + if (nullrpc_fd < 0) { + printerr(0, "failed to open %s: %s\n", + NULLRPC_FILE, strerror(errno)); + return; + } + nullrpc_event = event_new(evbase, nullrpc_fd, EV_READ | EV_PERSIST, + svcgssd_nullrpc_cb, NULL); + if (!nullrpc_event) { + printerr(0, "failed to create event for %s: %s\n", + NULLRPC_FILE, strerror(errno)); + close(nullrpc_fd); + nullrpc_fd = -1; + return; + } + event_add(nullrpc_event, NULL); + printerr(2, "opened nullrpc channel %s\n", NULLRPC_FILE); +} + +static void +svcgssd_wait_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) +{ + static int times = 0; + int rc; + + rc = access(NULLRPC_FILE, R_OK | W_OK); + if (rc != 0) { + struct timeval t = {times < 10 ? 1 : 10, 0}; + times++; + if (times % 30 == 0) + printerr(2, "still waiting for nullrpc channel: %s\n", + NULLRPC_FILE); + evtimer_add(wait_event, &t); + return; + } + + svcgssd_nullrpc_open(); + event_free(wait_event); + wait_event = NULL; +} + + + +int +main(int argc, char *argv[]) +{ + int get_creds = 1; + int fg = 0; + int verbosity = 0; + int rpc_verbosity = 0; + int idmap_verbosity = 0; + int opt, status; + extern char *optarg; + char *progname; + char *principal = NULL; + char *s; + int rc; + + conf_init_file(NFS_CONFFILE); + + s = conf_get_str("svcgssd", "principal"); + if (!s) + ; + else if (strcmp(s, "system")== 0) + get_creds = 0; + else + principal = s; + + verbosity = conf_get_num("svcgssd", "Verbosity", verbosity); + rpc_verbosity = conf_get_num("svcgssd", "RPC-Verbosity", rpc_verbosity); + idmap_verbosity = conf_get_num("svcgssd", "IDMAP-Verbosity", idmap_verbosity); + + while ((opt = getopt(argc, argv, "fivrnp:")) != -1) { + switch (opt) { + case 'f': + fg = 1; + break; + case 'i': + idmap_verbosity++; + break; + case 'n': + get_creds = 0; + break; + case 'v': + verbosity++; + break; + case 'r': + rpc_verbosity++; + break; + case 'p': + principal = optarg; + break; + default: + usage(argv[0]); + break; + } + } + + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + + initerr(progname, verbosity, fg); +#ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL + if (verbosity && rpc_verbosity == 0) + rpc_verbosity = verbosity; + authgss_set_debug_level(rpc_verbosity); +#elif HAVE_LIBTIRPC_SET_DEBUG + /* + * Only set the libtirpc debug level if explicitly requested via -r... + * svcgssd is chatty enough as it is. + */ + if (rpc_verbosity > 0) + libtirpc_set_debug(progname, rpc_verbosity, fg); +#else + if (rpc_verbosity > 0) + printerr(0, "Warning: rpcsec_gss library does not " + "support setting debug level\n"); +#endif +#ifdef HAVE_NFS4_SET_DEBUG + if (verbosity && idmap_verbosity == 0) + idmap_verbosity = verbosity; + nfs4_set_debug(idmap_verbosity, NULL); +#else + if (idmap_verbosity > 0) + printerr(0, "Warning: your nfsidmap library does not " + "support setting debug level\n"); +#endif + + if (gssd_check_mechs() != 0) { + printerr(0, "ERROR: Problem with gssapi library\n"); + exit(1); + } + + daemon_init(fg); + + evbase = event_base_new(); + if (!evbase) { + printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + signal(SIGHUP, sig_hup); + + if (get_creds) { + if (principal) + status = gssd_acquire_cred(principal, + ((const gss_OID)GSS_C_NT_USER_NAME)); + else + status = gssd_acquire_cred(GSSD_SERVICE_NAME, + (const gss_OID)GSS_C_NT_HOSTBASED_SERVICE); + if (status == FALSE) { + printerr(0, "unable to obtain root (machine) credentials\n"); + printerr(0, "do you have a keytab entry for %s in" + "/etc/krb5.keytab?\n", + principal ? principal : "nfs/@"); + exit(1); + } + } else { + status = gssd_acquire_cred(NULL, + (const gss_OID)GSS_C_NT_HOSTBASED_SERVICE); + if (status == FALSE) { + printerr(0, "unable to obtain nameless credentials\n"); + exit(1); + } + } + + svcgssd_nullrpc_open(); + if (!nullrpc_event) { + struct timeval t = {1, 0}; + + printerr(2, "waiting for nullrpc channel to appear\n"); + wait_event = evtimer_new(evbase, svcgssd_wait_cb, NULL); + if (!wait_event) { + printerr(0, "ERROR: failed to create wait event: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + evtimer_add(wait_event, &t); + } + + daemon_ready(); + + /* We don't need the config anymore */ + conf_cleanup(); + + nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ + + rc = event_base_dispatch(evbase); + if (rc < 0) + printerr(0, "event_base_dispatch() returned %i!\n", rc); + + svcgssd_nullrpc_close(); + if (wait_event) + event_free(wait_event); + + event_base_free(evbase); + + nfs4_term_name_mapping(); + svcgssd_free_enctypes(); + gssd_cleanup(); + + return EXIT_SUCCESS; +} diff --git a/utils/gssd/svcgssd.h b/utils/gssd/svcgssd.h new file mode 100644 index 0000000..e229b98 --- /dev/null +++ b/utils/gssd/svcgssd.h @@ -0,0 +1,42 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _RPC_SVCGSSD_H_ +#define _RPC_SVCGSSD_H_ + +#include +#include +#include + +void handle_nullreq(char *cp); + +#define GSSD_SERVICE_NAME "nfs" + +#endif /* _RPC_SVCGSSD_H_ */ diff --git a/utils/gssd/svcgssd.man b/utils/gssd/svcgssd.man new file mode 100644 index 0000000..8771c03 --- /dev/null +++ b/utils/gssd/svcgssd.man @@ -0,0 +1,88 @@ +.\" +.\" rpc.svcgssd(8) +.\" +.\" Copyright (C) 2003 J. Bruce Fields +.TH rpc.svcgssd 8 "12 Jan 2007" +.SH NAME +rpc.svcgssd \- server-side rpcsec_gss daemon +.SH SYNOPSIS +.B "rpc.svcgssd [-n] [-v] [-r] [-i] [-f] [-p principal]" +.SH DESCRIPTION +The rpcsec_gss protocol gives a means of using the gss-api generic security +api to provide security for protocols using rpc (in particular, nfs). Before +exchanging any rpc requests using rpcsec_gss, the rpc client must first +establish a security context with the rpc server. The linux kernel's +implementation of rpcsec_gss depends on the userspace daemon +.B rpc.svcgssd +to handle context establishment on the rpc server. The +daemon uses files in the proc filesystem to communicate with +the kernel. + +.SH OPTIONS +.TP +.B -f +Runs +.B rpc.svcgssd +in the foreground and sends output to stderr (as opposed to syslogd) +.TP +.B -v +Increases the verbosity of the output (can be specified multiple times). +.TP +.B -r +If the rpcsec_gss library supports setting debug level, +increases the verbosity of the output (can be specified multiple times). +.TP +.B -i +If the nfsidmap library supports setting debug level, +increases the verbosity of the output (can be specified multiple times). +.TP +.B -p +Use \fIprincipal\fR instead of the default +.RI nfs/ FQDN @ REALM . +.TP +.B -n +Use the system default credentials +.RI (host/ FQDN @ REALM ) +rather than the default +.RI nfs/ FQDN @ REALM . +.SH CONFIGURATION FILE +Some of the options that can be set on the command line can also be +controlled through values set in the +.B [svcgssd] +section of the +.I /etc/nfs.conf +configuration file. Values recognized include: +.TP +.B principal +If set to +.B system +this is equivalent to the +.B -n +option. If set to any other value, that is used like the +.B -p +option. +.TP +.B verbosity +Value which is equivalent to the number of +.BR -v . +.TP +.B rpc-verbosity +Value which is equivalent to the number of +.BR -r . +.TP +.B idmap-verbosity +Value which is equivalent to the number of +.BR -i . + + +.SH SEE ALSO +.BR rpc.gssd(8), +.SH AUTHORS +.br +Dug Song +.br +Andy Adamson +.br +Marius Aamodt Eriksen +.br +J. Bruce Fields diff --git a/utils/gssd/svcgssd_krb5.c b/utils/gssd/svcgssd_krb5.c new file mode 100644 index 0000000..2503c38 --- /dev/null +++ b/utils/gssd/svcgssd_krb5.c @@ -0,0 +1,237 @@ +/* + * COPYRIGHT (c) 2011 + * The Regents of the University of Michigan + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include "gss_util.h" +#include "gss_oids.h" +#include "err_util.h" +#include "svcgssd_krb5.h" +#include "version.h" + +#define MYBUFLEN 1024 + +char *supported_enctypes_filename = "/proc/fs/nfsd/supported_krb5_enctypes"; +int parsed_num_enctypes = 0; +krb5_enctype *parsed_enctypes = NULL; +char *cached_enctypes = NULL; + +/*==========================*/ +/*=== Internal routines ===*/ +/*==========================*/ + +/* + * Parse the supported encryption type information + */ +static int +parse_enctypes(char *enctypes) +{ + int n = 0; + char *curr, *comma; + int i; + + /* Don't parse the same string over and over... */ + if (cached_enctypes && strcmp(cached_enctypes, enctypes) == 0) + return 0; + + /* Free any existing cached_enctypes */ + svcgssd_free_enctypes(); + + /* count the number of commas */ + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { + comma = strchr(curr, ','); + if (comma != NULL) + n++; + else + break; + } + + /* If no more commas and we're not at the end, there's one more value */ + if (*curr != '\0') + n++; + + /* Empty string, return an error */ + if (n == 0) + return ENOENT; + + /* Skip pass any non digits */ + while (*enctypes && isdigit(*enctypes) == 0) + enctypes++; + if (*enctypes == '\0') + return EINVAL; + + /* Allocate space for enctypes array */ + if ((parsed_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { + return ENOMEM; + } + + /* Now parse each value into the array */ + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { + parsed_enctypes[i++] = atoi(curr); + comma = strchr(curr, ','); + if (comma == NULL) + break; + } + + parsed_num_enctypes = n; + if ((cached_enctypes = malloc(strlen(enctypes)+1))) + strcpy(cached_enctypes, enctypes); + + return 0; +} + +static void +get_kernel_supported_enctypes(void) +{ + FILE *s_e; + int ret; + char buffer[MYBUFLEN + 1]; + + memset(buffer, '\0', sizeof(buffer)); + + s_e = fopen(supported_enctypes_filename, "r"); + if (s_e == NULL) + goto out_clean_parsed; + + ret = fread(buffer, 1, MYBUFLEN, s_e); + if (ret < 0) { + fclose(s_e); + goto out_clean_parsed; + } + fclose(s_e); + if (parse_enctypes(buffer)) { + goto out_clean_parsed; + } +out: + return; + +out_clean_parsed: + if (parsed_enctypes != NULL) { + free(parsed_enctypes); + parsed_num_enctypes = 0; + } + goto out; +} + +/*==========================*/ +/*=== External routines ===*/ +/*==========================*/ + +void +svcgssd_free_enctypes(void) +{ + free(cached_enctypes); + cached_enctypes = NULL; + + if (parsed_enctypes != NULL) { + free(parsed_enctypes); + parsed_enctypes = NULL; + parsed_num_enctypes = 0; + } +} + +/* + * Get encryption types supported by the kernel, and then + * call gss_krb5_set_allowable_enctypes() to limit the + * encryption types negotiated. + * + * Returns: + * 0 => all went well + * -1 => there was an error + */ + +int +svcgssd_limit_krb5_enctypes(void) +{ +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + u_int maj_stat, min_stat; + krb5_enctype old_kernel_enctypes[] = { + ENCTYPE_DES_CBC_CRC, + ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_MD4 }; + krb5_enctype new_kernel_enctypes[] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, + ENCTYPE_DES3_CBC_SHA1, + ENCTYPE_ARCFOUR_HMAC, + ENCTYPE_DES_CBC_CRC, + ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_MD4 }; + krb5_enctype *default_enctypes, *enctypes; + int default_num_enctypes, num_enctypes; + + + if (linux_version_code() < MAKE_VERSION(2, 6, 35)) { + default_enctypes = old_kernel_enctypes; + default_num_enctypes = + sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]); + } else { + default_enctypes = new_kernel_enctypes; + default_num_enctypes = + sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]); + } + + get_kernel_supported_enctypes(); + + if (parsed_enctypes != NULL) { + enctypes = parsed_enctypes; + num_enctypes = parsed_num_enctypes; + printerr(2, "%s: Calling gss_set_allowable_enctypes with %d " + "enctypes from the kernel\n", __func__, num_enctypes); + } else { + enctypes = default_enctypes; + num_enctypes = default_num_enctypes; + printerr(2, "%s: Calling gss_set_allowable_enctypes with %d " + "enctypes from defaults\n", __func__, num_enctypes); + } + + maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds, + &krb5oid, num_enctypes, enctypes); + if (maj_stat != GSS_S_COMPLETE) { + printerr(1, "WARNING: gss_set_allowable_enctypes failed\n"); + pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes", + maj_stat, min_stat, &krb5oid); + return -1; + } +#endif + return 0; +} diff --git a/utils/gssd/svcgssd_krb5.h b/utils/gssd/svcgssd_krb5.h new file mode 100644 index 0000000..78a90e9 --- /dev/null +++ b/utils/gssd/svcgssd_krb5.h @@ -0,0 +1,37 @@ +/* + * COPYRIGHT (c) 2011 + * The Regents of the University of Michigan + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#ifndef SVCGSSD_KRB5_H +#define SVCGSSD_KRB5_H + +int svcgssd_limit_krb5_enctypes(void); +void svcgssd_free_enctypes(void); + +#endif /* SVCGSSD_KRB5_H */ diff --git a/utils/gssd/svcgssd_mech2file.c b/utils/gssd/svcgssd_mech2file.c new file mode 100644 index 0000000..c26b435 --- /dev/null +++ b/utils/gssd/svcgssd_mech2file.c @@ -0,0 +1,74 @@ +/* + linux_downcall.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2004 Andy Adamson . + All rights reserved, all wrongs reversed. + + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +char * mech2file(gss_OID mech); + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +struct mech2file { + gss_OID_desc mech; + char filename[8]; +}; + +struct mech2file m2f[] = { + {{9, "\052\206\110\206\367\022\001\002\002"}, "krb5"}, + {{0,0},""}, +}; + +/* + * Find the Linux svcgssd downcall file name given the mechanism + */ +char * +mech2file(gss_OID mech) +{ + struct mech2file *m2fp = m2f; + + while(m2fp->mech.length != 0) { + if (g_OID_equal(mech,&m2fp->mech)) + return(m2fp->filename); + m2fp++; + } + return NULL; +} diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c new file mode 100644 index 0000000..b403143 --- /dev/null +++ b/utils/gssd/svcgssd_proc.c @@ -0,0 +1,444 @@ +/* + svc_in_gssd_proc.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2002 Bruce Fields + + 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 University 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 ``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 REGENTS 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. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svcgssd.h" +#include "gss_util.h" +#include "err_util.h" +#include "context.h" +#include "misc.h" +#include "gss_oids.h" +#include "svcgssd_krb5.h" +#include "gss_names.h" + +extern char * mech2file(gss_OID mech); +#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" +#define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel" + +#define TOKEN_BUF_SIZE 8192 + +struct svc_cred { + uid_t cr_uid; + gid_t cr_gid; + int cr_ngroups; + gid_t cr_groups[NGROUPS]; +}; + +static int +do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, + gss_OID mech, gss_buffer_desc *context_token, + int32_t endtime, char *client_name) +{ + char buf[RPC_CHAN_BUF_SIZE], *bp; + int i, f, err, blen; + char *fname = NULL; + + printerr(1, "doing downcall\n"); + if ((fname = mech2file(mech)) == NULL) + goto out_err; + + f = open(SVCGSSD_CONTEXT_CHANNEL, O_WRONLY); + if (f < 0) { + printerr(0, "WARNING: unable to open downcall channel " + "%s: %s\n", + SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); + goto out_err; + } + bp = buf, blen = sizeof(buf); + qword_addhex(&bp, &blen, out_handle->value, out_handle->length); + /* XXX are types OK for the rest of this? */ + /* For context cache, use the actual context endtime */ + qword_addint(&bp, &blen, endtime); + qword_addint(&bp, &blen, cred->cr_uid); + qword_addint(&bp, &blen, cred->cr_gid); + qword_addint(&bp, &blen, cred->cr_ngroups); + printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), " + "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n", + fname, out_handle->length, context_token->length, + endtime, endtime - time(0), + client_name ? client_name : "", + cred->cr_uid, cred->cr_gid, cred->cr_ngroups); + for (i=0; i < cred->cr_ngroups; i++) { + qword_addint(&bp, &blen, cred->cr_groups[i]); + printerr(2, " (%4d) %d\n", i+1, cred->cr_groups[i]); + } + qword_add(&bp, &blen, fname); + qword_addhex(&bp, &blen, context_token->value, context_token->length); + if (client_name) + qword_add(&bp, &blen, client_name); + qword_addeol(&bp, &blen); + err = 0; + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { + printerr(1, "WARNING: error writing to downcall channel " + "%s: %s\n", SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); + err = -1; + } + close(f); + return err; +out_err: + printerr(1, "WARNING: downcall failed\n"); + return -1; +} + +struct gss_verifier { + u_int32_t flav; + gss_buffer_desc body; +}; + +#define RPCSEC_GSS_SEQ_WIN 5 + +static int +send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token, + u_int32_t maj_stat, u_int32_t min_stat, + gss_buffer_desc *out_handle, gss_buffer_desc *out_token) +{ + char buf[2 * TOKEN_BUF_SIZE]; + char *bp = buf; + int blen = sizeof(buf); + /* XXXARG: */ + int g; + + printerr(1, "sending null reply\n"); + + qword_addhex(&bp, &blen, in_handle->value, in_handle->length); + qword_addhex(&bp, &blen, in_token->value, in_token->length); + /* For init cache, only needed for a short time */ + qword_addint(&bp, &blen, time(0) + 60); + qword_adduint(&bp, &blen, maj_stat); + qword_adduint(&bp, &blen, min_stat); + qword_addhex(&bp, &blen, out_handle->value, out_handle->length); + qword_addhex(&bp, &blen, out_token->value, out_token->length); + qword_addeol(&bp, &blen); + if (blen <= 0) { + printerr(0, "WARNING: send_respsonse: message too long\n"); + return -1; + } + g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY); + if (g == -1) { + printerr(0, "WARNING: open %s failed: %s\n", + SVCGSSD_INIT_CHANNEL, strerror(errno)); + return -1; + } + *bp = '\0'; + printerr(3, "writing message: %s", buf); + if (write(g, buf, bp - buf) == -1) { + printerr(0, "WARNING: failed to write message\n"); + close(g); + return -1; + } + close(g); + return 0; +} + +#define rpc_auth_ok 0 +#define rpc_autherr_badcred 1 +#define rpc_autherr_rejectedcred 2 +#define rpc_autherr_badverf 3 +#define rpc_autherr_rejectedverf 4 +#define rpc_autherr_tooweak 5 +#define rpcsec_gsserr_credproblem 13 +#define rpcsec_gsserr_ctxproblem 14 + +static void +add_supplementary_groups(char *secname, char *name, struct svc_cred *cred) +{ + int ret; + static gid_t *groups = NULL; + + cred->cr_ngroups = NGROUPS; + ret = nfs4_gss_princ_to_grouplist(secname, name, + cred->cr_groups, &cred->cr_ngroups); + if (ret < 0) { + groups = realloc(groups, cred->cr_ngroups*sizeof(gid_t)); + ret = nfs4_gss_princ_to_grouplist(secname, name, + groups, &cred->cr_ngroups); + if (ret < 0) + cred->cr_ngroups = 0; + else { + if (cred->cr_ngroups > NGROUPS) + cred->cr_ngroups = NGROUPS; + memcpy(cred->cr_groups, groups, + cred->cr_ngroups*sizeof(gid_t)); + } + } +} + +static int +get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; + char *sname; + int res = -1; + uid_t uid, gid; + gss_OID name_type = GSS_C_NO_OID; + char *secname; + + maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("get_ids: gss_display_name", + maj_stat, min_stat, mech); + goto out; + } + if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */ + !(sname = calloc(name.length + 1, 1))) { + printerr(0, "WARNING: get_ids: error allocating %d bytes " + "for sname\n", name.length + 1); + gss_release_buffer(&min_stat, &name); + goto out; + } + memcpy(sname, name.value, name.length); + printerr(1, "sname = %s\n", sname); + gss_release_buffer(&min_stat, &name); + + res = -EINVAL; + if ((secname = mech2file(mech)) == NULL) { + printerr(0, "WARNING: get_ids: error mapping mech to " + "file for name '%s'\n", sname); + goto out_free; + } + + res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid); + if (res < 0) { + /* + * -ENOENT means there was no mapping, any other error + * value means there was an error trying to do the + * mapping. + * If there was no mapping, we send down the value -1 + * to indicate that the anonuid/anongid for the export + * should be used. + */ + if (res == -ENOENT) { + cred->cr_uid = -1; + cred->cr_gid = -1; + cred->cr_ngroups = 0; + res = 0; + goto out_free; + } + printerr(1, "WARNING: get_ids: failed to map name '%s' " + "to uid/gid: %s\n", sname, strerror(-res)); + goto out_free; + } + cred->cr_uid = uid; + cred->cr_gid = gid; + add_supplementary_groups(secname, sname, cred); + res = 0; +out_free: + free(sname); +out: + return res; +} + +#ifdef DEBUG +void +print_hexl(const char *description, unsigned char *cp, int length) +{ + int i, j, jm; + unsigned char c; + + printf("%s (length %d)\n", description, length); + + for (i = 0; i < length; i += 0x10) { + printf(" %04x: ", (u_int)i); + jm = length - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + if ((j % 2) == 1) + printf("%02x ", (u_int)cp[i+j]); + else + printf("%02x", (u_int)cp[i+j]); + } + for (; j < 16; j++) { + if ((j % 2) == 1) + printf(" "); + else + printf(" "); + } + printf(" "); + + for (j = 0; j < jm; j++) { + c = cp[i+j]; + c = isprint(c) ? c : '.'; + printf("%c", c); + } + printf("\n"); + } +} +#endif + +void +handle_nullreq(char *cp) { + /* XXX initialize to a random integer to reduce chances of unnecessary + * invalidation of existing ctx's on restarting svcgssd. */ + static u_int32_t handle_seq = 0; + char in_tok_buf[TOKEN_BUF_SIZE]; + char in_handle_buf[15]; + char out_handle_buf[15]; + gss_buffer_desc in_tok = {.value = in_tok_buf}, + out_tok = {.value = NULL}, + in_handle = {.value = in_handle_buf}, + out_handle = {.value = out_handle_buf}, + ctx_token = {.value = NULL}, + ignore_out_tok = {.value = NULL}, + /* XXX isn't there a define for this?: */ + null_token = {.value = NULL}; + u_int32_t ret_flags; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_name_t client_name = NULL; + gss_OID mech = GSS_C_NO_OID; + u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; + u_int32_t ignore_min_stat; + struct svc_cred cred; + int32_t ctx_endtime; + char *hostbased_name = NULL; + + printerr(1, "handling null request\n"); + + in_handle.length = (size_t) qword_get(&cp, in_handle.value, + sizeof(in_handle_buf)); +#ifdef DEBUG + print_hexl("in_handle", in_handle.value, in_handle.length); +#endif + + in_tok.length = (size_t) qword_get(&cp, in_tok.value, + sizeof(in_tok_buf)); +#ifdef DEBUG + print_hexl("in_tok", in_tok.value, in_tok.length); +#endif + + if (in_handle.length != 0) { /* CONTINUE_INIT case */ + if (in_handle.length != sizeof(ctx)) { + printerr(0, "WARNING: handle_nullreq: " + "input handle has unexpected length %d\n", + in_handle.length); + goto out_err; + } + /* in_handle is the context id stored in the out_handle + * for the GSS_S_CONTINUE_NEEDED case below. */ + memcpy(&ctx, in_handle.value, in_handle.length); + } + + if (svcgssd_limit_krb5_enctypes()) { + goto out_err; + } + + maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds, + &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, + &mech, &out_tok, &ret_flags, NULL, NULL); + + if (maj_stat == GSS_S_CONTINUE_NEEDED) { + printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n"); + + /* Save the context handle for future calls */ + out_handle.length = sizeof(ctx); + memcpy(out_handle.value, &ctx, sizeof(ctx)); + goto continue_needed; + } + else if (maj_stat != GSS_S_COMPLETE) { + printerr(1, "WARNING: gss_accept_sec_context failed\n"); + pgsserr("handle_nullreq: gss_accept_sec_context", + maj_stat, min_stat, mech); + goto out_err; + } + if (get_ids(client_name, mech, &cred)) { + /* get_ids() prints error msg */ + maj_stat = GSS_S_BAD_NAME; /* XXX ? */ + goto out_err; + } + if (get_hostbased_client_name(client_name, mech, &hostbased_name)) { + /* get_hostbased_client_name() prints error msg */ + maj_stat = GSS_S_BAD_NAME; /* XXX ? */ + goto out_err; + } + + /* Context complete. Pass handle_seq in out_handle to use + * for context lookup in the kernel. */ + handle_seq++; + out_handle.length = sizeof(handle_seq); + memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); + + /* kernel needs ctx to calculate verifier on null response, so + * must give it context before doing null call: */ + if (serialize_context_for_kernel(&ctx, &ctx_token, mech, &ctx_endtime)) { + printerr(0, "WARNING: handle_nullreq: " + "serialize_context_for_kernel failed\n"); + maj_stat = GSS_S_FAILURE; + goto out_err; + } + /* We no longer need the gss context */ + gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); + + do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime, + hostbased_name); +continue_needed: + send_response(&in_handle, &in_tok, maj_stat, min_stat, + &out_handle, &out_tok); +out: + if (ctx_token.value != NULL) + free(ctx_token.value); + if (out_tok.value != NULL) + gss_release_buffer(&ignore_min_stat, &out_tok); + if (client_name) + gss_release_name(&ignore_min_stat, &client_name); + free(hostbased_name); + printerr(1, "finished handling null request\n"); + return; + +out_err: + if (ctx != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); + send_response(&in_handle, &in_tok, maj_stat, min_stat, + &null_token, &null_token); + goto out; +} diff --git a/utils/gssd/write_bytes.h b/utils/gssd/write_bytes.h new file mode 100644 index 0000000..b3f342b --- /dev/null +++ b/utils/gssd/write_bytes.h @@ -0,0 +1,159 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + 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 University 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 ``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 REGENTS 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 _WRITE_BYTES_H_ +#define _WRITE_BYTES_H_ + +#include +#include +#include +#include /* for ntohl */ + +inline static int +write_bytes(char **ptr, const char *end, const void *arg, int arg_len) +{ + char *p = *ptr, *arg_end; + + arg_end = p + arg_len; + if (arg_end > end || arg_end < p) + return -1; + memcpy(p, arg, arg_len); + *ptr = arg_end; + return 0; +} + +#define WRITE_BYTES(p, end, arg) write_bytes(p, end, &arg, sizeof(arg)) + +inline static int +write_buffer(char **p, char *end, gss_buffer_desc *arg) +{ + int len = (int)arg->length; /* make an int out of size_t */ + if (WRITE_BYTES(p, end, len)) + return -1; + if (*p + len > end) + return -1; + memcpy(*p, arg->value, len); + *p += len; + return 0; +} + +inline static int +write_oid(char **p, char *end, gss_OID_desc *arg) +{ + int len = (int)arg->length; /* make an int out of size_t */ + if (WRITE_BYTES(p, end, len)) + return -1; + if (*p + arg->length > end) + return -1; + memcpy(*p, arg->elements, len); + *p += len; + return 0; +} + +static inline int +get_bytes(char **ptr, const char *end, void *res, int len) +{ + char *p, *q; + p = *ptr; + q = p + len; + if (q > end || q < p) + return -1; + memcpy(res, p, len); + *ptr = q; + return 0; +} + +static inline int +get_buffer(char **ptr, const char *end, gss_buffer_desc *res) +{ + char *p, *q; + p = *ptr; + int len; + if (get_bytes(&p, end, &len, sizeof(len))) + return -1; + res->length = len; /* promote to size_t if necessary */ + q = p + res->length; + if (q > end || q < p) + return -1; + if (!(res->value = malloc(res->length))) + return -1; + memcpy(res->value, p, res->length); + *ptr = q; + return 0; +} + +static inline int +xdr_get_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t *res) +{ + if (get_bytes((char **)ptr, (char *)end, res, sizeof(res))) + return -1; + *res = ntohl(*res); + return 0; +} + +static inline int +xdr_get_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *res) +{ + u_int32_t *p, *q; + u_int32_t len; + p = *ptr; + if (xdr_get_u32(&p, end, &len)) + return -1; + res->length = len; + q = p + ((res->length + 3) >> 2); + if (q > end || q < p) + return -1; + if (!(res->value = malloc(res->length))) + return -1; + memcpy(res->value, p, res->length); + *ptr = q; + return 0; +} + +static inline int +xdr_write_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t arg) +{ + u_int32_t tmp; + + tmp = htonl(arg); + return WRITE_BYTES((char **)ptr, (char *)end, tmp); +} + +static inline int +xdr_write_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *arg) +{ + int len = arg->length; + if (xdr_write_u32(ptr, end, len)) + return -1; + return write_bytes((char **)ptr, (char *)end, arg->value, + (arg->length + 3) & ~3); +} + +#endif /* _WRITE_BYTES_H_ */ -- cgit v1.2.3