summaryrefslogtreecommitdiff
path: root/src/lib/gssapi
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
committerCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
commit33a9b234e7087f573ef08cd7318c6497ba08b439 (patch)
treed0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/lib/gssapi
Diffstat (limited to 'src/lib/gssapi')
-rw-r--r--src/lib/gssapi/LICENSE91
-rw-r--r--src/lib/gssapi/Makefile.in104
-rw-r--r--src/lib/gssapi/README_SAMPLE_APP4
-rw-r--r--src/lib/gssapi/deps1
-rw-r--r--src/lib/gssapi/generic/Makefile.in172
-rw-r--r--src/lib/gssapi/generic/deps96
-rw-r--r--src/lib/gssapi/generic/disp_com_err_status.c62
-rw-r--r--src/lib/gssapi/generic/disp_major_status.c301
-rw-r--r--src/lib/gssapi/generic/gssapi.hin920
-rw-r--r--src/lib/gssapi/generic/gssapiP_generic.h330
-rw-r--r--src/lib/gssapi/generic/gssapi_alloc.h128
-rw-r--r--src/lib/gssapi/generic/gssapi_err_generic.et49
-rw-r--r--src/lib/gssapi/generic/gssapi_ext.h578
-rw-r--r--src/lib/gssapi/generic/gssapi_generic.c450
-rw-r--r--src/lib/gssapi/generic/gssapi_generic.h59
-rw-r--r--src/lib/gssapi/generic/maptest.c68
-rw-r--r--src/lib/gssapi/generic/oid_ops.c553
-rw-r--r--src/lib/gssapi/generic/rel_buffer.c57
-rw-r--r--src/lib/gssapi/generic/rel_oid_set.c61
-rw-r--r--src/lib/gssapi/generic/t_seqstate.c197
-rw-r--r--src/lib/gssapi/generic/util_buffer.c48
-rw-r--r--src/lib/gssapi/generic/util_buffer_set.c126
-rw-r--r--src/lib/gssapi/generic/util_errmap.c264
-rw-r--r--src/lib/gssapi/generic/util_seqstate.c163
-rw-r--r--src/lib/gssapi/generic/util_set.c106
-rw-r--r--src/lib/gssapi/generic/util_token.c229
-rw-r--r--src/lib/gssapi/krb5/Makefile.in259
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c1347
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c1261
-rw-r--r--src/lib/gssapi/krb5/canon_name.c44
-rw-r--r--src/lib/gssapi/krb5/compare_name.c52
-rw-r--r--src/lib/gssapi/krb5/context_time.c63
-rw-r--r--src/lib/gssapi/krb5/copy_ccache.c60
-rw-r--r--src/lib/gssapi/krb5/cred_store.c50
-rw-r--r--src/lib/gssapi/krb5/delete_sec_context.c99
-rw-r--r--src/lib/gssapi/krb5/deps756
-rw-r--r--src/lib/gssapi/krb5/disp_name.c81
-rw-r--r--src/lib/gssapi/krb5/disp_status.c200
-rw-r--r--src/lib/gssapi/krb5/duplicate_name.c59
-rw-r--r--src/lib/gssapi/krb5/export_cred.c481
-rw-r--r--src/lib/gssapi/krb5/export_name.c88
-rw-r--r--src/lib/gssapi/krb5/export_sec_context.c101
-rw-r--r--src/lib/gssapi/krb5/get_tkt_flags.c45
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h1428
-rw-r--r--src/lib/gssapi/krb5/gssapi_err_krb5.et42
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c1159
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.h281
-rw-r--r--src/lib/gssapi/krb5/iakerb.c1329
-rw-r--r--src/lib/gssapi/krb5/import_cred.c648
-rw-r--r--src/lib/gssapi/krb5/import_name.c332
-rw-r--r--src/lib/gssapi/krb5/import_sec_context.c118
-rw-r--r--src/lib/gssapi/krb5/indicate_mechs.c37
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c1104
-rw-r--r--src/lib/gssapi/krb5/inq_context.c312
-rw-r--r--src/lib/gssapi/krb5/inq_cred.c247
-rw-r--r--src/lib/gssapi/krb5/inq_names.c100
-rw-r--r--src/lib/gssapi/krb5/k5seal.c413
-rw-r--r--src/lib/gssapi/krb5/k5sealiov.c557
-rw-r--r--src/lib/gssapi/krb5/k5sealv3.c512
-rw-r--r--src/lib/gssapi/krb5/k5sealv3iov.c468
-rw-r--r--src/lib/gssapi/krb5/k5unseal.c588
-rw-r--r--src/lib/gssapi/krb5/k5unsealiov.c675
-rw-r--r--src/lib/gssapi/krb5/krb5_gss_glue.c445
-rw-r--r--src/lib/gssapi/krb5/lucid_context.c292
-rw-r--r--src/lib/gssapi/krb5/naming_exts.c684
-rw-r--r--src/lib/gssapi/krb5/prf.c139
-rw-r--r--src/lib/gssapi/krb5/process_context_token.c66
-rw-r--r--src/lib/gssapi/krb5/rel_cred.c101
-rw-r--r--src/lib/gssapi/krb5/rel_name.c47
-rw-r--r--src/lib/gssapi/krb5/rel_oid.c78
-rw-r--r--src/lib/gssapi/krb5/s4u_gss_glue.c308
-rw-r--r--src/lib/gssapi/krb5/ser_sctx.c798
-rw-r--r--src/lib/gssapi/krb5/set_allowable_enctypes.c123
-rw-r--r--src/lib/gssapi/krb5/set_ccache.c101
-rw-r--r--src/lib/gssapi/krb5/store_cred.c234
-rw-r--r--src/lib/gssapi/krb5/util_cksum.c295
-rw-r--r--src/lib/gssapi/krb5/util_crypt.c782
-rw-r--r--src/lib/gssapi/krb5/util_seed.c61
-rw-r--r--src/lib/gssapi/krb5/util_seqnum.c102
-rw-r--r--src/lib/gssapi/krb5/val_cred.c83
-rw-r--r--src/lib/gssapi/krb5/wrap_size_limit.c178
-rw-r--r--src/lib/gssapi/libgssapi_krb5.exports162
-rw-r--r--src/lib/gssapi/mechglue/Makefile.in224
-rw-r--r--src/lib/gssapi/mechglue/deps510
-rw-r--r--src/lib/gssapi/mechglue/g_accept_sec_context.c399
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred.c565
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c529
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c524
-rw-r--r--src/lib/gssapi/mechglue/g_authorize_localname.c227
-rw-r--r--src/lib/gssapi/mechglue/g_buffer_set.c55
-rw-r--r--src/lib/gssapi/mechglue/g_canon_name.c176
-rw-r--r--src/lib/gssapi/mechglue/g_compare_name.c210
-rw-r--r--src/lib/gssapi/mechglue/g_complete_auth_token.c70
-rw-r--r--src/lib/gssapi/mechglue/g_context_time.c79
-rw-r--r--src/lib/gssapi/mechglue/g_decapsulate_token.c66
-rw-r--r--src/lib/gssapi/mechglue/g_del_name_attr.c66
-rw-r--r--src/lib/gssapi/mechglue/g_delete_sec_context.c104
-rw-r--r--src/lib/gssapi/mechglue/g_dsp_name.c118
-rw-r--r--src/lib/gssapi/mechglue/g_dsp_name_ext.c133
-rw-r--r--src/lib/gssapi/mechglue/g_dsp_status.c363
-rw-r--r--src/lib/gssapi/mechglue/g_dup_name.c144
-rw-r--r--src/lib/gssapi/mechglue/g_encapsulate_token.c65
-rw-r--r--src/lib/gssapi/mechglue/g_exp_sec_context.c144
-rw-r--r--src/lib/gssapi/mechglue/g_export_cred.c114
-rw-r--r--src/lib/gssapi/mechglue/g_export_name.c58
-rw-r--r--src/lib/gssapi/mechglue/g_export_name_comp.c72
-rw-r--r--src/lib/gssapi/mechglue/g_get_name_attr.c93
-rw-r--r--src/lib/gssapi/mechglue/g_glue.c752
-rw-r--r--src/lib/gssapi/mechglue/g_imp_cred.c177
-rw-r--r--src/lib/gssapi/mechglue/g_imp_name.c387
-rw-r--r--src/lib/gssapi/mechglue/g_imp_sec_context.c175
-rw-r--r--src/lib/gssapi/mechglue/g_init_sec_context.c254
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c1615
-rw-r--r--src/lib/gssapi/mechglue/g_inq_context.c168
-rw-r--r--src/lib/gssapi/mechglue/g_inq_context_oid.c68
-rw-r--r--src/lib/gssapi/mechglue/g_inq_cred.c233
-rw-r--r--src/lib/gssapi/mechglue/g_inq_cred_oid.c133
-rw-r--r--src/lib/gssapi/mechglue/g_inq_name.c97
-rw-r--r--src/lib/gssapi/mechglue/g_inq_names.c168
-rw-r--r--src/lib/gssapi/mechglue/g_map_name_to_any.c76
-rw-r--r--src/lib/gssapi/mechglue/g_mech_invoke.c72
-rw-r--r--src/lib/gssapi/mechglue/g_mechattr.c222
-rw-r--r--src/lib/gssapi/mechglue/g_mechname.c116
-rw-r--r--src/lib/gssapi/mechglue/g_oid_ops.c112
-rw-r--r--src/lib/gssapi/mechglue/g_prf.c81
-rw-r--r--src/lib/gssapi/mechglue/g_process_context.c82
-rw-r--r--src/lib/gssapi/mechglue/g_rel_buffer.c58
-rw-r--r--src/lib/gssapi/mechglue/g_rel_cred.c99
-rw-r--r--src/lib/gssapi/mechglue/g_rel_name.c86
-rw-r--r--src/lib/gssapi/mechglue/g_rel_name_mapping.c74
-rw-r--r--src/lib/gssapi/mechglue/g_rel_oid_set.c43
-rw-r--r--src/lib/gssapi/mechglue/g_saslname.c220
-rw-r--r--src/lib/gssapi/mechglue/g_seal.c249
-rw-r--r--src/lib/gssapi/mechglue/g_set_context_option.c107
-rw-r--r--src/lib/gssapi/mechglue/g_set_cred_option.c198
-rw-r--r--src/lib/gssapi/mechglue/g_set_name_attr.c70
-rw-r--r--src/lib/gssapi/mechglue/g_set_neg_mechs.c73
-rw-r--r--src/lib/gssapi/mechglue/g_sign.c134
-rw-r--r--src/lib/gssapi/mechglue/g_store_cred.c266
-rw-r--r--src/lib/gssapi/mechglue/g_unseal.c130
-rw-r--r--src/lib/gssapi/mechglue/g_unwrap_aead.c197
-rw-r--r--src/lib/gssapi/mechglue/g_unwrap_iov.c141
-rw-r--r--src/lib/gssapi/mechglue/g_verify.c106
-rw-r--r--src/lib/gssapi/mechglue/g_wrap_aead.c267
-rw-r--r--src/lib/gssapi/mechglue/g_wrap_iov.c261
-rw-r--r--src/lib/gssapi/mechglue/gssd_pname_to_uid.c226
-rw-r--r--src/lib/gssapi/mechglue/mechglue.h42
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h854
-rw-r--r--src/lib/gssapi/spnego/Makefile.in24
-rw-r--r--src/lib/gssapi/spnego/deps18
-rw-r--r--src/lib/gssapi/spnego/gssapiP_spnego.h664
-rw-r--r--src/lib/gssapi/spnego/mech_spnego.exports1
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c4355
153 files changed, 44751 insertions, 0 deletions
diff --git a/src/lib/gssapi/LICENSE b/src/lib/gssapi/LICENSE
new file mode 100644
index 000000000000..612f8ad6ef7b
--- /dev/null
+++ b/src/lib/gssapi/LICENSE
@@ -0,0 +1,91 @@
+[ NOTE: MIT has only incorporated the mechglue and spnego change, and
+not the incremental propagation changes. The filenames are different
+between the Sun and MIT sources. The actual MIT filenames appear in
+the top-level README file. Original text of Sun's LICENSE file
+follows. ]
+
+Subject to the license set forth below, Sun Microsystems, Inc. donates
+the attached files to MIT for the purpose of including these
+modifications and additions in future versions of the Kerberos system.
+
+Many of the files attached are subject to licenses issued by other
+entities, including OpenVision, MIT, and FundsXpress. See the
+individual files, and/or related Readme files, for these licenses.
+
+In addition Sun requires that the license set forth below be
+incorporated into any future version of the Kerberos system which
+contains portions of the files attached. The following files must be
+listed, in the top level Readme file, as being provided subject to such
+license:
+
+cmd/krb5/iprop/iprop.x
+cmd/krb5/iprop/iprop_hdr.h
+cmd/krb5/kadmin/server/ipropd_svc.c
+cmd/krb5/kproplog/kproplog.c
+cmd/krb5/slave/kpropd_rpc.c
+lib/gss_mechs/mech_krb5/et/kdb5_err.c
+lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h
+lib/gss_mechs/mech_spnego/mech/spnego_mech.c
+lib/krb5/kadm5/kadm_host_srv_names.c
+lib/krb5/kdb/kdb_convert.c
+lib/krb5/kdb/kdb_hdr.h
+lib/krb5/kdb/kdb_log.c
+lib/krb5/kdb/kdb_log.h
+lib/libgss/g_accept_sec_context.c
+lib/libgss/g_acquire_cred.c
+lib/libgss/g_canon_name.c
+lib/libgss/g_compare_name.c
+lib/libgss/g_context_time.c
+lib/libgss/g_delete_sec_context.c
+lib/libgss/g_dsp_name.c
+lib/libgss/g_dsp_status.c
+lib/libgss/g_dup_name.c
+lib/libgss/g_exp_sec_context.c
+lib/libgss/g_export_name.c
+lib/libgss/g_glue.c
+lib/libgss/g_imp_name.c
+lib/libgss/g_imp_sec_context.c
+lib/libgss/g_init_sec_context.c
+lib/libgss/g_initialize.c
+lib/libgss/g_inquire_context.c
+lib/libgss/g_inquire_cred.c
+lib/libgss/g_inquire_names.c
+lib/libgss/g_process_context.c
+lib/libgss/g_rel_buffer.c
+lib/libgss/g_rel_cred.c
+lib/libgss/g_rel_name.c
+lib/libgss/g_rel_oid_set.c
+lib/libgss/g_seal.c
+lib/libgss/g_sign.c
+lib/libgss/g_store_cred.c
+lib/libgss/g_unseal.c
+lib/libgss/g_userok.c
+lib/libgss/g_utils.c
+lib/libgss/g_verify.c
+lib/libgss/gssd_pname_to_uid.c
+uts/common/gssapi/include/gssapi_err_generic.h
+uts/common/gssapi/include/mechglueP.h
+
+Sun's License is as follows:
+
+Copyright (c) 2004 Sun Microsystems, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/src/lib/gssapi/Makefile.in b/src/lib/gssapi/Makefile.in
new file mode 100644
index 000000000000..1e8db4e9796e
--- /dev/null
+++ b/src/lib/gssapi/Makefile.in
@@ -0,0 +1,104 @@
+mydir=lib$(S)gssapi
+BUILDTOP=$(REL)..$(S)..
+SUBDIRS= generic krb5 spnego mechglue
+DEFINES=-D_GSS_STATIC_LINK=1
+
+##DOSLIBNAME=$(OUTPRE)gssapi.lib
+##DOSOBJFILELIST=@$(OUTPRE)mechglue.lst @$(OUTPRE)spnego.lst @$(OUTPRE)generic.lst @$(OUTPRE)krb5.lst # @$(OUTPRE)gssapi.lst
+##DOSOBJFILEDEP=$(OUTPRE)mechglue.lst $(OUTPRE)spnego.lst $(OUTPRE)generic.lst $(OUTPRE)krb5.lst # $(OUTPRE)gssapi.lst
+
+###DOSOBJFILE=$(OUTPRE)gssapi.lst
+##DOSLIBOBJS=$(OBJS)
+
+##DOS##DLL_EXP_TYPE=GSS
+
+LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5 -I$(srcdir)/mechglue
+STLIBOBJS=
+
+OBJS=
+SRCS=
+
+LIBBASE=gssapi_krb5
+LIBMAJOR=2
+LIBMINOR=2
+#LIBINITFUNC=gssint_lib_init
+#LIBFINIFUNC=gssint_lib_fini
+STOBJLISTS=OBJS.ST generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST spnego/OBJS.ST
+SUBDIROBJLISTS=generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST spnego/OBJS.ST
+SHLIB_EXPDEPS=\
+ $(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
+RELDIR=gssapi
+
+all-unix: all-liblinks @MAINT@ verify-calling-conventions-gssapi
+
+install-unix: install-libs
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs clean-misc-unix
+
+clean-windows::
+ $(RM) gssapi.lib gssapi.bak
+
+clean-misc-unix: clean-recurse
+ $(RM) merged-gssapi-header.h
+ $(RM) -r $(EHDRDIR)
+
+EHDRDIR=$(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS= \
+ $(EHDRDIR)$(S)gssapi_krb5.h \
+ $(EHDRDIR)$(S)gssapi_generic.h \
+ $(EHDRDIR)$(S)gssapi.h \
+ $(EHDRDIR)$(S)gssapi_alloc.h \
+ $(EHDRDIR)$(S)gssapi_ext.h
+merged-gssapi-header.h: $(EXPORTED_HEADERS)
+ cat $(EXPORTED_HEADERS) > merged.tmp
+ $(MV) merged.tmp merged-gssapi-header.h
+verify-calling-conventions-gssapi: merged-gssapi-header.h
+ $(PERL) -w $(top_srcdir)/util/def-check.pl merged-gssapi-header.h $(srcdir)/../gssapi32.def
+
+# These rules are an attempt to handle several different problems:
+#
+# Certain files in subdirectories must be made current by the
+# recursion step before we can build files in this directory that
+# depend on them. Existing but out-of-date versions must not be used.
+#
+# In a parallel make, nothing should be built more than once. This
+# effect can be exaggerated for testing by sticking "sleep 5" into the
+# rules for generating the files in subdirectories. For example, in
+# between testing for a directory and creating it -- do you then get
+# mkdir complaining that the directory exists? Adding the sleep
+# command may also exaggerate the build-with-outdated-headers problem,
+# by causing the timestamp on the newly generated header to be several
+# seconds newer than object files built with its old version, even on
+# fast machines where the UNIX filesystem's one-second granularity
+# would mask the problem.
+#
+# We must not cause these files to always be considered newly updated
+# when it comes time to build the object files in this directory.
+# Otherwise, we wind up recompiling some files every time we run make.
+
+# This set of rules fails the parallel make case; it can build
+# gssapi-include and all-recurse at the same time, and both will
+# create include/gssapi and gssapi.h.
+#$(BUILDTOP)/include/gssapi/gssapi.h: generic/gssapi.h
+# (cd generic && $(MAKE) gssapi-include)
+#generic/gssapi.h: generic/gssapi.hin
+# (cd generic && $(MAKE) gssapi.h)
+#generic/gssapi_err_generic.h: generic/gssapi_err_generic.et
+# (cd generic && $(MAKE) gssapi_err_generic.h)
+#krb5/gssapi_err_krb5.h: krb5/gssapi_err_krb5.et
+# (cd krb5 && $(MAKE) gssapi_err_krb5.h)
+
+# This version, without the no-op command to run, reportedly caused
+# repeated rebuilds in certain cases. With the no-op command, it
+# appears to be properly serializing the subdir processing and local
+# compiles... so far.
+##DOS##!if 0
+$(EXPORTED_HEADERS) generic/gssapi.h krb5/gssapi_err_krb5.h generic/gssapi_err_generic.h krb5/gssapi_krb5.h: all-recurse
+ : $@ updated by recursion rule
+##DOS##!endif
+
+
+@lib_frag@
+@libobj_frag@
+
diff --git a/src/lib/gssapi/README_SAMPLE_APP b/src/lib/gssapi/README_SAMPLE_APP
new file mode 100644
index 000000000000..c26bb09adebf
--- /dev/null
+++ b/src/lib/gssapi/README_SAMPLE_APP
@@ -0,0 +1,4 @@
+A sample GSS-API client and server application can be found in the
+directory ./appl/gss-sample in this distribution. Read the file
+./appl/gss-sample/README for information on how it works and how to
+build it.
diff --git a/src/lib/gssapi/deps b/src/lib/gssapi/deps
new file mode 100644
index 000000000000..2feac3c9d388
--- /dev/null
+++ b/src/lib/gssapi/deps
@@ -0,0 +1 @@
+# No dependencies here.
diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in
new file mode 100644
index 000000000000..a9e894899d1a
--- /dev/null
+++ b/src/lib/gssapi/generic/Makefile.in
@@ -0,0 +1,172 @@
+mydir=lib$(S)gssapi$(S)generic
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=generic
+##DOS##OBJFILE=..\$(OUTPRE)generic.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+ETSRCS= gssapi_err_generic.c
+ETOBJS= $(OUTPRE)gssapi_err_generic.$(OBJEXT)
+ETHDRS= gssapi_err_generic.h
+
+EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
+
+HDRS= $(EHDRDIR)$(S)gssapi.h \
+ $(EHDRDIR)$(S)gssapi_generic.h \
+ $(EHDRDIR)$(S)gssapi_alloc.h \
+ $(EHDRDIR)$(S)gssapi_ext.h
+
+MK_EHDRDIR=if test -d $(EHDRDIR); then :; else (set -x; mkdir $(EHDRDIR)); fi
+##DOS##MK_EHDRDIR=rem
+
+gssapi-include: $(EHDRDIR)$(S)gssapi.h
+
+$(EHDRDIR)$(S)gssapi.h: $(EHDRDIR)$(S)timestamp gssapi.h
+ $(CP) gssapi.h $@
+$(EHDRDIR)$(S)gssapi_generic.h: $(EHDRDIR)$(S)timestamp $(srcdir)$(S)gssapi_generic.h
+ $(CP) $(srcdir)$(S)gssapi_generic.h $@
+$(EHDRDIR)$(S)gssapi_alloc.h: $(EHDRDIR)$(S)timestamp $(srcdir)$(S)gssapi_alloc.h
+ $(CP) $(srcdir)$(S)gssapi_alloc.h $@
+$(EHDRDIR)$(S)gssapi_ext.h: $(EHDRDIR)$(S)timestamp $(srcdir)$(S)gssapi_ext.h
+ $(CP) $(srcdir)$(S)gssapi_ext.h $@
+
+$(EHDRDIR)$(S)timestamp:
+ $(MK_EHDRDIR)
+ echo timestamp > $(EHDRDIR)$(S)timestamp
+
+$(OUTPRE)gssapi_err_generic.$(OBJEXT): gssapi_err_generic.c
+gssapi_err_generic.h: gssapi_err_generic.et
+gssapi_err_generic.c: gssapi_err_generic.et
+
+##DOS##!if 0
+include_xom=@include_xom@
+##DOS##include_xom=rem
+gssapi.h: gssapi.hin
+ @echo "Creating gssapi.h" ; \
+ h=gss$$$$; $(RM) $$h; \
+ (echo "/* This is the gssapi.h prologue. */"; \
+ $(include_xom) && \
+ echo "/* End of gssapi.h prologue. */"&& \
+ cat $(srcdir)/gssapi.hin )> $$h && \
+ (set -x; $(MV) $$h $@) ; e=$$?; $(RM) $$h; exit $$e
+##DOS##!endif
+##DOS##gssapi.h: gssapi.hin
+##DOS## $(CP) $** $@
+
+SRCS = \
+ $(srcdir)/disp_com_err_status.c \
+ $(srcdir)/disp_major_status.c \
+ $(srcdir)/gssapi_generic.c \
+ $(srcdir)/oid_ops.c \
+ $(srcdir)/rel_buffer.c \
+ $(srcdir)/rel_oid_set.c \
+ $(srcdir)/util_buffer.c \
+ $(srcdir)/util_buffer_set.c \
+ $(srcdir)/util_errmap.c \
+ $(srcdir)/util_set.c \
+ $(srcdir)/util_seqstate.c \
+ $(srcdir)/util_token.c \
+ gssapi_err_generic.c
+
+EXTRADEPSRCS = t_seqstate.c
+
+OBJS = \
+ $(OUTPRE)disp_com_err_status.$(OBJEXT) \
+ $(OUTPRE)disp_major_status.$(OBJEXT) \
+ $(OUTPRE)gssapi_generic.$(OBJEXT) \
+ $(OUTPRE)oid_ops.$(OBJEXT) \
+ $(OUTPRE)rel_buffer.$(OBJEXT) \
+ $(OUTPRE)rel_oid_set.$(OBJEXT) \
+ $(OUTPRE)util_buffer.$(OBJEXT) \
+ $(OUTPRE)util_buffer_set.$(OBJEXT) \
+ $(OUTPRE)util_errmap.$(OBJEXT) \
+ $(OUTPRE)util_set.$(OBJEXT) \
+ $(OUTPRE)util_seqstate.$(OBJEXT) \
+ $(OUTPRE)util_token.$(OBJEXT) \
+ $(OUTPRE)gssapi_err_generic.$(OBJEXT)
+
+STLIBOBJS = \
+ disp_com_err_status.o \
+ disp_major_status.o \
+ gssapi_generic.o \
+ oid_ops.o \
+ rel_buffer.o \
+ rel_oid_set.o \
+ util_buffer.o \
+ util_buffer_set.o \
+ util_errmap.o \
+ util_set.o \
+ util_seqstate.o \
+ util_token.o \
+ gssapi_err_generic.o
+
+EXPORTED_HEADERS= gssapi_generic.h gssapi_ext.h
+EXPORTED_BUILT_HEADERS= gssapi.h
+
+$(OBJS): $(EXPORTED_HEADERS) $(ETHDRS)
+
+all-unix: $(EXPORTED_HEADERS) $(ETHDRS) $(HDRS)
+all-unix: all-libobjs
+
+errmap.h: $(top_srcdir)/util/gen.pl $(top_srcdir)/util/t_array.pm \
+ $(top_srcdir)/util/t_bimap.pm
+ $(PERL) -w -I$(top_srcdir)/util $(top_srcdir)/util/gen.pl bimap \
+ errmap.h \
+ NAME=mecherrmap LEFT=OM_uint32 RIGHT="struct mecherror" \
+ LEFTPRINT=print_OM_uint32 RIGHTPRINT=mecherror_print \
+ LEFTCMP=cmp_OM_uint32 RIGHTCMP=mecherror_cmp
+
+maptest.h: $(top_srcdir)/util/gen.pl $(top_srcdir)/util/t_array.pm \
+ $(top_srcdir)/util/t_bimap.pm
+ $(PERL) -w -I$(top_srcdir)/util $(top_srcdir)/util/gen.pl bimap \
+ maptest.h \
+ NAME=foo LEFT=int RIGHT=elt LEFTPRINT=intprt \
+ RIGHTPRINT=eltprt LEFTCMP=intcmp RIGHTCMP=eltcmp
+maptest.o: maptest.c maptest.h
+maptest: maptest.o
+ $(CC_LINK) -o maptest maptest.o
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-windows: win-create-ehdrdir
+all-windows: $(HDRS)
+
+win-create-ehdrdir:
+ if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR)
+
+clean-unix:: clean-libobjs
+ $(RM) $(ETHDRS) $(ETSRCS) $(HDRS) $(EXPORTED_BUILT_HEADERS) \
+ $(EHDRDIR)$(S)timestamp errmap.h maptest.h
+ $(RM) t_seqstate.o t_seqstate
+
+clean-windows::
+ $(RM) $(HDRS) maptest.h
+ -if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+t_seqstate: t_seqstate.o util_seqstate.o $(SUPPORT_DEPLIB)
+ $(CC_LINK) $(ALL_CFLAGS) -o $@ t_seqstate.o util_seqstate.o \
+ $(SUPPORT_LIB)
+
+check-unix: t_seqstate
+ $(RUN_TEST) ./t_seqstate
+
+generate-files-mac: gssapi.h errmap.h
+
+# Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5)
+install-headers-unix install: gssapi.h
+ @set -x; for f in $(EXPORTED_HEADERS) ; \
+ do $(INSTALL_DATA) $(srcdir)/$$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+ done
+ @set -x; for f in $(EXPORTED_BUILT_HEADERS) ; \
+ do $(INSTALL_DATA) $$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+ done
+
+depend: $(ETSRCS) $(ETHDRS) $(HDRS) errmap.h maptest.h
+
+@libobj_frag@
+
diff --git a/src/lib/gssapi/generic/deps b/src/lib/gssapi/generic/deps
new file mode 100644
index 000000000000..5b80e7f3876c
--- /dev/null
+++ b/src/lib/gssapi/generic/deps
@@ -0,0 +1,96 @@
+#
+# Generated makefile dependencies follow.
+#
+disp_com_err_status.so disp_com_err_status.po $(OUTPRE)disp_com_err_status.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h disp_com_err_status.c \
+ gssapiP_generic.h gssapi_err_generic.h gssapi_ext.h \
+ gssapi_generic.h
+disp_major_status.so disp_major_status.po $(OUTPRE)disp_major_status.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h disp_major_status.c \
+ gssapiP_generic.h gssapi_err_generic.h gssapi_ext.h \
+ gssapi_generic.h
+gssapi_generic.so gssapi_generic.po $(OUTPRE)gssapi_generic.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.c \
+ gssapi_generic.h
+oid_ops.so oid_ops.po $(OUTPRE)oid_ops.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_generic.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ oid_ops.c
+rel_buffer.so rel_buffer.po $(OUTPRE)rel_buffer.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ rel_buffer.c
+rel_oid_set.so rel_oid_set.po $(OUTPRE)rel_oid_set.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ rel_oid_set.c
+util_buffer.so util_buffer.po $(OUTPRE)util_buffer.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ util_buffer.c
+util_buffer_set.so util_buffer_set.po $(OUTPRE)util_buffer_set.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ util_buffer_set.c
+util_errmap.so util_errmap.po $(OUTPRE)util_errmap.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/krb5.h \
+ errmap.h gssapiP_generic.h gssapi_err_generic.h gssapi_ext.h \
+ gssapi_generic.h util_errmap.c
+util_set.so util_set.po $(OUTPRE)util_set.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ util_set.c
+util_seqstate.so util_seqstate.po $(OUTPRE)util_seqstate.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ util_seqstate.c
+util_token.so util_token.po $(OUTPRE)util_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ util_token.c
+gssapi_err_generic.so gssapi_err_generic.po $(OUTPRE)gssapi_err_generic.$(OBJEXT): \
+ $(COM_ERR_DEPS) gssapi_err_generic.c
+t_seqstate.so t_seqstate.po $(OUTPRE)t_seqstate.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(COM_ERR_DEPS) \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h gssapiP_generic.h \
+ gssapi_err_generic.h gssapi_ext.h gssapi_generic.h \
+ t_seqstate.c
diff --git a/src/lib/gssapi/generic/disp_com_err_status.c b/src/lib/gssapi/generic/disp_com_err_status.c
new file mode 100644
index 000000000000..bc416107e74e
--- /dev/null
+++ b/src/lib/gssapi/generic/disp_com_err_status.c
@@ -0,0 +1,62 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+#include "com_err.h"
+
+/* XXXX internationalization!! */
+
+/**/
+
+static const char * const no_error = "No error";
+
+/**/
+
+/* if status_type == GSS_C_GSS_CODE, return up to three error messages,
+ for routine errors, call error, and status, in that order.
+ message_context == 0 : print the routine error
+ message_context == 1 : print the calling error
+ message_context > 2 : print supplementary info bit (message_context-2)
+ if status_type == GSS_C_MECH_CODE, return the output from error_message()
+*/
+
+OM_uint32
+g_display_com_err_status(OM_uint32 *minor_status, OM_uint32 status_value,
+ gss_buffer_t status_string)
+{
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if (! g_make_string_buffer(((status_value == 0)?no_error:
+ error_message(status_value)),
+ status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/generic/disp_major_status.c b/src/lib/gssapi/generic/disp_major_status.c
new file mode 100644
index 000000000000..848af8fa5526
--- /dev/null
+++ b/src/lib/gssapi/generic/disp_major_status.c
@@ -0,0 +1,301 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * $Id$
+ */
+
+/* This code has knowledge of the min and max errors of each type
+ within the gssapi major status */
+
+#define GSS_ERROR_STR(value, array, select, min, max, num) \
+ (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
+ _((array)[num(value)]))
+
+/**/
+
+static const char * const calling_error_string[] = {
+ NULL,
+ N_("A required input parameter could not be read"),
+ N_("A required input parameter could not be written"),
+ N_("A parameter was malformed"),
+};
+
+static const char * const calling_error = N_("calling error");
+
+#define GSS_CALLING_ERROR_STR(x) \
+ GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
+ GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
+ GSS_CALLING_ERROR_FIELD)
+
+/**/
+
+static const char * const routine_error_string[] = {
+ NULL,
+ N_("An unsupported mechanism was requested"),
+ N_("An invalid name was supplied"),
+ N_("A supplied name was of an unsupported type"),
+ N_("Incorrect channel bindings were supplied"),
+ N_("An invalid status code was supplied"),
+ N_("A token had an invalid signature"),
+ N_("No credentials were supplied"),
+ N_("No context has been established"),
+ N_("A token was invalid"),
+ N_("A credential was invalid"),
+ N_("The referenced credentials have expired"),
+ N_("The context has expired"),
+ N_("Miscellaneous failure"),
+ N_("The quality-of-protection requested could not be provided"),
+ N_("The operation is forbidden by the local security policy"),
+ N_("The operation or option is not available"),
+};
+
+static const char * const routine_error = N_("routine error");
+
+#define GSS_ROUTINE_ERROR_STR(x) \
+ GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
+ GSS_S_BAD_MECH, GSS_S_FAILURE, \
+ GSS_ROUTINE_ERROR_FIELD)
+
+/**/
+
+/* this becomes overly gross after about 4 strings */
+
+static const char * const sinfo_string[] = {
+ N_("The routine must be called again to complete its function"),
+ N_("The token was a duplicate of an earlier token"),
+ N_("The token's validity period has expired"),
+ N_("A later token has already been processed"),
+};
+
+static const char * const sinfo_code = N_("supplementary info code");
+
+#define LSBGET(x) ((((x)^((x)-1))+1)>>1)
+#define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
+
+#define GSS_SINFO_STR(x) \
+ ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
+ /**/NULL:sinfo_string[(x)])
+
+/**/
+
+static const char * const no_error = N_("No error");
+static const char * const unknown_error = N_("Unknown %s (field = %d)");
+
+/**/
+
+static int
+display_unknown(const char *kind, OM_uint32 value, gss_buffer_t buffer)
+{
+ char *str;
+
+ if (asprintf(&str, _(unknown_error), kind, value) < 0)
+ return(0);
+
+ buffer->length = strlen(str);
+ buffer->value = str;
+
+ return(1);
+}
+
+/* code should be set to the calling error field */
+
+static OM_uint32
+display_calling(OM_uint32 *minor_status, OM_uint32 code,
+ gss_buffer_t status_string)
+{
+ const char *str;
+
+ if ((str = GSS_CALLING_ERROR_STR(code))) {
+ if (! g_make_string_buffer(str, status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ if (! display_unknown(_(calling_error), GSS_CALLING_ERROR_FIELD(code),
+ status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+/* code should be set to the routine error field */
+
+static OM_uint32
+display_routine(OM_uint32 *minor_status, OM_uint32 code,
+ gss_buffer_t status_string)
+{
+ const char *str;
+
+ if ((str = GSS_ROUTINE_ERROR_STR(code))) {
+ if (! g_make_string_buffer(str, status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ if (! display_unknown(_(routine_error), GSS_ROUTINE_ERROR_FIELD(code),
+ status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+/* code should be set to the bit offset (log_2) of a supplementary info bit */
+
+static OM_uint32
+display_bit(OM_uint32 *minor_status, OM_uint32 code,
+ gss_buffer_t status_string)
+{
+ const char *str;
+
+ if ((str = GSS_SINFO_STR(code))) {
+ if (! g_make_string_buffer(str, status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ if (! display_unknown(_(sinfo_code), 1<<code, status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+/**/
+
+/* return error messages, for routine errors, call error, and status,
+ in that order.
+ message_context == 0 : print the routine error
+ message_context == 1 : print the calling error
+ message_context > 2 : print supplementary info bit (message_context-2)
+*/
+
+OM_uint32
+g_display_major_status(OM_uint32 *minor_status, OM_uint32 status_value,
+ OM_uint32 *message_context, gss_buffer_t status_string)
+{
+ OM_uint32 ret, tmp;
+ int bit;
+
+ /*** deal with no error at all specially */
+
+ if (status_value == 0) {
+ if (! g_make_string_buffer(no_error, status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ *message_context = 0;
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+
+ /*** do routine error */
+
+ if (*message_context == 0) {
+ if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
+ status_value -= tmp;
+ if ((ret = display_routine(minor_status, tmp, status_string)))
+ return(ret);
+ *minor_status = 0;
+ if (status_value) {
+ (*message_context)++;
+ return(GSS_S_COMPLETE);
+ } else {
+ *message_context = 0;
+ return(GSS_S_COMPLETE);
+ }
+ } else {
+ (*message_context)++;
+ }
+ } else {
+ status_value -= GSS_ROUTINE_ERROR(status_value);
+ }
+
+ /*** do calling error */
+
+ if (*message_context == 1) {
+ if ((tmp = GSS_CALLING_ERROR(status_value))) {
+ status_value -= tmp;
+ if ((ret = display_calling(minor_status, tmp, status_string)))
+ return(ret);
+ *minor_status = 0;
+ if (status_value) {
+ (*message_context)++;
+ return(GSS_S_COMPLETE);
+ } else {
+ *message_context = 0;
+ return(GSS_S_COMPLETE);
+ }
+ } else {
+ (*message_context)++;
+ }
+ } else {
+ status_value -= GSS_CALLING_ERROR(status_value);
+ }
+
+ /*** do sinfo bits (*message_context == 2 + number of bits done) */
+
+ tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
+ /* mask off the bits which have been done */
+ if (*message_context > 2) {
+ tmp &= ~LSBMASK(*message_context-3);
+ status_value &= ~LSBMASK(*message_context-3);
+ }
+
+ if (!tmp) {
+ /* bogon input - there should be something left */
+ *minor_status = (OM_uint32) G_BAD_MSG_CTX;
+ return(GSS_S_FAILURE);
+ }
+
+ /* compute the bit offset */
+ /*SUPPRESS 570*/
+ for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
+
+ /* print it */
+ if ((ret = display_bit(minor_status, bit, status_string)))
+ return(ret);
+
+ /* compute the new status_value/message_context */
+ status_value -= ((OM_uint32) 1)<<bit;
+
+ if (status_value) {
+ *message_context = bit+3;
+ return(GSS_S_COMPLETE);
+ } else {
+ *message_context = 0;
+ return(GSS_S_COMPLETE);
+ }
+}
diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin
new file mode 100644
index 000000000000..59cd93e09f92
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi.hin
@@ -0,0 +1,920 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#ifndef _GSSAPI_H_
+#define _GSSAPI_H_
+
+/*
+ * Determine platform-dependent configuration.
+ */
+
+#if defined(__MACH__) && defined(__APPLE__)
+# include <TargetConditionals.h>
+# if TARGET_RT_MAC_CFM
+# error "Use KfM 4.0 SDK headers for CFM compilation."
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if TARGET_OS_MAC
+# pragma pack(push,2)
+#endif
+
+#if defined(_MSDOS) || defined(_WIN32)
+#include <win-mac.h>
+#endif
+
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+
+#include <stdint.h>
+
+/*
+ * First, include stddef.h to get size_t defined.
+ */
+#include <stddef.h>
+
+/*
+ * POSIX says that sys/types.h is where size_t is defined.
+ */
+#include <sys/types.h>
+
+/*
+ * $Id$
+ */
+
+/*
+ * First, define the three platform-dependent pointer types.
+ */
+
+struct gss_name_struct;
+typedef struct gss_name_struct * gss_name_t;
+
+struct gss_cred_id_struct;
+typedef struct gss_cred_id_struct * gss_cred_id_t;
+
+struct gss_ctx_id_struct;
+typedef struct gss_ctx_id_struct * gss_ctx_id_t;
+
+/*
+ * The following type must be defined as the smallest natural unsigned integer
+ * supported by the platform that has at least 32 bits of precision.
+ */
+typedef uint32_t gss_uint32;
+typedef int32_t gss_int32;
+
+#ifdef OM_STRING
+/*
+ * We have included the xom.h header file. Use the definition for
+ * OM_object identifier.
+ */
+typedef OM_object_identifier gss_OID_desc, *gss_OID;
+#else /* OM_STRING */
+/*
+ * We can't use X/Open definitions, so roll our own.
+ */
+typedef gss_uint32 OM_uint32;
+
+typedef struct gss_OID_desc_struct {
+ OM_uint32 length;
+ void *elements;
+} gss_OID_desc, *gss_OID;
+#endif /* OM_STRING */
+
+typedef struct gss_OID_set_desc_struct {
+ size_t count;
+ gss_OID elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+typedef struct gss_buffer_desc_struct {
+ size_t length;
+ void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+ OM_uint32 initiator_addrtype;
+ gss_buffer_desc initiator_address;
+ OM_uint32 acceptor_addrtype;
+ gss_buffer_desc acceptor_address;
+ gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+/*
+ * For now, define a QOP-type as an OM_uint32 (pending resolution of ongoing
+ * discussions).
+ */
+typedef OM_uint32 gss_qop_t;
+typedef int gss_cred_usage_t;
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_SEQUENCE_FLAG 8
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+#define GSS_C_ANON_FLAG 64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG 256
+#define GSS_C_DELEG_POLICY_FLAG 32768
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * The constant definitions for channel-bindings address families
+ */
+#define GSS_C_AF_UNSPEC 0
+#define GSS_C_AF_LOCAL 1
+#define GSS_C_AF_INET 2
+#define GSS_C_AF_IMPLINK 3
+#define GSS_C_AF_PUP 4
+#define GSS_C_AF_CHAOS 5
+#define GSS_C_AF_NS 6
+#define GSS_C_AF_NBS 7
+#define GSS_C_AF_ECMA 8
+#define GSS_C_AF_DATAKIT 9
+#define GSS_C_AF_CCITT 10
+#define GSS_C_AF_SNA 11
+#define GSS_C_AF_DECnet 12
+#define GSS_C_AF_DLI 13
+#define GSS_C_AF_LAT 14
+#define GSS_C_AF_HYLINK 15
+#define GSS_C_AF_APPLETALK 16
+#define GSS_C_AF_BSC 17
+#define GSS_C_AF_DSS 18
+#define GSS_C_AF_OSI 19
+#define GSS_C_AF_NETBIOS 20
+#define GSS_C_AF_X25 21
+
+#define GSS_C_AF_NULLADDR 255
+
+/*
+ * Various Null values.
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above values. These are defined
+ * for V1 compatibility.
+ */
+#define GSS_C_NULL_OID GSS_C_NO_OID
+#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
+
+/*
+ * Define the default Quality of Protection for per-message services. Note
+ * that an implementation that offers multiple levels of QOP may either reserve
+ * a value (for example zero, as assumed here) to mean "default protection", or
+ * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit
+ * QOP value. However a value of 0 should always be interpreted by a GSSAPI
+ * implementation as a request for the default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)
+
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul)
+
+/*
+ * The macros that test status codes for error conditions. Note that the
+ * GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now
+ * evaluates its argument only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+ ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+ ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+ ((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+ ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+ (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+ (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+ (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+ (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MIC GSS_S_BAD_SIG
+#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL \
+ (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED \
+ (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED \
+ (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT \
+ (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN \
+ (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MECH_ATTR \
+ (((OM_uint32) 19ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+
+/*
+ * Finally, function prototypes for the GSSAPI routines.
+ */
+
+#if defined (_WIN32) && defined (_MSC_VER)
+# ifdef GSS_DLL_FILE
+# define GSS_DLLIMP __declspec(dllexport)
+# else
+# define GSS_DLLIMP __declspec(dllimport)
+# endif
+#else
+# define GSS_DLLIMP
+#endif
+
+/* Reserved static storage for GSS_oids. Comments are quotes from RFC 2744.
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_USER_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_STRING_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_ANONYMOUS;
+
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_EXPORT_NAME;
+
+/* Function Prototypes */
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_release_cred(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t *); /* cred_handle */
+
+OM_uint32 KRB5_CALLCONV
+gss_init_sec_context(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t *, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type (used to be const) */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID *, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_accept_sec_context(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_cred_id_t, /* acceptor_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_name_t *, /* src_name */
+ gss_OID *, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 *, /* time_rec */
+ gss_cred_id_t *); /* delegated_cred_handle */
+
+OM_uint32 KRB5_CALLCONV
+gss_process_context_token(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t); /* token_buffer */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_delete_sec_context(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t); /* output_token */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_context_time(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ OM_uint32 *); /* time_rec */
+
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_get_mic(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t); /* message_token */
+
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* message_token */
+ gss_qop_t * /* qop_state */
+);
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_wrap(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t); /* output_message_buffer */
+
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_unwrap(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ gss_qop_t *); /* qop_state */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_display_status(
+ OM_uint32 *, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type (used to be const) */
+ OM_uint32 *, /* message_context */
+ gss_buffer_t); /* status_string */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs(
+ OM_uint32 *, /* minor_status */
+ gss_OID_set *); /* mech_set */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_compare_name(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name1 */
+ gss_name_t, /* name2 */
+ int *); /* name_equal */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_display_name(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID *); /* output_name_type */
+
+
+OM_uint32 KRB5_CALLCONV
+gss_import_name(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type(used to be const) */
+ gss_name_t *); /* output_name */
+
+OM_uint32 KRB5_CALLCONV
+gss_release_name(
+ OM_uint32 *, /* minor_status */
+ gss_name_t *); /* input_name */
+
+OM_uint32 KRB5_CALLCONV
+gss_release_buffer(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t); /* buffer */
+
+OM_uint32 KRB5_CALLCONV
+gss_release_oid_set(
+ OM_uint32 *, /* minor_status */
+ gss_OID_set *); /* set */
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ gss_cred_usage_t *, /* cred_usage */
+ gss_OID_set *); /* mechanisms */
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_context(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_name_t *, /* src_name */
+ gss_name_t *, /* targ_name */
+ OM_uint32 *, /* lifetime_rec */
+ gss_OID *, /* mech_type */
+ OM_uint32 *, /* ctx_flags */
+ int *, /* locally_initiated */
+ int *); /* open */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_wrap_size_limit(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 *); /* max_input_size */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_import_name_object(
+ OM_uint32 *, /* minor_status */
+ void *, /* input_name */
+ gss_OID, /* input_name_type */
+ gss_name_t *); /* output_name */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_export_name_object(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_OID, /* desired_name_type */
+ void **); /* output_name */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_name_t, /* desired_name */
+ gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred_by_mech(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t *); /* cred_usage */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_export_sec_context(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t); /* interprocess_token */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_import_sec_context(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t *); /* context_handle */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_release_oid(
+ OM_uint32 *, /* minor_status */
+ gss_OID *); /* oid */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_create_empty_oid_set(
+ OM_uint32 *, /* minor_status */
+ gss_OID_set *); /* oid_set */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_add_oid_set_member(
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* member_oid */
+ gss_OID_set *); /* oid_set */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_test_oid_set_member(
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* member */
+ gss_OID_set, /* set */
+ int *); /* present */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_str_to_oid(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* oid_str */
+ gss_OID *); /* oid */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_oid_to_str(
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* oid */
+ gss_buffer_t); /* oid_str */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_names_for_mech(
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set *); /* name_types */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mechs_for_name(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_OID_set *); /* mech_types */
+
+/*
+ * The following routines are obsolete variants of gss_get_mic, gss_wrap,
+ * gss_verify_mic and gss_unwrap. They should be provided by GSSAPI V2
+ * implementations for backwards compatibility with V1 applications. Distinct
+ * entrypoints (as opposed to #defines) should be provided, to allow GSSAPI
+ * V1 applications to link against GSSAPI V2 implementations.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_sign(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t); /* message_token */
+
+OM_uint32 KRB5_CALLCONV
+gss_verify(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* token_buffer */
+ int *); /* qop_state */
+
+OM_uint32 KRB5_CALLCONV
+gss_seal(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ int, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t); /* output_message_buffer */
+
+OM_uint32 KRB5_CALLCONV
+gss_unseal(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ int *); /* qop_state */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_export_name(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t); /* exported_name */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_duplicate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_name_t *); /* dest_name */
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_canonicalize_name(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ const gss_OID, /* mech_type */
+ gss_name_t *); /* output_name */
+
+/* RFC 4401 */
+
+#define GSS_C_PRF_KEY_FULL 0
+#define GSS_C_PRF_KEY_PARTIAL 1
+
+OM_uint32 KRB5_CALLCONV
+gss_pseudo_random(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context */
+ int, /* prf_key */
+ const gss_buffer_t, /* prf_in */
+ ssize_t, /* desired_output_len */
+ gss_buffer_t); /* prf_out */
+
+OM_uint32 KRB5_CALLCONV
+gss_store_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t,/* input_cred_handle */
+ gss_cred_usage_t, /* input_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t *);/* cred_usage_stored */
+
+OM_uint32 KRB5_CALLCONV
+gss_set_neg_mechs(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ const gss_OID_set); /* mech_set */
+
+#if TARGET_OS_MAC
+# pragma pack(pop)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* XXXX these are not part of the GSSAPI C bindings! (but should be) */
+
+#define GSS_CALLING_ERROR_FIELD(x) \
+ (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
+#define GSS_ROUTINE_ERROR_FIELD(x) \
+ (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
+#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
+ (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
+
+/* XXXX This is a necessary evil until the spec is fixed */
+#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
+
+/*
+ * RFC 5587
+ */
+typedef const gss_buffer_desc *gss_const_buffer_t;
+typedef const struct gss_channel_bindings_struct *gss_const_channel_bindings_t;
+typedef const struct gss_ctx_id_struct *gss_const_ctx_id_t;
+typedef const struct gss_cred_id_struct *gss_const_cred_id_t;
+typedef const struct gss_name_struct *gss_const_name_t;
+typedef const gss_OID_desc *gss_const_OID;
+typedef const gss_OID_set_desc *gss_const_OID_set;
+
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs_by_attrs(
+ OM_uint32 *, /* minor_status */
+ gss_const_OID_set, /* desired_mech_attrs */
+ gss_const_OID_set, /* except_mech_attrs */
+ gss_const_OID_set, /* critical_mech_attrs */
+ gss_OID_set *); /* mechs */
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_attrs_for_mech(
+ OM_uint32 *, /* minor_status */
+ gss_const_OID, /* mech */
+ gss_OID_set *, /* mech_attrs */
+ gss_OID_set *); /* known_mech_attrs */
+
+OM_uint32 KRB5_CALLCONV
+gss_display_mech_attr(
+ OM_uint32 *, /* minor_status */
+ gss_const_OID, /* mech_attr */
+ gss_buffer_t, /* name */
+ gss_buffer_t, /* short_desc */
+ gss_buffer_t); /* long_desc */
+
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_CONCRETE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_PSEUDO;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_COMPOSITE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_NEGO;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_GLUE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_MECH;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_DEPRECATED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_DFLT_MECH;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_ITOK_FRAMED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_ANON;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_ANON;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_DELEG_CRED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_INTEG_PROT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CONF_PROT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MIC;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_WRAP;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_PROT_READY;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_REPLAY_DET;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_OOS_DET;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CBINDINGS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_PFS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_COMPRESS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CTX_TRANS;
+
+/*
+ * RFC 5801
+ */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_saslname_for_mech(
+ OM_uint32 *, /* minor_status */
+ const gss_OID, /* desired_mech */
+ gss_buffer_t, /* sasl_mech_name */
+ gss_buffer_t, /* mech_name */
+ gss_buffer_t /* mech_description */
+);
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mech_for_saslname(
+ OM_uint32 *, /* minor_status */
+ const gss_buffer_t, /* sasl_mech_name */
+ gss_OID * /* mech_type */
+);
+
+#endif /* _GSSAPI_H_ */
diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h
new file mode 100644
index 000000000000..686a21772db8
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapiP_generic.h
@@ -0,0 +1,330 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#ifndef _GSSAPIP_GENERIC_H_
+#define _GSSAPIP_GENERIC_H_
+
+/*
+ * $Id$
+ */
+
+#if defined(_WIN32)
+#include "k5-int.h"
+#else
+#include "autoconf.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#endif
+
+#include "k5-thread.h"
+
+#include "gssapi_generic.h"
+#include "gssapi_ext.h"
+#include <gssapi/gssapi_alloc.h>
+#include "gssapi_err_generic.h"
+#include <errno.h>
+
+#include "k5-platform.h"
+#include "k5-buf.h"
+
+/** helper macros **/
+
+#define g_OID_equal(o1, o2) \
+ (((o1)->length == (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0))
+
+/* this code knows that an int on the wire is 32 bits. The type of
+ num should be at least this big, or the extra shifts may do weird
+ things */
+
+#define TWRITE_INT(ptr, num, bigend) \
+ if (bigend) store_32_be(num, ptr); else store_32_le(num, ptr); \
+ (ptr) += 4;
+
+#define TWRITE_INT16(ptr, num, bigend) \
+ if (bigend) store_16_be((num)>>16, ptr); else store_16_le(num, ptr); \
+ (ptr) += 2;
+
+#define TREAD_INT(ptr, num, bigend) \
+ (num) = ((bigend) ? load_32_be(ptr) : load_32_le(ptr)); \
+ (ptr) += 4;
+
+#define TREAD_INT16(ptr, num, bigend) \
+ (num) = ((bigend) ? (load_16_be(ptr) << 16) : load_16_le(ptr)); \
+ (ptr) += 2;
+
+#define TWRITE_STR(ptr, str, len) \
+ memcpy((ptr), (str), (len)); \
+ (ptr) += (len);
+
+#define TREAD_STR(ptr, str, len) \
+ (str) = (ptr); \
+ (ptr) += (len);
+
+#define TWRITE_BUF(ptr, buf, bigend) \
+ TWRITE_INT((ptr), (buf).length, (bigend)); \
+ TWRITE_STR((ptr), (buf).value, (buf).length);
+
+/** malloc wrappers; these may actually do something later */
+
+#define xmalloc(n) malloc(n)
+#define xrealloc(p,n) realloc(p,n)
+#ifdef xfree
+#undef xfree
+#endif
+#define xfree(p) free(p)
+
+/** helper functions **/
+
+/* hide names from applications, especially glib applications */
+#define g_set_init gssint_g_set_init
+#define g_set_destroy gssint_g_set_destroy
+#define g_set_entry_add gssint_g_set_entry_add
+#define g_set_entry_delete gssint_g_set_entry_delete
+#define g_set_entry_get gssint_g_set_entry_get
+#define g_make_string_buffer gssint_g_make_string_buffer
+#define g_token_size gssint_g_token_size
+#define g_make_token_header gssint_g_make_token_header
+#define g_verify_token_header gssint_g_verify_token_header
+#define g_display_major_status gssint_g_display_major_status
+#define g_display_com_err_status gssint_g_display_com_err_status
+#define g_seqstate_init gssint_g_seqstate_init
+#define g_seqstate_check gssint_g_seqstate_check
+#define g_seqstate_free gssint_g_seqstate_free
+#define g_seqstate_size gssint_g_seqstate_size
+#define g_seqstate_externalize gssint_g_seqstate_externalize
+#define g_seqstate_internalize gssint_g_seqstate_internalize
+#define g_canonicalize_host gssint_g_canonicalize_host
+#define g_local_host_name gssint_g_local_host_name
+#define g_strdup gssint_g_strdup
+
+typedef struct _g_set_elt *g_set_elt;
+typedef struct {
+ k5_mutex_t mutex;
+ void *data;
+} g_set;
+#define G_SET_INIT { K5_MUTEX_PARTIAL_INITIALIZER, 0 }
+
+typedef struct g_seqnum_state_st *g_seqnum_state;
+
+int g_set_init (g_set_elt *s);
+int g_set_destroy (g_set_elt *s);
+int g_set_entry_add (g_set_elt *s, void *key, void *value);
+int g_set_entry_delete (g_set_elt *s, void *key);
+int g_set_entry_get (g_set_elt *s, void *key, void **value);
+
+int g_save_name (g_set *vdb, gss_name_t name);
+int g_save_cred_id (g_set *vdb, gss_cred_id_t cred);
+int g_save_ctx_id (g_set *vdb, gss_ctx_id_t ctx);
+int g_save_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_validate_name (g_set *vdb, gss_name_t name);
+int g_validate_cred_id (g_set *vdb, gss_cred_id_t cred);
+int g_validate_ctx_id (g_set *vdb, gss_ctx_id_t ctx);
+int g_validate_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_delete_name (g_set *vdb, gss_name_t name);
+int g_delete_cred_id (g_set *vdb, gss_cred_id_t cred);
+int g_delete_ctx_id (g_set *vdb, gss_ctx_id_t ctx);
+int g_delete_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_make_string_buffer (const char *str, gss_buffer_t buffer);
+
+unsigned int g_token_size (const gss_OID_desc * mech, unsigned int body_size);
+
+void g_make_token_header (const gss_OID_desc * mech, unsigned int body_size,
+ unsigned char **buf, int tok_type);
+
+/* flags for g_verify_token_header() */
+#define G_VFY_TOKEN_HDR_WRAPPER_REQUIRED 0x01
+
+gss_int32 g_verify_token_header (const gss_OID_desc * mech,
+ unsigned int *body_size,
+ unsigned char **buf, int tok_type,
+ unsigned int toksize_in,
+ int flags);
+
+OM_uint32 g_display_major_status (OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string);
+
+OM_uint32 g_display_com_err_status (OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ gss_buffer_t status_string);
+
+long g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum,
+ int do_replay, int do_sequence, int wide);
+OM_uint32 g_seqstate_check(g_seqnum_state state, uint64_t seqnum);
+void g_seqstate_free(g_seqnum_state state);
+void g_seqstate_size(g_seqnum_state state, size_t *sizep);
+long g_seqstate_externalize(g_seqnum_state state, unsigned char **buf,
+ size_t *lenremain);
+long g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf,
+ size_t *lenremain);
+
+char *g_strdup (char *str);
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32
+generic_gss_release_buffer(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t); /* buffer */
+
+OM_uint32
+generic_gss_release_oid_set(
+ OM_uint32 *, /* minor_status */
+ gss_OID_set *); /* set */
+
+OM_uint32
+generic_gss_release_oid(
+ OM_uint32 *, /* minor_status */
+ gss_OID *); /* set */
+
+OM_uint32
+generic_gss_copy_oid(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_desc * const, /* oid */
+ gss_OID *); /* new_oid */
+
+OM_uint32
+generic_gss_create_empty_oid_set(
+ OM_uint32 *, /* minor_status */
+ gss_OID_set *); /* oid_set */
+
+OM_uint32
+generic_gss_add_oid_set_member(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_desc * const, /* member_oid */
+ gss_OID_set *); /* oid_set */
+
+OM_uint32
+generic_gss_test_oid_set_member(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_desc * const, /* member */
+ gss_OID_set, /* set */
+ int *); /* present */
+
+OM_uint32
+generic_gss_oid_to_str(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_desc * const, /* oid */
+ gss_buffer_t); /* oid_str */
+
+OM_uint32
+generic_gss_str_to_oid(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* oid_str */
+ gss_OID *); /* oid */
+
+OM_uint32
+generic_gss_oid_compose(
+ OM_uint32 *, /* minor_status */
+ const char *, /* prefix */
+ size_t, /* prefix_len */
+ int, /* suffix */
+ gss_OID_desc *); /* oid */
+
+OM_uint32
+generic_gss_oid_decompose(
+ OM_uint32 *, /* minor_status */
+ const char *, /*prefix */
+ size_t, /* prefix_len */
+ gss_OID_desc *, /* oid */
+ int *); /* suffix */
+
+int gssint_mecherrmap_init(void);
+void gssint_mecherrmap_destroy(void);
+OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc *oid);
+int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid,
+ OM_uint32 *mech_minor);
+OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode);
+
+/*
+ * Transfer contents of a k5buf to a gss_buffer and invalidate the source
+ * On unix, this is a simple pointer copy
+ * On windows, memory is reallocated and copied.
+ */
+static inline OM_uint32
+k5buf_to_gss(OM_uint32 *minor,
+ struct k5buf *input_k5buf,
+ gss_buffer_t output_buffer)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+
+ if (k5_buf_status(input_k5buf) != 0) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ output_buffer->length = input_k5buf->len;
+#if defined(_WIN32) || defined(DEBUG_GSSALLOC)
+ if (output_buffer->length > 0) {
+ output_buffer->value = gssalloc_malloc(output_buffer->length);
+ if (output_buffer->value) {
+ memcpy(output_buffer->value, input_k5buf->data,
+ output_buffer->length);
+ } else {
+ status = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ }
+ } else {
+ output_buffer->value = NULL;
+ }
+ k5_buf_free(input_k5buf);
+#else
+ output_buffer->value = input_k5buf->data;
+ memset(input_k5buf, 0, sizeof(*input_k5buf));
+#endif
+ return status;
+}
+
+OM_uint32 generic_gss_create_empty_buffer_set
+(OM_uint32 * /*minor_status*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 generic_gss_add_buffer_set_member
+(OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*member_buffer*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 generic_gss_release_buffer_set
+(OM_uint32 * /*minor_status*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 generic_gss_copy_oid_set
+(OM_uint32 *, /* minor_status */
+ const gss_OID_set_desc * const /*oidset*/,
+ gss_OID_set * /*new_oidset*/);
+
+extern gss_OID_set gss_ma_known_attrs;
+
+OM_uint32 generic_gss_display_mech_attr(
+ OM_uint32 *minor_status,
+ gss_const_OID mech_attr,
+ gss_buffer_t name,
+ gss_buffer_t short_desc,
+ gss_buffer_t long_desc);
+
+#endif /* _GSSAPIP_GENERIC_H_ */
diff --git a/src/lib/gssapi/generic/gssapi_alloc.h b/src/lib/gssapi/generic/gssapi_alloc.h
new file mode 100644
index 000000000000..9a5cd9892c2c
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_alloc.h
@@ -0,0 +1,128 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* To the extent possible under law, Painless Security, LLC has waived
+ * all copyright and related or neighboring rights to GSS-API Memory
+ * Management Header. This work is published from: United States.
+ */
+
+#ifndef GSSAPI_ALLOC_H
+#define GSSAPI_ALLOC_H
+
+#ifdef _WIN32
+#include "winbase.h"
+#endif
+#include <string.h>
+
+#if defined(_WIN32)
+
+static inline void
+gssalloc_free(void *value)
+{
+ if (value)
+ HeapFree(GetProcessHeap(), 0, value);
+}
+
+static inline void *
+gssalloc_malloc(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, size);
+}
+
+static inline void *
+gssalloc_calloc(size_t count, size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * size);
+}
+
+static inline void *
+gssalloc_realloc(void *value, size_t size)
+{
+ return HeapReAlloc(GetProcessHeap(), 0, value, size);
+}
+
+#elif defined(DEBUG_GSSALLOC)
+
+/* Be deliberately incompatible with malloc and free, to allow us to detect
+ * mismatched malloc/gssalloc usage on Unix. */
+
+static inline void
+gssalloc_free(void *value)
+{
+ char *p = (char *)value - 8;
+
+ if (value == NULL)
+ return;
+ if (memcmp(p, "gssalloc", 8) != 0)
+ abort();
+ free(p);
+}
+
+static inline void *
+gssalloc_malloc(size_t size)
+{
+ char *p = calloc(size + 8, 1);
+
+ memcpy(p, "gssalloc", 8);
+ return p + 8;
+}
+
+static inline void *
+gssalloc_calloc(size_t count, size_t size)
+{
+ return gssalloc_malloc(count * size);
+}
+
+static inline void *
+gssalloc_realloc(void *value, size_t size)
+{
+ char *p = (char *)value - 8;
+
+ if (value == NULL)
+ return gssalloc_malloc(size);
+ if (memcmp(p, "gssalloc", 8) != 0)
+ abort();
+ return (char *)realloc(p, size) + 8;
+}
+
+#else /* not _WIN32 or DEBUG_GSSALLOC */
+
+/* Normal Unix case, just use free/malloc/calloc/realloc. */
+
+static inline void
+gssalloc_free(void *value)
+{
+ free(value);
+}
+
+static inline void *
+gssalloc_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void *
+gssalloc_calloc(size_t count, size_t size)
+{
+ return calloc(count, size);
+}
+
+static inline void *
+gssalloc_realloc(void *value, size_t size)
+{
+ return realloc(value, size);
+}
+
+#endif /* not _WIN32 or DEBUG_GSSALLOC */
+
+static inline char *
+gssalloc_strdup(const char *str)
+{
+ size_t size = strlen(str)+1;
+ char *copy = gssalloc_malloc(size);
+ if (copy) {
+ memcpy(copy, str, size);
+ copy[size-1] = '\0';
+ }
+ return copy;
+}
+
+#endif
diff --git a/src/lib/gssapi/generic/gssapi_err_generic.et b/src/lib/gssapi/generic/gssapi_err_generic.et
new file mode 100644
index 000000000000..3e976e3dbf50
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_err_generic.et
@@ -0,0 +1,49 @@
+#
+# Copyright 1993 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.
+#
+
+#
+# $Id$
+#
+
+error_table ggss
+
+error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string"
+error_code G_BAD_STRING_UID, "STRING-UID-NAME contains nondigits"
+error_code G_NOUSER, "UID does not resolve to username"
+error_code G_VALIDATE_FAILED, "Validation error"
+error_code G_BUFFER_ALLOC, "Couldn't allocate gss_buffer_t data"
+error_code G_BAD_MSG_CTX, "Message context invalid"
+error_code G_WRONG_SIZE, "Buffer is the wrong size"
+error_code G_BAD_USAGE, "Credential usage type is unknown"
+error_code G_UNKNOWN_QOP, "Unknown quality of protection specified"
+error_code G_NO_HOSTNAME, "Local host name could not be determined"
+error_code G_BAD_HOSTNAME, "Hostname in SERVICE-NAME string could not be canonicalized"
+error_code G_WRONG_MECH, "Mechanism is incorrect"
+error_code G_BAD_TOK_HEADER, "Token header is malformed or corrupt"
+error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction"
+error_code G_TOK_TRUNC, "Token is missing data"
+error_code G_REFLECT, "Token was reflected"
+error_code G_WRONG_TOKID, "Received token ID does not match expected token ID"
+error_code G_CRED_USAGE_MISMATCH, "The given credential's usage does not match the requested usage"
+error_code G_STORE_ACCEPTOR_CRED_NOSUPP, "Storing of acceptor credentials is not supported by the mechanism"
+error_code G_STORE_NON_DEFAULT_CRED_NOSUPP, "Storing of non-default credentials is not supported by the mechanism"
+end
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
new file mode 100644
index 000000000000..9ad44216d05e
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2008 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.
+ */
+
+#ifndef GSSAPI_EXT_H_
+#define GSSAPI_EXT_H_
+
+#include <gssapi/gssapi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Solaris extensions
+ */
+#ifndef _WIN32
+OM_uint32 KRB5_CALLCONV
+gss_pname_to_uid
+ (OM_uint32 *minor,
+ const gss_name_t name,
+ const gss_OID mech_type,
+ uid_t *uidOut);
+#endif
+
+/**
+ * Provides a platform-specific name for a GSSAPI name as interpreted by a
+ * given mechanism.
+ *
+ * @param [out] minor Minor status code
+ * @param [in] name The gss name resulting from accept_sec_context
+ * @param [in] mech_type The mechanism that will be asked to map @a name to a
+ * local name
+ * @param [out] localname Caller-allocated buffer to be filled in with the
+ * local name on success
+ */
+OM_uint32 KRB5_CALLCONV
+gss_localname
+ (OM_uint32 *minor,
+ const gss_name_t name,
+ gss_const_OID mech_type,
+ gss_buffer_t localname);
+
+/**
+ * Determine whether a mechanism name is authorized to act as a username.
+ *
+ * @param [in] name Mechanism name
+ * @param [in] username System username
+ *
+ * This is a simple wrapper around gss_authorize_localname(). It only supports
+ * system usernames as local names, and cannot distinguish between lack of
+ * authorization and other errors.
+ *
+ * @retval 1 @a name is authorized to act as @a username
+ * @retval 0 @a name is not authorized or an error occurred
+ */
+int KRB5_CALLCONV
+gss_userok(const gss_name_t name,
+ const char *username);
+
+/**
+ * Determine whether a mechanism name is authorized to act as a local name.
+ *
+ * @param [out] minor Minor status code
+ * @param [in] name Mechanism name
+ * @param [in] user Local name
+ *
+ * @a name is a mechanism name, typically the result of a completed
+ * gss_accept_sec_context(). @a user is an internal name representing a local
+ * name, such as a name imported by gss_import_name() with an @a
+ * input_name_type of @c GSS_C_NT_USER_NAME.
+ *
+ * @return Return GSS_S_COMPLETE if @a name is authorized to act as @a user,
+ * GSS_S_UNAUTHORIZED if not, or an appropriate GSS error code if an error
+ * occured.
+ *
+ * @sa gss_userok
+ */
+OM_uint32 KRB5_CALLCONV
+gss_authorize_localname(OM_uint32 *minor,
+ const gss_name_t name,
+ const gss_name_t user);
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_password(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ const gss_buffer_t, /* password */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_password(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t,/* input_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ const gss_buffer_t, /* password */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
+/*
+ * GGF extensions
+ */
+typedef struct gss_buffer_set_desc_struct {
+ size_t count;
+ gss_buffer_desc *elements;
+} gss_buffer_set_desc, *gss_buffer_set_t;
+
+#define GSS_C_NO_BUFFER_SET ((gss_buffer_set_t) 0)
+
+OM_uint32 KRB5_CALLCONV gss_create_empty_buffer_set
+ (OM_uint32 * /*minor_status*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 KRB5_CALLCONV gss_add_buffer_set_member
+ (OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*member_buffer*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 KRB5_CALLCONV gss_release_buffer_set
+ (OM_uint32 * /*minor_status*/,
+ gss_buffer_set_t * /*buffer_set*/);
+
+OM_uint32 KRB5_CALLCONV gss_inquire_sec_context_by_oid
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ const gss_OID /*desired_object*/,
+ gss_buffer_set_t * /*data_set*/);
+
+OM_uint32 KRB5_CALLCONV gss_inquire_cred_by_oid
+ (OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*cred_handle*/,
+ const gss_OID /*desired_object*/,
+ gss_buffer_set_t * /*data_set*/);
+
+OM_uint32 KRB5_CALLCONV gss_set_sec_context_option
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*cred_handle*/,
+ const gss_OID /*desired_object*/,
+ const gss_buffer_t /*value*/);
+
+OM_uint32 KRB5_CALLCONV gss_set_cred_option
+ (OM_uint32 * /*minor_status*/,
+ gss_cred_id_t * /*cred*/,
+ const gss_OID /*desired_object*/,
+ const gss_buffer_t /*value*/);
+
+OM_uint32 KRB5_CALLCONV gssspi_mech_invoke
+ (OM_uint32 * /*minor_status*/,
+ const gss_OID /*desired_mech*/,
+ const gss_OID /*desired_object*/,
+ gss_buffer_t /*value*/);
+
+/*
+ * AEAD extensions
+ */
+
+OM_uint32 KRB5_CALLCONV gss_wrap_aead
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ gss_qop_t /*qop_req*/,
+ gss_buffer_t /*input_assoc_buffer*/,
+ gss_buffer_t /*input_payload_buffer*/,
+ int * /*conf_state*/,
+ gss_buffer_t /*output_message_buffer*/);
+
+OM_uint32 KRB5_CALLCONV gss_unwrap_aead
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ gss_buffer_t /*input_message_buffer*/,
+ gss_buffer_t /*input_assoc_buffer*/,
+ gss_buffer_t /*output_payload_buffer*/,
+ int * /*conf_state*/,
+ gss_qop_t * /*qop_state*/);
+
+/*
+ * SSPI extensions
+ */
+#define GSS_C_DCE_STYLE 0x1000
+#define GSS_C_IDENTIFY_FLAG 0x2000
+#define GSS_C_EXTENDED_ERROR_FLAG 0x4000
+
+/*
+ * Returns a buffer set with the first member containing the
+ * session key for SSPI compatibility. The optional second
+ * member contains an OID identifying the session key type.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_INQ_SSPI_SESSION_KEY;
+
+OM_uint32 KRB5_CALLCONV gss_complete_auth_token
+ (OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer);
+
+typedef struct gss_iov_buffer_desc_struct {
+ OM_uint32 type;
+ gss_buffer_desc buffer;
+} gss_iov_buffer_desc, *gss_iov_buffer_t;
+
+#define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0)
+
+#define GSS_IOV_BUFFER_TYPE_EMPTY 0
+#define GSS_IOV_BUFFER_TYPE_DATA 1 /* Packet data */
+#define GSS_IOV_BUFFER_TYPE_HEADER 2 /* Mechanism header */
+#define GSS_IOV_BUFFER_TYPE_MECH_PARAMS 3 /* Mechanism specific parameters */
+#define GSS_IOV_BUFFER_TYPE_TRAILER 7 /* Mechanism trailer */
+#define GSS_IOV_BUFFER_TYPE_PADDING 9 /* Padding */
+#define GSS_IOV_BUFFER_TYPE_STREAM 10 /* Complete wrap token */
+#define GSS_IOV_BUFFER_TYPE_SIGN_ONLY 11 /* Sign only packet data */
+#define GSS_IOV_BUFFER_TYPE_MIC_TOKEN 12 /* MIC token destination */
+
+#define GSS_IOV_BUFFER_FLAG_MASK 0xFFFF0000
+#define GSS_IOV_BUFFER_FLAG_ALLOCATE 0x00010000 /* indicates GSS should allocate */
+#define GSS_IOV_BUFFER_FLAG_ALLOCATED 0x00020000 /* indicates caller should free */
+
+#define GSS_IOV_BUFFER_TYPE(_type) ((_type) & ~(GSS_IOV_BUFFER_FLAG_MASK))
+#define GSS_IOV_BUFFER_FLAGS(_type) ((_type) & GSS_IOV_BUFFER_FLAG_MASK)
+
+/*
+ * Sign and optionally encrypt a sequence of buffers. The buffers
+ * shall be ordered HEADER | DATA | PADDING | TRAILER. Suitable
+ * space for the header, padding and trailer should be provided
+ * by calling gss_wrap_iov_length(), or the ALLOCATE flag should
+ * be set on those buffers.
+ *
+ * Encryption is in-place. SIGN_ONLY buffers are untouched. Only
+ * a single PADDING buffer should be provided. The order of the
+ * buffers in memory does not matter. Buffers in the IOV should
+ * be arranged in the order above, and in the case of multiple
+ * DATA buffers the sender and receiver should agree on the
+ * order.
+ *
+ * With GSS_C_DCE_STYLE it is acceptable to not provide PADDING
+ * and TRAILER, but the caller must guarantee the plaintext data
+ * being encrypted is correctly padded, otherwise an error will
+ * be returned.
+ *
+ * While applications that have knowledge of the underlying
+ * cryptosystem may request a specific configuration of data
+ * buffers, the only generally supported configurations are:
+ *
+ * HEADER | DATA | PADDING | TRAILER
+ *
+ * which will emit GSS_Wrap() compatible tokens, and:
+ *
+ * HEADER | SIGN_ONLY | DATA | PADDING | TRAILER
+ *
+ * for AEAD.
+ *
+ * The typical (special cased) usage for DCE is as follows:
+ *
+ * SIGN_ONLY_1 | DATA | SIGN_ONLY_2 | HEADER
+ */
+OM_uint32 KRB5_CALLCONV gss_wrap_iov
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Verify and optionally decrypt a sequence of buffers. To process
+ * a GSS-API message without separate buffer, pass STREAM | DATA.
+ * Upon return DATA will contain the decrypted or integrity
+ * protected message. Only a single DATA buffer may be provided
+ * with this usage. DATA by default will point into STREAM, but if
+ * the ALLOCATE flag is set a copy will be returned.
+ *
+ * Otherwise, decryption is in-place. SIGN_ONLY buffers are
+ * untouched.
+ */
+OM_uint32 KRB5_CALLCONV gss_unwrap_iov
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int *, /* conf_state */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Query HEADER, PADDING and TRAILER buffer lengths. DATA buffers
+ * should be provided so the correct padding length can be determined.
+ */
+OM_uint32 KRB5_CALLCONV gss_wrap_iov_length
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Produce a GSSAPI MIC token for a sequence of buffers. All SIGN_ONLY and
+ * DATA buffers will be signed, in the order they appear. One MIC_TOKEN buffer
+ * must be included for the result. Suitable space should be provided for the
+ * MIC_TOKEN buffer by calling gss_get_mic_iov_length, or the ALLOCATE flag
+ * should be set on that buffer. If the ALLOCATE flag is used, use
+ * gss_release_iov_buffer to free the allocated buffer within the iov list when
+ * it is no longer needed.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Query the MIC_TOKEN buffer length within the iov list.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov_length(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Verify the MIC_TOKEN buffer within the iov list against the SIGN_ONLY and
+ * DATA buffers in the order they appear. Return values are the same as for
+ * gss_verify_mic.
+ */
+OM_uint32 KRB5_CALLCONV gss_verify_mic_iov
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Release buffers that have the ALLOCATED flag set.
+ */
+OM_uint32 KRB5_CALLCONV gss_release_iov_buffer
+(
+ OM_uint32 *, /* minor_status */
+ gss_iov_buffer_desc *, /* iov */
+ int); /* iov_count */
+
+/*
+ * Protocol transition
+ */
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
+/*
+ * Naming extensions
+ */
+GSS_DLLIMP extern gss_buffer_t GSS_C_ATTR_LOCAL_LOGIN_USER;
+GSS_DLLIMP extern gss_OID GSS_C_NT_COMPOSITE_EXPORT;
+
+OM_uint32 KRB5_CALLCONV gss_display_name_ext
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_OID, /* display_as_name_type */
+ gss_buffer_t /* display_name */
+);
+
+OM_uint32 KRB5_CALLCONV gss_inquire_name
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int *, /* name_is_MN */
+ gss_OID *, /* MN_mech */
+ gss_buffer_set_t * /* attrs */
+);
+
+OM_uint32 KRB5_CALLCONV gss_get_name_attribute
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t, /* attr */
+ int *, /* authenticated */
+ int *, /* complete */
+ gss_buffer_t, /* value */
+ gss_buffer_t, /* display_value */
+ int * /* more */
+);
+
+OM_uint32 KRB5_CALLCONV gss_set_name_attribute
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int, /* complete */
+ gss_buffer_t, /* attr */
+ gss_buffer_t /* value */
+);
+
+OM_uint32 KRB5_CALLCONV gss_delete_name_attribute
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t /* attr */
+);
+
+OM_uint32 KRB5_CALLCONV gss_export_name_composite
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t /* exp_composite_name */
+);
+
+typedef struct gss_any *gss_any_t;
+
+OM_uint32 KRB5_CALLCONV gss_map_name_to_any
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int, /* authenticated */
+ gss_buffer_t, /* type_id */
+ gss_any_t * /* output */
+);
+
+OM_uint32 KRB5_CALLCONV gss_release_any_name_mapping
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t, /* type_id */
+ gss_any_t * /* input */
+);
+
+/* draft-josefsson-gss-capsulate */
+OM_uint32 KRB5_CALLCONV gss_encapsulate_token
+(
+ gss_const_buffer_t, /* input_token */
+ gss_const_OID, /* token_oid */
+ gss_buffer_t /* output_token */
+);
+
+OM_uint32 KRB5_CALLCONV gss_decapsulate_token
+(
+ gss_const_buffer_t, /* input_token */
+ gss_const_OID, /* token_oid */
+ gss_buffer_t /* output_token */
+);
+
+int KRB5_CALLCONV gss_oid_equal
+(
+ gss_const_OID, /* first_oid */
+ gss_const_OID /* second_oid */
+);
+
+/* Credential store extensions */
+
+struct gss_key_value_element_struct {
+ const char *key;
+ const char *value;
+};
+typedef struct gss_key_value_element_struct gss_key_value_element_desc;
+
+struct gss_key_value_set_struct {
+ OM_uint32 count;
+ gss_key_value_element_desc *elements;
+};
+typedef struct gss_key_value_set_struct gss_key_value_set_desc;
+typedef const gss_key_value_set_desc *gss_const_key_value_set_t;
+
+#define GSS_C_NO_CRED_STORE ((gss_const_key_value_set_t) 0)
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_from(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_from(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_name_t, /* desired_name */
+ gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_store_cred_into(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_cred_usage_t, /* input_usage */
+ gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t *); /* cred_usage_stored */
+
+OM_uint32 KRB5_CALLCONV
+gss_export_cred(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_buffer_t); /* token */
+
+OM_uint32 KRB5_CALLCONV
+gss_import_cred(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* token */
+ gss_cred_id_t *); /* cred_handle */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GSSAPI_EXT_H_ */
diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
new file mode 100644
index 000000000000..5496aa33582c
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_generic.c
@@ -0,0 +1,450 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+
+/*
+ * See krb5/gssapi_krb5.c for a description of the algorithm for
+ * encoding an object identifier.
+ */
+
+/* Reserved static storage for GSS_oids. Comments are quotes from RFC 2744. */
+
+#define oids ((gss_OID_desc *)const_oids)
+static const gss_OID_desc const_oids[] = {
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) Unites States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) service_name(4)}.
+ * The constant GSS_C_NT_HOSTBASED_SERVICE should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ /* corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+ /*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ /* corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+ {6, (void *)"\x2b\x06\x01\x05\x06\x06"},
+ /* corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 6(gss-composite-export)}. The constant
+ * GSS_C_NT_COMPOSITE_EXPORT should be initialized to point
+ * to that gss_OID_desc.
+ */
+ /* GSS_C_INQ_SSPI_SESSION_KEY 1.2.840.113554.1.2.2.5.5 */
+ {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"},
+
+ /* RFC 5587 attributes, see below */
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x01"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x02"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x03"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x04"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x05"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x06"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x07"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x08"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x09"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0a"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0b"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0c"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0d"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0e"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0f"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x10"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x11"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x12"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x13"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x14"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x15"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x16"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x17"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x18"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"},
+ {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"},
+};
+
+/* Here are the constants which point to the static structure above.
+ *
+ * Constants of the form GSS_C_NT_* are specified by rfc 2744.
+ *
+ * Constants of the form gss_nt_* are the original MIT krb5 names
+ * found in gssapi_generic.h. They are provided for compatibility. */
+
+GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = oids+0;
+GSS_DLLIMP gss_OID gss_nt_user_name = oids+0;
+
+GSS_DLLIMP gss_OID GSS_C_NT_MACHINE_UID_NAME = oids+1;
+GSS_DLLIMP gss_OID gss_nt_machine_uid_name = oids+1;
+
+GSS_DLLIMP gss_OID GSS_C_NT_STRING_UID_NAME = oids+2;
+GSS_DLLIMP gss_OID gss_nt_string_uid_name = oids+2;
+
+GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = oids+3;
+gss_OID gss_nt_service_name_v2 = oids+3;
+
+GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = oids+4;
+GSS_DLLIMP gss_OID gss_nt_service_name = oids+4;
+
+GSS_DLLIMP gss_OID GSS_C_NT_ANONYMOUS = oids+5;
+
+GSS_DLLIMP gss_OID GSS_C_NT_EXPORT_NAME = oids+6;
+gss_OID gss_nt_exported_name = oids+6;
+
+GSS_DLLIMP gss_OID GSS_C_NT_COMPOSITE_EXPORT = oids+7;
+
+GSS_DLLIMP gss_OID GSS_C_INQ_SSPI_SESSION_KEY = oids+8;
+
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_CONCRETE = oids+9;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_PSEUDO = oids+10;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_COMPOSITE = oids+11;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_NEGO = oids+12;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_GLUE = oids+13;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_MECH = oids+14;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DEPRECATED = oids+15;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_DFLT_MECH = oids+16;
+GSS_DLLIMP gss_const_OID GSS_C_MA_ITOK_FRAMED = oids+17;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT = oids+18;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG = oids+19;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_INIT = oids+20;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_INIT = oids+21;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_ANON = oids+22;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_ANON = oids+23;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DELEG_CRED = oids+24;
+GSS_DLLIMP gss_const_OID GSS_C_MA_INTEG_PROT = oids+25;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CONF_PROT = oids+26;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MIC = oids+27;
+GSS_DLLIMP gss_const_OID GSS_C_MA_WRAP = oids+28;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PROT_READY = oids+29;
+GSS_DLLIMP gss_const_OID GSS_C_MA_REPLAY_DET = oids+30;
+GSS_DLLIMP gss_const_OID GSS_C_MA_OOS_DET = oids+31;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CBINDINGS = oids+32;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PFS = oids+33;
+GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS = oids+34;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS = oids+35;
+
+static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 };
+gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
+
+static struct mech_attr_info_desc {
+ gss_OID mech_attr;
+ const char *name;
+ const char *short_desc;
+ const char *long_desc;
+} mech_attr_info[] = {
+ {
+ oids+9,
+ "GSS_C_MA_MECH_CONCRETE",
+ "concrete-mech",
+ "Mechanism is neither a pseudo-mechanism nor a composite mechanism.",
+ },
+ {
+ oids+10,
+ "GSS_C_MA_MECH_PSEUDO",
+ "pseudo-mech",
+ "Mechanism is a pseudo-mechanism.",
+ },
+ {
+ oids+11,
+ "GSS_C_MA_MECH_COMPOSITE",
+ "composite-mech",
+ "Mechanism is a composite of other mechanisms.",
+ },
+ {
+ oids+12,
+ "GSS_C_MA_MECH_NEGO",
+ "mech-negotiation-mech",
+ "Mechanism negotiates other mechanisms.",
+ },
+ {
+ oids+13,
+ "GSS_C_MA_MECH_GLUE",
+ "mech-glue",
+ "OID is not a mechanism but the GSS-API itself.",
+ },
+ {
+ oids+14,
+ "GSS_C_MA_NOT_MECH",
+ "not-mech",
+ "Known OID but not a mechanism OID.",
+ },
+ {
+ oids+15,
+ "GSS_C_MA_DEPRECATED",
+ "mech-deprecated",
+ "Mechanism is deprecated.",
+ },
+ {
+ oids+16,
+ "GSS_C_MA_NOT_DFLT_MECH",
+ "mech-not-default",
+ "Mechanism must not be used as a default mechanism.",
+ },
+ {
+ oids+17,
+ "GSS_C_MA_ITOK_FRAMED",
+ "initial-is-framed",
+ "Mechanism's initial contexts are properly framed.",
+ },
+ {
+ oids+18,
+ "GSS_C_MA_AUTH_INIT",
+ "auth-init-princ",
+ "Mechanism supports authentication of initiator to acceptor.",
+ },
+ {
+ oids+19,
+ "GSS_C_MA_AUTH_TARG",
+ "auth-targ-princ",
+ "Mechanism supports authentication of acceptor to initiator.",
+ },
+ {
+ oids+20,
+ "GSS_C_MA_AUTH_INIT_INIT",
+ "auth-init-princ-initial",
+ "Mechanism supports authentication of initiator using "
+ "initial credentials.",
+ },
+ {
+ oids+21,
+ "GSS_C_MA_AUTH_TARG_INIT",
+ "auth-target-princ-initial",
+ "Mechanism supports authentication of acceptor using "
+ "initial credentials.",
+ },
+ {
+ oids+22,
+ "GSS_C_MA_AUTH_INIT_ANON",
+ "auth-init-princ-anon",
+ "Mechanism supports GSS_C_NT_ANONYMOUS as an initiator name.",
+ },
+ {
+ oids+23,
+ "GSS_C_MA_AUTH_TARG_ANON",
+ "auth-targ-princ-anon",
+ "Mechanism supports GSS_C_NT_ANONYMOUS as an acceptor name.",
+ },
+ {
+ oids+24,
+ "GSS_C_MA_DELEG_CRED",
+ "deleg-cred",
+ "Mechanism supports credential delegation.",
+ },
+ {
+ oids+25,
+ "GSS_C_MA_INTEG_PROT",
+ "integ-prot",
+ "Mechanism supports per-message integrity protection.",
+ },
+ {
+ oids+26,
+ "GSS_C_MA_CONF_PROT",
+ "conf-prot",
+ "Mechanism supports per-message confidentiality protection.",
+ },
+ {
+ oids+27,
+ "GSS_C_MA_MIC",
+ "mic",
+ "Mechanism supports Message Integrity Code (MIC) tokens.",
+ },
+ {
+ oids+28,
+ "GSS_C_MA_WRAP",
+ "wrap",
+ "Mechanism supports wrap tokens.",
+ },
+ {
+ oids+29,
+ "GSS_C_MA_PROT_READY",
+ "prot-ready",
+ "Mechanism supports per-message proteciton prior to "
+ "full context establishment.",
+ },
+ {
+ oids+30,
+ "GSS_C_MA_REPLAY_DET",
+ "replay-detection",
+ "Mechanism supports replay detection.",
+ },
+ {
+ oids+31,
+ "GSS_C_MA_OOS_DET",
+ "oos-detection",
+ "Mechanism supports out-of-sequence detection.",
+ },
+ {
+ oids+32,
+ "GSS_C_MA_CBINDINGS",
+ "channel-bindings",
+ "Mechanism supports channel bindings.",
+ },
+ {
+ oids+33,
+ "GSS_C_MA_PFS",
+ "pfs",
+ "Mechanism supports Perfect Forward Security.",
+ },
+ {
+ oids+34,
+ "GSS_C_MA_COMPRESS",
+ "compress",
+ "Mechanism supports compression of data inputs to gss_wrap().",
+ },
+ {
+ oids+35,
+ "GSS_C_MA_CTX_TRANS",
+ "context-transfer",
+ "Mechanism supports security context export/import.",
+ },
+};
+
+OM_uint32
+generic_gss_display_mech_attr(
+ OM_uint32 *minor_status,
+ gss_const_OID mech_attr,
+ gss_buffer_t name,
+ gss_buffer_t short_desc,
+ gss_buffer_t long_desc)
+{
+ size_t i;
+
+ if (name != GSS_C_NO_BUFFER) {
+ name->length = 0;
+ name->value = NULL;
+ }
+ if (short_desc != GSS_C_NO_BUFFER) {
+ short_desc->length = 0;
+ short_desc->value = NULL;
+ }
+ if (long_desc != GSS_C_NO_BUFFER) {
+ long_desc->length = 0;
+ long_desc->value = NULL;
+ }
+ for (i = 0; i < sizeof(mech_attr_info)/sizeof(mech_attr_info[0]); i++) {
+ struct mech_attr_info_desc *mai = &mech_attr_info[i];
+
+ if (g_OID_equal(mech_attr, mai->mech_attr)) {
+ if (name != GSS_C_NO_BUFFER &&
+ !g_make_string_buffer(mai->name, name)) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (short_desc != GSS_C_NO_BUFFER &&
+ !g_make_string_buffer(mai->short_desc, short_desc)) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (long_desc != GSS_C_NO_BUFFER &&
+ !g_make_string_buffer(mai->long_desc, long_desc)) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ return GSS_S_COMPLETE;
+ }
+ }
+
+ return GSS_S_BAD_MECH_ATTR;
+}
+
+static gss_buffer_desc const_attrs[] = {
+ { sizeof("local-login-user") - 1,
+ "local-login-user" },
+};
+
+GSS_DLLIMP gss_buffer_t GSS_C_ATTR_LOCAL_LOGIN_USER = &const_attrs[0];
diff --git a/src/lib/gssapi/generic/gssapi_generic.h b/src/lib/gssapi/generic/gssapi_generic.h
new file mode 100644
index 000000000000..e11f938c672b
--- /dev/null
+++ b/src/lib/gssapi/generic/gssapi_generic.h
@@ -0,0 +1,59 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#ifndef _GSSAPI_GENERIC_H_
+#define _GSSAPI_GENERIC_H_
+
+/*
+ * $Id$
+ */
+
+#include <gssapi/gssapi.h>
+
+#if defined(__cplusplus) && !defined(GSSAPIGENERIC_BEGIN_DECLS)
+#define GSSAPIGENERIC_BEGIN_DECLS extern "C" {
+#define GSSAPIGENERIC_END_DECLS }
+#else
+#define GSSAPIGENERIC_BEGIN_DECLS
+#define GSSAPIGENERIC_END_DECLS
+#endif
+
+#define GSS_EMPTY_BUFFER(buf) ((buf) == NULL || \
+ (buf)->value == NULL || (buf)->length == 0)
+
+GSSAPIGENERIC_BEGIN_DECLS
+
+/* Deprecated MIT krb5 oid names provided for compatibility.
+ * The correct oids (GSS_C_NT_USER_NAME, etc) from rfc 2744
+ * are defined in gssapi.h. */
+
+GSS_DLLIMP extern gss_OID gss_nt_user_name;
+GSS_DLLIMP extern gss_OID gss_nt_machine_uid_name;
+GSS_DLLIMP extern gss_OID gss_nt_string_uid_name;
+extern gss_OID gss_nt_service_name_v2;
+GSS_DLLIMP extern gss_OID gss_nt_service_name;
+extern gss_OID gss_nt_exported_name;
+
+GSSAPIGENERIC_END_DECLS
+
+#endif /* _GSSAPI_GENERIC_H_ */
diff --git a/src/lib/gssapi/generic/maptest.c b/src/lib/gssapi/generic/maptest.c
new file mode 100644
index 000000000000..566d88c316f1
--- /dev/null
+++ b/src/lib/gssapi/generic/maptest.c
@@ -0,0 +1,68 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+typedef struct { int a, b; } elt;
+static int eltcp(elt *dest, elt src)
+{
+ *dest = src;
+ return 0;
+}
+static int eltcmp(elt left, elt right)
+{
+ if (left.a < right.a)
+ return -1;
+ if (left.a > right.a)
+ return 1;
+ if (left.b < right.b)
+ return -1;
+ if (left.b > right.b)
+ return 1;
+ return 0;
+}
+static void eltprt(elt v, FILE *f)
+{
+ fprintf(f, "{%d,%d}", v.a, v.b);
+}
+static int intcmp(int left, int right)
+{
+ if (left < right)
+ return -1;
+ if (left > right)
+ return 1;
+ return 0;
+}
+static void intprt(int v, FILE *f)
+{
+ fprintf(f, "%d", v);
+}
+
+#include "maptest.h"
+
+foo foo1;
+
+int main ()
+{
+ elt v1 = { 1, 2 }, v2 = { 3, 4 };
+ const elt *vp;
+ const int *ip;
+
+ assert(0 == foo_init(&foo1));
+ vp = foo_findleft(&foo1, 47);
+ assert(vp == NULL);
+ assert(0 == foo_add(&foo1, 47, v1));
+ vp = foo_findleft(&foo1, 47);
+ assert(vp != NULL);
+ assert(0 == eltcmp(*vp, v1));
+ vp = foo_findleft(&foo1, 3);
+ assert(vp == NULL);
+ assert(0 == foo_add(&foo1, 93, v2));
+ ip = foo_findright(&foo1, v1);
+ assert(ip != NULL);
+ assert(*ip == 47);
+ printf("Map content: ");
+ foo_printmap(&foo1, stdout);
+ printf("\n");
+ return 0;
+}
diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c
new file mode 100644
index 000000000000..6e294b9bcf94
--- /dev/null
+++ b/src/lib/gssapi/generic/oid_ops.c
@@ -0,0 +1,553 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/oid_ops.c */
+/*
+ * Copyright 1995 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 1993 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.
+ */
+
+/* GSS-API V2 interfaces to manipulate OIDs */
+
+#include "gssapiP_generic.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <gssapi/gssapi_generic.h>
+#include <errno.h>
+#include <ctype.h>
+
+/*
+ * The functions for allocating and releasing individual OIDs use malloc and
+ * free instead of the gssalloc wrappers, because the mechglue currently mixes
+ * generic_gss_copy_oid() with hand-freeing of OIDs. We do not need to free
+ * free OIDs allocated by mechanisms, so this should not be a problem.
+ */
+
+OM_uint32
+generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
+{
+ if (minor_status)
+ *minor_status = 0;
+
+ if (oid == NULL || *oid == GSS_C_NO_OID)
+ return(GSS_S_COMPLETE);
+
+ /*
+ * The V2 API says the following!
+ *
+ * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+ * and will silently ignore attempts to free these OIDs; for other OIDs
+ * it will call the C free() routine for both the OID data and the
+ * descriptor. This allows applications to freely mix their own heap-
+ * allocated OID values with OIDs returned by GSS-API.
+ */
+
+ /*
+ * We use the official OID definitions instead of the unofficial OID
+ * defintions. But we continue to support the unofficial OID
+ * gss_nt_service_name just in case if some gss applications use
+ * the old OID.
+ */
+
+ if ((*oid != GSS_C_NT_USER_NAME) &&
+ (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
+ (*oid != GSS_C_NT_STRING_UID_NAME) &&
+ (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
+ (*oid != GSS_C_NT_ANONYMOUS) &&
+ (*oid != GSS_C_NT_EXPORT_NAME) &&
+ (*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
+ (*oid != gss_nt_service_name)) {
+ free((*oid)->elements);
+ free(*oid);
+ }
+ *oid = GSS_C_NO_OID;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+generic_gss_copy_oid(OM_uint32 *minor_status,
+ const gss_OID_desc * const oid,
+ gss_OID *new_oid)
+{
+ gss_OID p;
+
+ *minor_status = 0;
+
+ p = (gss_OID) malloc(sizeof(gss_OID_desc));
+ if (!p) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ p->length = oid->length;
+ p->elements = malloc(p->length);
+ if (!p->elements) {
+ free(p);
+ return GSS_S_FAILURE;
+ }
+ memcpy(p->elements, oid->elements, p->length);
+ *new_oid = p;
+ return(GSS_S_COMPLETE);
+}
+
+
+OM_uint32
+generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
+{
+ *minor_status = 0;
+
+ if (oid_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
+ memset(*oid_set, 0, sizeof(gss_OID_set_desc));
+ return(GSS_S_COMPLETE);
+ }
+ else {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+}
+
+OM_uint32
+generic_gss_add_oid_set_member(OM_uint32 *minor_status,
+ const gss_OID_desc * const member_oid,
+ gss_OID_set *oid_set)
+{
+ gss_OID elist;
+ gss_OID lastel;
+
+ *minor_status = 0;
+
+ if (member_oid == NULL || member_oid->length == 0 ||
+ member_oid->elements == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (oid_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ elist = (*oid_set)->elements;
+ /* Get an enlarged copy of the array */
+ if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
+ sizeof(gss_OID_desc)))) {
+ /* Copy in the old junk */
+ if (elist)
+ memcpy((*oid_set)->elements,
+ elist,
+ ((*oid_set)->count * sizeof(gss_OID_desc)));
+
+ /* Duplicate the input element */
+ lastel = &(*oid_set)->elements[(*oid_set)->count];
+ if ((lastel->elements =
+ (void *) gssalloc_malloc((size_t) member_oid->length))) {
+ /* Success - copy elements */
+ memcpy(lastel->elements, member_oid->elements,
+ (size_t) member_oid->length);
+ /* Set length */
+ lastel->length = member_oid->length;
+
+ /* Update count */
+ (*oid_set)->count++;
+ if (elist)
+ gssalloc_free(elist);
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+ else
+ gssalloc_free((*oid_set)->elements);
+ }
+ /* Failure - restore old contents of list */
+ (*oid_set)->elements = elist;
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_test_oid_set_member(OM_uint32 *minor_status,
+ const gss_OID_desc * const member,
+ gss_OID_set set,
+ int * present)
+{
+ OM_uint32 i;
+ int result;
+
+ *minor_status = 0;
+
+ if (member == NULL || set == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (present == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ result = 0;
+ for (i=0; i<set->count; i++) {
+ if ((set->elements[i].length == member->length) &&
+ !memcmp(set->elements[i].elements,
+ member->elements,
+ (size_t) member->length)) {
+ result = 1;
+ break;
+ }
+ }
+ *present = result;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+generic_gss_oid_to_str(OM_uint32 *minor_status,
+ const gss_OID_desc * const oid,
+ gss_buffer_t oid_str)
+{
+ unsigned long number, n;
+ OM_uint32 i;
+ int first;
+ unsigned char *cp;
+ struct k5buf buf;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (oid_str != GSS_C_NO_BUFFER) {
+ oid_str->length = 0;
+ oid_str->value = NULL;
+ }
+
+ if (oid == NULL || oid->length == 0 || oid->elements == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (oid_str == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /* Decoded according to krb5/gssapi_krb5.c */
+
+ cp = (unsigned char *) oid->elements;
+ number = (unsigned long) cp[0];
+ k5_buf_init_dynamic(&buf);
+ k5_buf_add(&buf, "{ ");
+ number = 0;
+ cp = (unsigned char *) oid->elements;
+ first = 1;
+ for (i = 0; i < oid->length; i++) {
+ number = (number << 7) | (cp[i] & 0x7f);
+ if ((cp[i] & 0x80) == 0) {
+ if (first) {
+ n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
+ k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
+ first = 0;
+ } else {
+ k5_buf_add_fmt(&buf, "%lu ", number);
+ }
+ number = 0;
+ }
+ }
+ k5_buf_add_len(&buf, "}\0", 2);
+ return k5buf_to_gss(minor_status, &buf, oid_str);
+}
+
+/* Return the length of a DER OID subidentifier encoding. */
+static size_t
+arc_encoded_length(unsigned long arc)
+{
+ size_t len = 1;
+
+ for (arc >>= 7; arc; arc >>= 7)
+ len++;
+ return len;
+}
+
+/* Encode a subidentifier into *bufp and advance it to the encoding's end. */
+static void
+arc_encode(unsigned long arc, unsigned char **bufp)
+{
+ unsigned char *p;
+
+ /* Advance to the end and encode backwards. */
+ p = *bufp = *bufp + arc_encoded_length(arc);
+ *--p = arc & 0x7f;
+ for (arc >>= 7; arc; arc >>= 7)
+ *--p = (arc & 0x7f) | 0x80;
+}
+
+/* Fetch an arc value from *bufp and advance past it and any following spaces
+ * or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */
+static int
+get_arc(const unsigned char **bufp, const unsigned char *end,
+ unsigned long *arc_out)
+{
+ const unsigned char *p = *bufp;
+ unsigned long arc = 0, newval;
+
+ if (p == end || !isdigit(*p))
+ return 0;
+ for (; p < end && isdigit(*p); p++) {
+ newval = arc * 10 + (*p - '0');
+ if (newval < arc)
+ return 0;
+ arc = newval;
+ }
+ while (p < end && (isspace(*p) || *p == '.'))
+ p++;
+ *bufp = p;
+ *arc_out = arc;
+ return 1;
+}
+
+/*
+ * Convert a sequence of two or more decimal arc values into a DER-encoded OID.
+ * The values may be separated by any combination of whitespace and period
+ * characters, and may be optionally surrounded with braces. Leading
+ * whitespace and trailing garbage is allowed. The first arc value must be 0,
+ * 1, or 2, and the second value must be less than 40 if the first value is not
+ * 2.
+ */
+OM_uint32
+generic_gss_str_to_oid(OM_uint32 *minor_status,
+ gss_buffer_t oid_str,
+ gss_OID *oid_out)
+{
+ const unsigned char *p, *end, *arc3_start;
+ unsigned char *out;
+ unsigned long arc, arc1, arc2;
+ size_t nbytes;
+ int brace = 0;
+ gss_OID oid;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (oid_out != NULL)
+ *oid_out = GSS_C_NO_OID;
+
+ if (GSS_EMPTY_BUFFER(oid_str))
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (oid_out == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /* Skip past initial spaces and, optionally, an open brace. */
+ brace = 0;
+ p = oid_str->value;
+ end = p + oid_str->length;
+ while (p < end && isspace(*p))
+ p++;
+ if (p < end && *p == '{') {
+ brace = 1;
+ p++;
+ }
+ while (p < end && isspace(*p))
+ p++;
+
+ /* Get the first two arc values, to be encoded as one subidentifier. */
+ if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
+ return (GSS_S_FAILURE);
+ if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
+ return (GSS_S_FAILURE);
+ arc3_start = p;
+
+ /* Compute the total length of the encoding while checking syntax. */
+ nbytes = arc_encoded_length(arc1 * 40 + arc2);
+ while (get_arc(&p, end, &arc))
+ nbytes += arc_encoded_length(arc);
+ if (brace && (p == end || *p != '}'))
+ return (GSS_S_FAILURE);
+
+ /* Allocate an oid structure. */
+ oid = malloc(sizeof(*oid));
+ if (oid == NULL)
+ return (GSS_S_FAILURE);
+ oid->elements = malloc(nbytes);
+ if (oid->elements == NULL) {
+ free(oid);
+ return (GSS_S_FAILURE);
+ }
+ oid->length = nbytes;
+
+ out = oid->elements;
+ arc_encode(arc1 * 40 + arc2, &out);
+ p = arc3_start;
+ while (get_arc(&p, end, &arc))
+ arc_encode(arc, &out);
+ assert(out - nbytes == oid->elements);
+ *oid_out = oid;
+ return(GSS_S_COMPLETE);
+}
+
+/* Compose an OID of a prefix and an integer suffix */
+OM_uint32
+generic_gss_oid_compose(OM_uint32 *minor_status,
+ const char *prefix,
+ size_t prefix_len,
+ int suffix,
+ gss_OID_desc *oid)
+{
+ int osuffix, i;
+ size_t nbytes;
+ unsigned char *op;
+
+ if (oid == GSS_C_NO_OID) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ if (oid->length < prefix_len) {
+ *minor_status = ERANGE;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(oid->elements, prefix, prefix_len);
+
+ nbytes = 0;
+ osuffix = suffix;
+ while (suffix) {
+ nbytes++;
+ suffix >>= 7;
+ }
+ suffix = osuffix;
+
+ if (oid->length < prefix_len + nbytes) {
+ *minor_status = ERANGE;
+ return GSS_S_FAILURE;
+ }
+
+ op = (unsigned char *) oid->elements + prefix_len + nbytes;
+ i = -1;
+ while (suffix) {
+ op[i] = (unsigned char)suffix & 0x7f;
+ if (i != -1)
+ op[i] |= 0x80;
+ i--;
+ suffix >>= 7;
+ }
+
+ oid->length = prefix_len + nbytes;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+generic_gss_oid_decompose(OM_uint32 *minor_status,
+ const char *prefix,
+ size_t prefix_len,
+ gss_OID_desc *oid,
+ int *suffix)
+{
+ size_t i, slen;
+ unsigned char *op;
+
+ if (oid->length < prefix_len ||
+ memcmp(oid->elements, prefix, prefix_len) != 0) {
+ return GSS_S_BAD_MECH;
+ }
+
+ op = (unsigned char *) oid->elements + prefix_len;
+
+ *suffix = 0;
+
+ slen = oid->length - prefix_len;
+
+ for (i = 0; i < slen; i++) {
+ *suffix = (*suffix << 7) | (op[i] & 0x7f);
+ if (i + 1 != slen && (op[i] & 0x80) == 0) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+generic_gss_copy_oid_set(OM_uint32 *minor_status,
+ const gss_OID_set_desc * const oidset,
+ gss_OID_set *new_oidset)
+{
+ gss_OID_set_desc *copy;
+ OM_uint32 minor = 0;
+ OM_uint32 major = GSS_S_COMPLETE;
+ OM_uint32 i;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (new_oidset != NULL)
+ *new_oidset = GSS_C_NO_OID_SET;
+
+ if (oidset == GSS_C_NO_OID_SET)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (new_oidset == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if ((copy->elements = (gss_OID_desc *)
+ gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+ copy->count = oidset->count;
+
+ for (i = 0; i < copy->count; i++) {
+ gss_OID_desc *out = &copy->elements[i];
+ gss_OID_desc *in = &oidset->elements[i];
+
+ if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+ (void) memcpy(out->elements, in->elements, in->length);
+ out->length = in->length;
+ }
+
+ *new_oidset = copy;
+done:
+ if (major != GSS_S_COMPLETE) {
+ (void) generic_gss_release_oid_set(&minor, &copy);
+ }
+
+ return (major);
+}
diff --git a/src/lib/gssapi/generic/rel_buffer.c b/src/lib/gssapi/generic/rel_buffer.c
new file mode 100644
index 000000000000..44dc98157b79
--- /dev/null
+++ b/src/lib/gssapi/generic/rel_buffer.c
@@ -0,0 +1,57 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* #ident "@(#)g_rel_buffer.c 1.2 96/02/06 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_release_buffer
+ */
+
+#include "gssapiP_generic.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32
+generic_gss_release_buffer(
+ OM_uint32 *minor_status,
+ gss_buffer_t buffer)
+{
+ if (minor_status)
+ *minor_status = 0;
+
+ /* if buffer is NULL, return */
+
+ if (buffer == GSS_C_NO_BUFFER)
+ return(GSS_S_COMPLETE);
+
+ if (buffer->value) {
+ gssalloc_free(buffer->value);
+ buffer->length = 0;
+ buffer->value = NULL;
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/generic/rel_oid_set.c b/src/lib/gssapi/generic/rel_oid_set.c
new file mode 100644
index 000000000000..954542e40754
--- /dev/null
+++ b/src/lib/gssapi/generic/rel_oid_set.c
@@ -0,0 +1,61 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* #ident "@(#)gss_release_oid_set.c 1.12 95/08/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_release_oid_set
+ */
+
+#include "gssapiP_generic.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32
+generic_gss_release_oid_set(
+ OM_uint32 *minor_status,
+ gss_OID_set *set)
+{
+ size_t i;
+ if (minor_status)
+ *minor_status = 0;
+
+ if (set == NULL)
+ return(GSS_S_COMPLETE);
+
+ if (*set == GSS_C_NULL_OID_SET)
+ return(GSS_S_COMPLETE);
+
+ for (i=0; i<(*set)->count; i++)
+ gssalloc_free((*set)->elements[i].elements);
+
+ gssalloc_free((*set)->elements);
+ gssalloc_free(*set);
+
+ *set = GSS_C_NULL_OID_SET;
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/generic/t_seqstate.c b/src/lib/gssapi/generic/t_seqstate.c
new file mode 100644
index 000000000000..8f44fcf3edb2
--- /dev/null
+++ b/src/lib/gssapi/generic/t_seqstate.c
@@ -0,0 +1,197 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/t_seqstate.c - Test program for sequence number state */
+/*
+ * Copyright (C) 2014 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gssapiP_generic.h"
+
+enum resultcode {
+ NOERR = GSS_S_COMPLETE,
+ GAP = GSS_S_GAP_TOKEN,
+ UNSEQ = GSS_S_UNSEQ_TOKEN,
+ OLD = GSS_S_OLD_TOKEN,
+ REPLAY = GSS_S_DUPLICATE_TOKEN
+};
+
+enum replayflag { NO_REPLAY = 0, DO_REPLAY = 1 };
+enum sequenceflag { NO_SEQUENCE = 0, DO_SEQUENCE = 1 };
+enum width { NARROW = 0, WIDE = 1, BOTH = 2 };
+
+struct test {
+ uint64_t initial;
+ enum replayflag do_replay;
+ enum sequenceflag do_sequence;
+ enum width wide_seqnums;
+ size_t nseqs;
+ struct {
+ uint64_t seqnum;
+ enum resultcode result;
+ } seqs[10];
+} tests[] = {
+ /* No replay or sequence checking. */
+ {
+ 10, NO_REPLAY, NO_SEQUENCE, BOTH,
+ 4, { { 11, NOERR }, { 10, NOERR }, { 10, NOERR }, { 9, NOERR } }
+ },
+
+ /* Basic sequence checking, no wraparound. */
+ {
+ 100, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 4, { { 100, NOERR }, { 102, GAP }, { 103, NOERR }, { 101, UNSEQ } }
+ },
+
+ /* Initial gap sequence checking, no wraparound. */
+ {
+ 200, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 4, { { 201, GAP }, { 202, NOERR }, { 200, UNSEQ }, { 203, NOERR } }
+ },
+
+ /* Sequence checking with wraparound. */
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
+ 4, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, NOERR },
+ { 1, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
+ 4, { { UINT32_MAX - 1, NOERR }, { 0, GAP }, { UINT32_MAX, UNSEQ },
+ { 1, NOERR } }
+ },
+ {
+ UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT64_MAX - 1, NOERR }, { UINT64_MAX, NOERR }, { 0, NOERR },
+ { 1, NOERR } }
+ },
+ {
+ UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT64_MAX - 1, NOERR }, { 0, GAP }, { UINT64_MAX, UNSEQ },
+ { 1, NOERR } }
+ },
+
+ /* 64-bit sequence checking beyond 32-bit range */
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT32_MAX - 1, NOERR },
+ { UINT32_MAX, NOERR },
+ { (uint64_t)UINT32_MAX + 1, NOERR },
+ { (uint64_t)UINT32_MAX + 2, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT32_MAX - 1, NOERR },
+ { (uint64_t)UINT32_MAX + 1, GAP },
+ { UINT32_MAX, UNSEQ },
+ { (uint64_t)UINT32_MAX + 2, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 3, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, GAP } }
+ },
+
+ /* Replay without the replay flag set. */
+ {
+ 250, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 2, { { 250, NOERR }, { 250, UNSEQ } }
+ },
+
+ /* Basic replay detection with and without sequence checking. */
+ {
+ 0, DO_REPLAY, DO_SEQUENCE, BOTH,
+ 10, { { 5, GAP }, { 3, UNSEQ }, { 8, GAP }, { 3, REPLAY },
+ { 0, UNSEQ }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
+ { 8, REPLAY }, { 9, NOERR } }
+ },
+ {
+ 0, DO_REPLAY, NO_SEQUENCE, BOTH,
+ 10, { { 5, NOERR }, { 3, NOERR }, { 8, NOERR }, { 3, REPLAY },
+ { 0, NOERR }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
+ { 8, REPLAY }, { 9, NOERR } }
+ },
+
+ /* Replay and sequence detection with wraparound. The last seqnum produces
+ * GAP because it is before the initial sequence number. */
+ {
+ UINT64_MAX - 5, DO_REPLAY, DO_SEQUENCE, WIDE,
+ 10, { { UINT64_MAX, GAP }, { UINT64_MAX - 2, UNSEQ }, { 0, NOERR },
+ { UINT64_MAX, REPLAY }, { UINT64_MAX, REPLAY },
+ { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
+ { UINT64_MAX - 2, REPLAY }, { UINT64_MAX - 6, GAP } }
+ },
+ {
+ UINT32_MAX - 5, DO_REPLAY, DO_SEQUENCE, NARROW,
+ 10, { { UINT32_MAX, GAP }, { UINT32_MAX - 2, UNSEQ }, { 0, NOERR },
+ { UINT32_MAX, REPLAY }, { UINT32_MAX, REPLAY },
+ { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
+ { UINT32_MAX - 2, REPLAY }, { UINT32_MAX - 6, GAP } }
+ },
+
+ /* Old token edge cases. The current code can detect replays up to 64
+ * numbers behind the expected sequence number (1164 in this case). */
+ {
+ 1000, DO_REPLAY, NO_SEQUENCE, BOTH,
+ 10, { { 1163, NOERR }, { 1100, NOERR }, { 1100, REPLAY },
+ { 1163, REPLAY }, { 1099, OLD }, { 1100, REPLAY },
+ { 1150, NOERR }, { 1150, REPLAY }, { 1000, OLD },
+ { 999, NOERR } }
+ },
+};
+
+int
+main()
+{
+ size_t i, j;
+ enum width w;
+ struct test *t;
+ g_seqnum_state seqstate;
+ OM_uint32 status;
+
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ t = &tests[i];
+ /* Try both widths if t->wide_seqnums is both, otherwise just one. */
+ for (w = NARROW; w <= WIDE; w++) {
+ if (t->wide_seqnums != BOTH && t->wide_seqnums != w)
+ continue;
+ if (g_seqstate_init(&seqstate, t->initial, t->do_replay,
+ t->do_sequence, w))
+ abort();
+ for (j = 0; j < t->nseqs; j++) {
+ status = g_seqstate_check(seqstate, t->seqs[j].seqnum);
+ if (status != t->seqs[j].result) {
+ fprintf(stderr, "Test %d seq %d failed: %d != %d\n",
+ (int)i, (int)j, status, t->seqs[j].result);
+ return 1;
+ }
+ }
+ g_seqstate_free(seqstate);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/lib/gssapi/generic/util_buffer.c b/src/lib/gssapi/generic/util_buffer.c
new file mode 100644
index 000000000000..da2d83291370
--- /dev/null
+++ b/src/lib/gssapi/generic/util_buffer.c
@@ -0,0 +1,48 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+
+/* return nonzero on success, 0 on failure
+ make sure that buffer is consistent (release'able) when this
+ function exits, no matter what the exit value */
+
+int g_make_string_buffer(const char *str, gss_buffer_t buffer)
+{
+ if (buffer == GSS_C_NO_BUFFER)
+ return (1);
+
+ buffer->length = strlen(str);
+
+ if ((buffer->value = gssalloc_strdup(str)) == NULL) {
+ buffer->length = 0;
+ return(0);
+ }
+
+ return(1);
+}
diff --git a/src/lib/gssapi/generic/util_buffer_set.c b/src/lib/gssapi/generic/util_buffer_set.c
new file mode 100644
index 000000000000..f7472a0807ba
--- /dev/null
+++ b/src/lib/gssapi/generic/util_buffer_set.c
@@ -0,0 +1,126 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2008 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.
+ *
+ */
+
+#include "gssapiP_generic.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32
+generic_gss_create_empty_buffer_set(OM_uint32 * minor_status,
+ gss_buffer_set_t *buffer_set)
+{
+ gss_buffer_set_t set;
+
+ set = (gss_buffer_set_desc *) gssalloc_malloc(sizeof(*set));
+ if (set == GSS_C_NO_BUFFER_SET) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ set->count = 0;
+ set->elements = NULL;
+
+ *buffer_set = set;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+generic_gss_add_buffer_set_member(OM_uint32 * minor_status,
+ const gss_buffer_t member_buffer,
+ gss_buffer_set_t *buffer_set)
+{
+ gss_buffer_set_t set;
+ gss_buffer_t p;
+ OM_uint32 ret;
+
+ if (*buffer_set == GSS_C_NO_BUFFER_SET) {
+ ret = generic_gss_create_empty_buffer_set(minor_status,
+ buffer_set);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ set = *buffer_set;
+ set->elements = (gss_buffer_desc *)gssalloc_realloc(set->elements,
+ (set->count + 1) *
+ sizeof(gss_buffer_desc));
+ if (set->elements == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = &set->elements[set->count];
+
+ p->value = gssalloc_malloc(member_buffer->length);
+ if (p->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(p->value, member_buffer->value, member_buffer->length);
+ p->length = member_buffer->length;
+
+ set->count++;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+generic_gss_release_buffer_set(OM_uint32 * minor_status,
+ gss_buffer_set_t *buffer_set)
+{
+ size_t i;
+ OM_uint32 minor;
+
+ *minor_status = 0;
+
+ if (*buffer_set == GSS_C_NO_BUFFER_SET) {
+ return GSS_S_COMPLETE;
+ }
+
+ for (i = 0; i < (*buffer_set)->count; i++) {
+ generic_gss_release_buffer(&minor, &((*buffer_set)->elements[i]));
+ }
+
+ if ((*buffer_set)->elements != NULL) {
+ gssalloc_free((*buffer_set)->elements);
+ (*buffer_set)->elements = NULL;
+ }
+
+ (*buffer_set)->count = 0;
+
+ gssalloc_free(*buffer_set);
+ *buffer_set = GSS_C_NO_BUFFER_SET;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/generic/util_errmap.c b/src/lib/gssapi/generic/util_errmap.c
new file mode 100644
index 000000000000..628a455d2ad4
--- /dev/null
+++ b/src/lib/gssapi/generic/util_errmap.c
@@ -0,0 +1,264 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2007, 2008 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.
+ *
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+/* The mapping table is 0-based, but let's export codes that are
+ 1-based, keeping 0 for errors or unknown errors.
+
+ The elements in the mapping table currently have separate copies of
+ each OID stored. This is a bit wasteful, but we are assuming the
+ table isn't likely to grow very large. */
+
+struct mecherror {
+ gss_OID_desc mech;
+ OM_uint32 code;
+};
+
+static inline int
+cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2)
+{
+ if (m1 < m2)
+ return -1;
+ else if (m1 > m2)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int
+mecherror_cmp(struct mecherror m1, struct mecherror m2)
+{
+ if (m1.code < m2.code)
+ return -1;
+ if (m1.code > m2.code)
+ return 1;
+ if (m1.mech.length < m2.mech.length)
+ return -1;
+ if (m1.mech.length > m2.mech.length)
+ return 1;
+ if (m1.mech.length == 0)
+ return 0;
+ return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length);
+}
+
+static void
+print_OM_uint32 (OM_uint32 value, FILE *f)
+{
+ fprintf(f, "%lu", (unsigned long) value);
+}
+
+static inline int
+mecherror_copy(struct mecherror *dest, struct mecherror src)
+{
+ *dest = src;
+ if (src.mech.length > 0) {
+ dest->mech.elements = malloc(src.mech.length);
+ if (dest->mech.elements == NULL)
+ return ENOMEM;
+ memcpy(dest->mech.elements, src.mech.elements, src.mech.length);
+ } else {
+ dest->mech.elements = NULL;
+ }
+ return 0;
+}
+
+static void
+mecherror_print(struct mecherror value, FILE *f)
+{
+ OM_uint32 minor;
+ gss_buffer_desc str;
+ static const struct {
+ const char *oidstr, *name;
+ } mechnames[] = {
+ { "{ 1 2 840 113554 1 2 2 }", "krb5-new" },
+ { "{ 1 3 5 1 5 2 }", "krb5-old" },
+ { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" },
+ { "{ 1 3 6 1 5 5 2 }", "spnego" },
+ };
+ unsigned int i;
+
+ fprintf(f, "%lu@", (unsigned long) value.code);
+
+ if (value.mech.length == 0) {
+ fprintf(f, "(com_err)");
+ return;
+ }
+ fprintf(f, "%p=", value.mech.elements);
+ if (generic_gss_oid_to_str(&minor, &value.mech, &str)) {
+ fprintf(f, "(error in conversion)");
+ return;
+ }
+ /* Note: generic_gss_oid_to_str returns a null-terminated string. */
+ for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) {
+ if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) {
+ fprintf(f, "%s", mechnames[i].name);
+ break;
+ }
+ }
+ if (i == sizeof(mechnames)/sizeof(mechnames[0]))
+ fprintf(f, "%s", (char *) str.value);
+ generic_gss_release_buffer(&minor, &str);
+}
+
+#include "errmap.h"
+#include "krb5.h" /* for KRB5KRB_AP_WRONG_PRINC */
+
+static mecherrmap m;
+static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static OM_uint32 next_fake = 100000;
+
+int gssint_mecherrmap_init(void)
+{
+ int err;
+
+ err = mecherrmap_init(&m);
+ if (err)
+ return err;
+ err = k5_mutex_finish_init(&mutex);
+ if (err) {
+ mecherrmap_destroy(&m);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Currently the enumeration template doesn't handle freeing
+ element storage when destroying the collection. */
+static int free_one(OM_uint32 i, struct mecherror value, void *p)
+{
+ free(value.mech.elements);
+ return 0;
+}
+
+void gssint_mecherrmap_destroy(void)
+{
+ mecherrmap_foreach(&m, free_one, NULL);
+ mecherrmap_destroy(&m);
+ k5_mutex_destroy(&mutex);
+}
+
+OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid)
+{
+ const struct mecherror *mep;
+ struct mecherror me, me_copy;
+ const OM_uint32 *p;
+ int err;
+ OM_uint32 new_status;
+
+#ifdef DEBUG
+ FILE *f;
+ f = fopen("/dev/pts/9", "w+");
+ if (f == NULL)
+ f = stderr;
+#endif
+
+ me.code = minor;
+ me.mech = *oid;
+ k5_mutex_lock(&mutex);
+
+ /* Is this status+oid already mapped? */
+ p = mecherrmap_findright(&m, me);
+ if (p != NULL) {
+ k5_mutex_unlock(&mutex);
+#ifdef DEBUG
+ fprintf(f, "%s: found ", __FUNCTION__);
+ mecherror_print(me, f);
+ fprintf(f, " in map as %lu\n", (unsigned long) *p);
+ if (f != stderr) fclose(f);
+#endif
+ return *p;
+ }
+ /* Is this status code already mapped to something else
+ mech-specific? */
+ mep = mecherrmap_findleft(&m, minor);
+ if (mep == NULL) {
+ /* Map it to itself plus this mech-oid. */
+ new_status = minor;
+ } else {
+ /* Already assigned. Pick a fake new value and map it. */
+ /* There's a theoretical infinite loop risk here, if we fill
+ in 2**32 values. Also, returning 0 has a special
+ meaning. */
+ do {
+ next_fake++;
+ new_status = next_fake;
+ if (new_status == 0)
+ /* ??? */;
+ } while (mecherrmap_findleft(&m, new_status) != NULL);
+ }
+ err = mecherror_copy(&me_copy, me);
+ if (err) {
+ k5_mutex_unlock(&mutex);
+ return err;
+ }
+ err = mecherrmap_add(&m, new_status, me_copy);
+ k5_mutex_unlock(&mutex);
+ if (err)
+ free(me_copy.mech.elements);
+#ifdef DEBUG
+ fprintf(f, "%s: mapping ", __FUNCTION__);
+ mecherror_print(me, f);
+ fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err);
+ mecherrmap_printmap(&m, f);
+ fprintf(f, "\n");
+ if (f != stderr) fclose(f);
+#endif
+ if (err)
+ return 0;
+ else
+ return new_status;
+}
+
+static gss_OID_desc no_oid = { 0, 0 };
+OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode)
+{
+ return gssint_mecherrmap_map(errcode, &no_oid);
+}
+
+int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid,
+ OM_uint32 *mech_minor)
+{
+ const struct mecherror *p;
+
+ if (minor == 0) {
+ return EINVAL;
+ }
+ k5_mutex_lock(&mutex);
+ p = mecherrmap_findleft(&m, minor);
+ k5_mutex_unlock(&mutex);
+ if (!p) {
+ return EINVAL;
+ }
+ *mech_oid = p->mech;
+ *mech_minor = p->code;
+ return 0;
+}
diff --git a/src/lib/gssapi/generic/util_seqstate.c b/src/lib/gssapi/generic/util_seqstate.c
new file mode 100644
index 000000000000..a0bc2cc1c1d4
--- /dev/null
+++ b/src/lib/gssapi/generic/util_seqstate.c
@@ -0,0 +1,163 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/util_seqstate.c - sequence number checking */
+/*
+ * Copyright (C) 2014 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+
+struct g_seqnum_state_st {
+ /* Flags to indicate whether we are supposed to check for replays or
+ * enforce strict sequencing. */
+ int do_replay;
+ int do_sequence;
+
+ /* UINT32_MAX for 32-bit sequence numbers, UINT64_MAX for 64-bit. Mask
+ * against this after arithmetic to stay within the correct range. */
+ uint64_t seqmask;
+
+ /* The initial sequence number for this context. This value will be
+ * subtracted from all received sequence numbers to simplify wraparound. */
+ uint64_t base;
+
+ /* The expected next sequence number (one more than the highest previously
+ * seen sequence number), relative to base. */
+ uint64_t next;
+
+ /*
+ * A bitmap for the 64 sequence numbers prior to next. If the 1<<(i-1) bit
+ * is set, then we have seen seqnum next-i relative to base. The least
+ * significant bit is always set if we have received any sequence numbers,
+ * and indicates the highest sequence number we have seen (next-1). When
+ * we advance next, we shift recvmap to the left.
+ */
+ uint64_t recvmap;
+};
+
+long
+g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum, int do_replay,
+ int do_sequence, int wide)
+{
+ g_seqnum_state state;
+
+ *state_out = NULL;
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return ENOMEM;
+ state->do_replay = do_replay;
+ state->do_sequence = do_sequence;
+ state->seqmask = wide ? UINT64_MAX : UINT32_MAX;
+ state->base = seqnum;
+ state->next = state->recvmap = 0;
+ *state_out = state;
+ return 0;
+}
+
+OM_uint32
+g_seqstate_check(g_seqnum_state state, uint64_t seqnum)
+{
+ uint64_t rel_seqnum, offset, bit;
+
+ if (!state->do_replay && !state->do_sequence)
+ return GSS_S_COMPLETE;
+
+ /* Use the difference from the base seqnum, to simplify wraparound. */
+ rel_seqnum = (seqnum - state->base) & state->seqmask;
+
+ if (rel_seqnum >= state->next) {
+ /* seqnum is the expected sequence number or in the future. Update the
+ * received bitmap and expected next sequence number. */
+ offset = rel_seqnum - state->next;
+ state->recvmap = (state->recvmap << (offset + 1)) | 1;
+ state->next = (rel_seqnum + 1) & state->seqmask;
+
+ return (offset > 0 && state->do_sequence) ? GSS_S_GAP_TOKEN :
+ GSS_S_COMPLETE;
+ }
+
+ /* seqnum is in the past. Check if it's too old for replay detection. */
+ offset = state->next - rel_seqnum;
+ if (offset > 64)
+ return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_OLD_TOKEN;
+
+ /* Check for replay and mark as received. */
+ bit = (uint64_t)1 << (offset - 1);
+ if (state->do_replay && (state->recvmap & bit))
+ return GSS_S_DUPLICATE_TOKEN;
+ state->recvmap |= bit;
+
+ return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_COMPLETE;
+}
+
+void
+g_seqstate_free(g_seqnum_state state)
+{
+ free(state);
+}
+
+/*
+ * These support functions are for the serialization routines
+ */
+void
+g_seqstate_size(g_seqnum_state state, size_t *sizep)
+{
+ *sizep += sizeof(*state);
+}
+
+long
+g_seqstate_externalize(g_seqnum_state state, unsigned char **buf,
+ size_t *lenremain)
+{
+ if (*lenremain < sizeof(*state))
+ return ENOMEM;
+ memcpy(*buf, state, sizeof(*state));
+ *buf += sizeof(*state);
+ *lenremain -= sizeof(*state);
+ return 0;
+}
+
+long
+g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf,
+ size_t *lenremain)
+{
+ g_seqnum_state state;
+
+ *state_out = NULL;
+ if (*lenremain < sizeof(*state))
+ return EINVAL;
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return ENOMEM;
+ memcpy(state, *buf, sizeof(*state));
+ *buf += sizeof(*state);
+ *lenremain -= sizeof(*state);
+ *state_out = state;
+ return 0;
+}
diff --git a/src/lib/gssapi/generic/util_set.c b/src/lib/gssapi/generic/util_set.c
new file mode 100644
index 000000000000..8866f525fbc9
--- /dev/null
+++ b/src/lib/gssapi/generic/util_set.c
@@ -0,0 +1,106 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1995 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+
+struct _g_set_elt {
+ void *key;
+ void *value;
+ struct _g_set_elt *next;
+};
+
+int g_set_init(g_set_elt *s)
+{
+ *s = NULL;
+
+ return(0);
+}
+
+#if 0
+int g_set_destroy(g_set_elt *s)
+{
+ g_set next;
+
+ while (*s) {
+ next = (*s)->next;
+ free(*s);
+ *s = next;
+ }
+
+ return(0);
+}
+#endif
+
+int g_set_entry_add(g_set_elt *s, void *key, void *value)
+{
+ g_set_elt first;
+
+ if ((first = (struct _g_set_elt *) malloc(sizeof(struct _g_set_elt))) == NULL)
+ return(ENOMEM);
+
+ first->key = key;
+ first->value = value;
+ first->next = *s;
+
+ *s = first;
+
+ return(0);
+}
+
+int g_set_entry_delete(g_set_elt *s, void *key)
+{
+ g_set_elt *p;
+
+ for (p=s; *p; p = &((*p)->next)) {
+ if ((*p)->key == key) {
+ g_set_elt next = (*p)->next;
+ free(*p);
+ *p = next;
+
+ return(0);
+ }
+ }
+
+ return(-1);
+}
+
+int g_set_entry_get(g_set_elt *s, void *key, void **value)
+{
+ g_set_elt p;
+
+ for (p = *s; p; p = p->next) {
+ if (p->key == key) {
+ *value = p->value;
+
+ return(0);
+ }
+ }
+
+ *value = NULL;
+
+ return(-1);
+}
diff --git a/src/lib/gssapi/generic/util_token.c b/src/lib/gssapi/generic/util_token.c
new file mode 100644
index 000000000000..6e339f4ac7f7
--- /dev/null
+++ b/src/lib/gssapi/generic/util_token.c
@@ -0,0 +1,229 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_generic.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <limits.h>
+
+/*
+ * $Id$
+ */
+
+/* XXXX this code currently makes the assumption that a mech oid will
+ never be longer than 127 bytes. This assumption is not inherent in
+ the interfaces, so the code can be fixed if the OSI namespace
+ balloons unexpectedly. */
+
+/*
+ * Each token looks like this:
+ * 0x60 tag for APPLICATION 0, SEQUENCE
+ * (constructed, definite-length)
+ * <length> possible multiple bytes, need to parse/generate
+ * 0x06 tag for OBJECT IDENTIFIER
+ * <moid_length> compile-time constant string (assume 1 byte)
+ * <moid_bytes> compile-time constant string
+ * <inner_bytes> the ANY containing the application token
+ * bytes 0,1 are the token type
+ * bytes 2,n are the token data
+ *
+ * Note that the token type field is a feature of RFC 1964 mechanisms and
+ * is not used by other GSSAPI mechanisms. As such, a token type of -1
+ * is interpreted to mean that no token type should be expected or
+ * generated.
+ *
+ * For the purposes of this abstraction, the token "header" consists of
+ * the sequence tag and length octets, the mech OID DER encoding, and the
+ * first two inner bytes, which indicate the token type. The token
+ * "body" consists of everything else.
+ */
+static unsigned int
+der_length_size(int length)
+{
+ if (length < (1<<7))
+ return(1);
+ else if (length < (1<<8))
+ return(2);
+#if INT_MAX == 0x7fff
+ else
+ return(3);
+#else
+ else if (length < (1<<16))
+ return(3);
+ else if (length < (1<<24))
+ return(4);
+ else
+ return(5);
+#endif
+}
+
+static void
+der_write_length(unsigned char **buf, int length)
+{
+ if (length < (1<<7)) {
+ *(*buf)++ = (unsigned char) length;
+ } else {
+ *(*buf)++ = (unsigned char) (der_length_size(length)+127);
+#if INT_MAX > 0x7fff
+ if (length >= (1<<24))
+ *(*buf)++ = (unsigned char) (length>>24);
+ if (length >= (1<<16))
+ *(*buf)++ = (unsigned char) ((length>>16)&0xff);
+#endif
+ if (length >= (1<<8))
+ *(*buf)++ = (unsigned char) ((length>>8)&0xff);
+ *(*buf)++ = (unsigned char) (length&0xff);
+ }
+}
+
+/* returns decoded length, or < 0 on failure. Advances buf and
+ decrements bufsize */
+
+static int
+der_read_length(unsigned char **buf, int *bufsize)
+{
+ unsigned char sf;
+ int ret;
+
+ if (*bufsize < 1)
+ return(-1);
+ sf = *(*buf)++;
+ (*bufsize)--;
+ if (sf & 0x80) {
+ if ((sf &= 0x7f) > ((*bufsize)-1))
+ return(-1);
+ if (sf > sizeof(int))
+ return (-1);
+ ret = 0;
+ for (; sf; sf--) {
+ ret = (ret<<8) + (*(*buf)++);
+ (*bufsize)--;
+ }
+ } else {
+ ret = sf;
+ }
+
+ return(ret);
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+unsigned int
+g_token_size(const gss_OID_desc * mech, unsigned int body_size)
+{
+ /* set body_size to sequence contents size */
+ body_size += 4 + (unsigned int)mech->length; /* NEED overflow check */
+ return(1 + der_length_size(body_size) + body_size);
+}
+
+/* fills in a buffer with the token header. The buffer is assumed to
+ be the right size. buf is advanced past the token header */
+
+void
+g_make_token_header(
+ const gss_OID_desc * mech,
+ unsigned int body_size,
+ unsigned char **buf,
+ int tok_type)
+{
+ *(*buf)++ = 0x60;
+ der_write_length(buf, ((tok_type == -1) ? 2 : 4) + mech->length + body_size);
+ *(*buf)++ = 0x06;
+ *(*buf)++ = (unsigned char) mech->length;
+ TWRITE_STR(*buf, mech->elements, mech->length);
+ if (tok_type != -1) {
+ *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
+ *(*buf)++ = (unsigned char) (tok_type&0xff);
+ }
+}
+
+/*
+ * Given a buffer containing a token, reads and verifies the token,
+ * leaving buf advanced past the token header, and setting body_size
+ * to the number of remaining bytes. Returns 0 on success,
+ * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
+ * mechanism in the token does not match the mech argument. buf and
+ * *body_size are left unmodified on error.
+ */
+
+gss_int32
+g_verify_token_header(
+ const gss_OID_desc * mech,
+ unsigned int *body_size,
+ unsigned char **buf_in,
+ int tok_type,
+ unsigned int toksize_in,
+ int flags)
+{
+ unsigned char *buf = *buf_in;
+ int seqsize;
+ gss_OID_desc toid;
+ int toksize = toksize_in;
+
+ if ((toksize-=1) < 0)
+ return(G_BAD_TOK_HEADER);
+ if (*buf++ != 0x60) {
+ if (flags & G_VFY_TOKEN_HDR_WRAPPER_REQUIRED)
+ return(G_BAD_TOK_HEADER);
+ buf--;
+ toksize++;
+ goto skip_wrapper;
+ }
+
+ if ((seqsize = der_read_length(&buf, &toksize)) < 0)
+ return(G_BAD_TOK_HEADER);
+
+ if (seqsize != toksize)
+ return(G_BAD_TOK_HEADER);
+
+ if ((toksize-=1) < 0)
+ return(G_BAD_TOK_HEADER);
+ if (*buf++ != 0x06)
+ return(G_BAD_TOK_HEADER);
+
+ if ((toksize-=1) < 0)
+ return(G_BAD_TOK_HEADER);
+ toid.length = *buf++;
+
+ if ((toksize-=toid.length) < 0)
+ return(G_BAD_TOK_HEADER);
+ toid.elements = buf;
+ buf+=toid.length;
+
+ if (! g_OID_equal(&toid, mech))
+ return G_WRONG_MECH;
+skip_wrapper:
+ if (tok_type != -1) {
+ if ((toksize-=2) < 0)
+ return(G_BAD_TOK_HEADER);
+
+ if ((*buf++ != ((tok_type>>8)&0xff)) ||
+ (*buf++ != (tok_type&0xff)))
+ return(G_WRONG_TOKID);
+ }
+ *buf_in = buf;
+ *body_size = toksize;
+
+ return 0;
+}
diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
new file mode 100644
index 000000000000..364a7a4c9b25
--- /dev/null
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -0,0 +1,259 @@
+mydir=lib$(S)gssapi$(S)krb5
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+DEFINES=-D_GSS_STATIC_LINK=1
+
+#MODULE_INSTALL_DIR = $(GSS_MODULE_DIR)
+#LIBBASE=mech_krb5
+#LIBMAJOR=0
+#LIBMINOR=0
+#LIBINITFUNC=gss_krb5int_init
+#LIBFINIFUNC=gss_krb5int_fini
+#STOBJLISTS=../generic/OBJS.ST OBJS.ST
+#SUBDIROBJLISTS=../generic/OBJS.ST
+#SHLIB_EXPDEPS=$(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
+#SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
+#RELDIR=gssapi/krb5
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=krb5
+##DOS##OBJFILE = ..\$(OUTPRE)krb5.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+ETSRCS= gssapi_err_krb5.c
+ETOBJS= $(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+ETHDRS= gssapi_err_krb5.h
+
+$(OUTPRE)gssapi_err_krb5.$(OBJEXT): gssapi_err_krb5.c
+gssapi_err_krb5.h: gssapi_err_krb5.et
+gssapi_err_krb5.c: gssapi_err_krb5.et
+
+SRCS = \
+ $(srcdir)/accept_sec_context.c \
+ $(srcdir)/acquire_cred.c \
+ $(srcdir)/canon_name.c \
+ $(srcdir)/compare_name.c \
+ $(srcdir)/context_time.c \
+ $(srcdir)/copy_ccache.c \
+ $(srcdir)/cred_store.c \
+ $(srcdir)/delete_sec_context.c \
+ $(srcdir)/disp_name.c \
+ $(srcdir)/disp_status.c \
+ $(srcdir)/duplicate_name.c \
+ $(srcdir)/export_cred.c \
+ $(srcdir)/export_name.c \
+ $(srcdir)/export_sec_context.c \
+ $(srcdir)/get_tkt_flags.c \
+ $(srcdir)/gssapi_krb5.c \
+ $(srcdir)/iakerb.c \
+ $(srcdir)/import_cred.c \
+ $(srcdir)/import_name.c \
+ $(srcdir)/import_sec_context.c \
+ $(srcdir)/indicate_mechs.c \
+ $(srcdir)/init_sec_context.c \
+ $(srcdir)/inq_context.c \
+ $(srcdir)/inq_cred.c \
+ $(srcdir)/inq_names.c \
+ $(srcdir)/k5seal.c \
+ $(srcdir)/k5sealiov.c \
+ $(srcdir)/k5sealv3.c \
+ $(srcdir)/k5sealv3iov.c \
+ $(srcdir)/k5unseal.c \
+ $(srcdir)/k5unsealiov.c \
+ $(srcdir)/krb5_gss_glue.c \
+ $(srcdir)/lucid_context.c \
+ $(srcdir)/naming_exts.c \
+ $(srcdir)/prf.c \
+ $(srcdir)/process_context_token.c \
+ $(srcdir)/rel_cred.c \
+ $(srcdir)/rel_oid.c \
+ $(srcdir)/rel_name.c \
+ $(srcdir)/s4u_gss_glue.c \
+ $(srcdir)/set_allowable_enctypes.c \
+ $(srcdir)/ser_sctx.c \
+ $(srcdir)/set_ccache.c \
+ $(srcdir)/store_cred.c \
+ $(srcdir)/util_cksum.c \
+ $(srcdir)/util_crypt.c \
+ $(srcdir)/util_seed.c \
+ $(srcdir)/util_seqnum.c \
+ $(srcdir)/val_cred.c \
+ $(srcdir)/wrap_size_limit.c
+
+
+OBJS = \
+ $(OUTPRE)accept_sec_context.$(OBJEXT) \
+ $(OUTPRE)acquire_cred.$(OBJEXT) \
+ $(OUTPRE)canon_name.$(OBJEXT) \
+ $(OUTPRE)compare_name.$(OBJEXT) \
+ $(OUTPRE)context_time.$(OBJEXT) \
+ $(OUTPRE)copy_ccache.$(OBJEXT) \
+ $(OUTPRE)cred_store.$(OBJEXT) \
+ $(OUTPRE)delete_sec_context.$(OBJEXT) \
+ $(OUTPRE)disp_name.$(OBJEXT) \
+ $(OUTPRE)disp_status.$(OBJEXT) \
+ $(OUTPRE)duplicate_name.$(OBJEXT) \
+ $(OUTPRE)export_cred.$(OBJEXT) \
+ $(OUTPRE)export_name.$(OBJEXT) \
+ $(OUTPRE)export_sec_context.$(OBJEXT) \
+ $(OUTPRE)get_tkt_flags.$(OBJEXT) \
+ $(OUTPRE)gssapi_krb5.$(OBJEXT) \
+ $(OUTPRE)iakerb.$(OBJEXT) \
+ $(OUTPRE)import_cred.$(OBJEXT) \
+ $(OUTPRE)import_name.$(OBJEXT) \
+ $(OUTPRE)import_sec_context.$(OBJEXT) \
+ $(OUTPRE)indicate_mechs.$(OBJEXT) \
+ $(OUTPRE)init_sec_context.$(OBJEXT) \
+ $(OUTPRE)inq_context.$(OBJEXT) \
+ $(OUTPRE)inq_cred.$(OBJEXT) \
+ $(OUTPRE)inq_names.$(OBJEXT) \
+ $(OUTPRE)k5seal.$(OBJEXT) \
+ $(OUTPRE)k5sealiov.$(OBJEXT) \
+ $(OUTPRE)k5sealv3.$(OBJEXT) \
+ $(OUTPRE)k5sealv3iov.$(OBJEXT) \
+ $(OUTPRE)k5unseal.$(OBJEXT) \
+ $(OUTPRE)k5unsealiov.$(OBJEXT) \
+ $(OUTPRE)krb5_gss_glue.$(OBJEXT) \
+ $(OUTPRE)lucid_context.$(OBJEXT) \
+ $(OUTPRE)naming_exts.$(OBJEXT) \
+ $(OUTPRE)prf.$(OBJEXT) \
+ $(OUTPRE)process_context_token.$(OBJEXT) \
+ $(OUTPRE)rel_cred.$(OBJEXT) \
+ $(OUTPRE)rel_oid.$(OBJEXT) \
+ $(OUTPRE)rel_name.$(OBJEXT) \
+ $(OUTPRE)s4u_gss_glue.$(OBJEXT) \
+ $(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
+ $(OUTPRE)ser_sctx.$(OBJEXT) \
+ $(OUTPRE)set_ccache.$(OBJEXT) \
+ $(OUTPRE)store_cred.$(OBJEXT) \
+ $(OUTPRE)util_cksum.$(OBJEXT) \
+ $(OUTPRE)util_crypt.$(OBJEXT) \
+ $(OUTPRE)util_seed.$(OBJEXT) \
+ $(OUTPRE)util_seqnum.$(OBJEXT) \
+ $(OUTPRE)val_cred.$(OBJEXT) \
+ $(OUTPRE)wrap_size_limit.$(OBJEXT) \
+ $(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+
+# k5mech.$(OBJEXT) \
+# pname_to_uid.$(OBJEXT)
+
+STLIBOBJS = \
+ accept_sec_context.o \
+ acquire_cred.o \
+ canon_name.o \
+ compare_name.o \
+ context_time.o \
+ copy_ccache.o \
+ cred_store.o \
+ delete_sec_context.o \
+ disp_name.o \
+ disp_status.o \
+ duplicate_name.o \
+ export_cred.o \
+ export_name.o \
+ export_sec_context.o \
+ get_tkt_flags.o \
+ gssapi_krb5.o \
+ iakerb.o \
+ import_cred.o \
+ import_name.o \
+ import_sec_context.o \
+ indicate_mechs.o \
+ init_sec_context.o \
+ inq_context.o \
+ inq_cred.o \
+ inq_names.o \
+ k5seal.o \
+ k5sealiov.o \
+ k5sealv3.o \
+ k5sealv3iov.o \
+ k5unseal.o \
+ k5unsealiov.o \
+ krb5_gss_glue.o \
+ lucid_context.o \
+ naming_exts.o \
+ prf.o \
+ process_context_token.o \
+ rel_cred.o \
+ rel_oid.o \
+ rel_name.o \
+ s4u_gss_glue.o \
+ set_allowable_enctypes.o \
+ ser_sctx.o \
+ set_ccache.o \
+ store_cred.o \
+ util_cksum.o \
+ util_crypt.o \
+ util_seed.o \
+ util_seqnum.o \
+ val_cred.o \
+ wrap_size_limit.o \
+ gssapi_err_krb5.o
+
+# k5mech.o \
+# pname_to_uid.o
+
+HDRS= $(ETHDRS)
+
+EHDRDIR=$(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS= gssapi_krb5.h
+
+##DOS##LIBOBJS = $(OBJS)
+
+GSSAPI_KRB5_HDR=$(EHDRDIR)$(S)gssapi_krb5.h
+
+all-windows: $(EHDRDIR) $(GSSAPI_KRB5_HDR) $(SRCS) $(HDRS)
+
+##DOS##$(EHDRDIR):
+##DOS## mkdir $(EHDRDIR)
+
+MK_EHDRDIR=if test -d $(EHDRDIR); then :; else (set -x; mkdir $(EHDRDIR)); fi
+##DOS##MK_EHDRDIR=rem
+
+$(GSSAPI_KRB5_HDR): $(srcdir)$(S)gssapi_krb5.h
+ @$(MK_EHDRDIR)
+ $(CP) $(srcdir)$(S)gssapi_krb5.h "$@"
+
+all-unix: $(SRCS) $(HDRS) $(GSSAPI_KRB5_HDR)
+all-unix: all-libobjs
+
+error_map.h: $(top_srcdir)/util/gen-map.pl \
+ $(top_srcdir)/util/ktemplate.pm Makefile
+ $(PERL) -I$(top_srcdir)/util $(top_srcdir)/util/gen-map.pl \
+ -oerror_map.new \
+ NAME=gsserrmap \
+ KEY=OM_uint32 \
+ VALUE="char *" \
+ COMPARE=compare_OM_uint32 \
+ FREEVALUE=free_string
+ $(RM) $@
+ $(MV) error_map.new $@
+
+clean-unix::
+ $(RM) $(BUILDTOP)/include/gssapi/gssapi_krb5.h
+ -$(RM) error_map.h
+
+clean-unix:: clean-libobjs
+ $(RM) $(ETHDRS) $(ETSRCS)
+
+clean-windows::
+ $(RM) $(EHDRDIR)\gssapi_krb5.h
+ $(RM) error_map.h
+ -if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+
+generate-files-mac: error_map.h
+
+install-headers-unix install:
+ @set -x; for f in $(EXPORTED_HEADERS) ; \
+ do $(INSTALL_DATA) $(srcdir)/$$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+ done
+
+depend: $(ETSRCS) $(ETHDRS) $(GSSAPI_KRB5_HDR) error_map.h
+
+install:
+
+@libobj_frag@
+
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
new file mode 100644
index 000000000000..580d08cbf53e
--- /dev/null
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -0,0 +1,1347 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2004, 2007, 2008 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 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+#ifdef CFX_EXERCISE
+#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
+#else
+#define CFX_ACCEPTOR_SUBKEY 1
+#endif
+
+#ifndef LEAN_CLIENT
+
+static OM_uint32
+create_constrained_deleg_creds(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t verifier_cred_handle,
+ krb5_ticket *ticket,
+ krb5_gss_cred_id_t *out_cred,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_creds krb_creds;
+ krb5_data *data;
+ krb5_error_code code;
+
+ assert(out_cred != NULL);
+ assert(verifier_cred_handle->usage == GSS_C_BOTH);
+
+ memset(&krb_creds, 0, sizeof(krb_creds));
+ krb_creds.client = ticket->enc_part2->client;
+ krb_creds.server = ticket->server;
+ krb_creds.keyblock = *(ticket->enc_part2->session);
+ krb_creds.ticket_flags = ticket->enc_part2->flags;
+ krb_creds.times = ticket->enc_part2->times;
+ krb_creds.magic = KV5M_CREDS;
+ krb_creds.authdata = NULL;
+
+ code = encode_krb5_ticket(ticket, &data);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ krb_creds.ticket = *data;
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ verifier_cred_handle,
+ &krb_creds,
+ GSS_C_INDEFINITE,
+ out_cred,
+ NULL,
+ context);
+
+ krb5_free_data(context, data);
+
+ return major_status;
+}
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+static krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
+ krb5_context context;
+ krb5_auth_context auth_context;
+ krb5_data *inbuf;
+ krb5_gss_cred_id_t *out_cred;
+{
+ krb5_creds ** creds = NULL;
+ krb5_error_code retval;
+ krb5_ccache ccache = NULL;
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_auth_context new_auth_ctx = NULL;
+ krb5_int32 flags_org;
+
+ if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
+ return retval;
+ krb5_auth_con_setflags(context, auth_context,
+ 0);
+
+ /*
+ * By the time krb5_rd_cred is called here (after krb5_rd_req has been
+ * called in krb5_gss_accept_sec_context), the "keyblock" field of
+ * auth_context contains a pointer to the session key, and the
+ * "recv_subkey" field might contain a session subkey. Either of
+ * these (the "recv_subkey" if it isn't NULL, otherwise the
+ * "keyblock") might have been used to encrypt the encrypted part of
+ * the KRB_CRED message that contains the forwarded credentials. (The
+ * Java Crypto and Security Implementation from the DSTC in Australia
+ * always uses the session key. But apparently it never negotiates a
+ * subkey, so this code works fine against a JCSI client.) Up to the
+ * present, though, GSSAPI clients linked against the MIT code (which
+ * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
+ * all -- at this level. So if the first call to krb5_rd_cred fails,
+ * we should call it a second time with another auth context freshly
+ * created by krb5_auth_con_init. All of its keyblock fields will be
+ * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
+ * unencrypted. (The MIT code doesn't actually send the KRB_CRED
+ * message in the clear -- the "authenticator" whose "checksum" ends up
+ * containing the KRB_CRED message does get encrypted.)
+ */
+ if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
+ if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
+ goto cleanup;
+ krb5_auth_con_setflags(context, new_auth_ctx, 0);
+ if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
+ &creds, NULL)))
+ goto cleanup;
+ }
+
+ if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
+ ccache = NULL;
+ goto cleanup;
+ }
+
+ if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
+ goto cleanup;
+
+ if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+ goto cleanup;
+
+ /* generate a delegated credential handle */
+ if (out_cred) {
+ /* allocate memory for a cred_t... */
+ if (!(cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
+ retval = ENOMEM; /* out of memory? */
+ goto cleanup;
+ }
+
+ /* zero it out... */
+ memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+ retval = k5_mutex_init(&cred->lock);
+ if (retval) {
+ xfree(cred);
+ cred = NULL;
+ goto cleanup;
+ }
+
+ /* copy the client principle into it... */
+ if ((retval =
+ kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
+ &cred->name))) {
+ k5_mutex_destroy(&cred->lock);
+ retval = ENOMEM; /* out of memory? */
+ xfree(cred); /* clean up memory on failure */
+ cred = NULL;
+ goto cleanup;
+ }
+
+ cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+ /* cred->name already set */
+ cred->keytab = NULL; /* no keytab associated with this... */
+ cred->expire = creds[0]->times.endtime; /* store the end time */
+ cred->ccache = ccache; /* the ccache containing the credential */
+ cred->destroy_ccache = 1;
+ ccache = NULL; /* cred takes ownership so don't destroy */
+ }
+
+ /* If there were errors, there might have been a memory leak
+ if (!cred)
+ if ((retval = krb5_cc_close(context, ccache)))
+ goto cleanup;
+ */
+cleanup:
+ if (creds)
+ krb5_free_tgt_creds(context, creds);
+
+ if (ccache)
+ (void)krb5_cc_destroy(context, ccache);
+
+ if (out_cred)
+ *out_cred = cred; /* return credential */
+
+ if (new_auth_ctx)
+ krb5_auth_con_free(context, new_auth_ctx);
+
+ krb5_auth_con_setflags(context, auth_context, flags_org);
+
+ return retval;
+}
+
+
+/*
+ * Performs third leg of DCE authentication
+ */
+static OM_uint32
+kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
+ input_token, input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec, delegated_cred_handle)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+{
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx = 0;
+ krb5_timestamp now;
+ krb5_gss_name_t name = NULL;
+ krb5_ui_4 nonce = 0;
+ krb5_data ap_rep;
+ OM_uint32 major_status = GSS_S_FAILURE;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (mech_type)
+ *mech_type = GSS_C_NULL_OID;
+ /* return a bogus cred handle */
+ if (delegated_cred_handle)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ ctx = (krb5_gss_ctx_id_rec *)*context_handle;
+
+ code = krb5_timeofday(ctx->k5_context, &now);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ap_rep.data = input_token->value;
+ ap_rep.length = input_token->length;
+
+ code = krb5_rd_rep_dce(ctx->k5_context,
+ ctx->auth_context,
+ &ap_rep,
+ &nonce);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ctx->established = 1;
+
+ if (src_name) {
+ code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ *src_name = (gss_name_t) name;
+ }
+
+ if (mech_type)
+ *mech_type = ctx->mech_used;
+
+ if (time_rec)
+ *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
+
+ /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
+ * delegation yet. */
+ if (ret_flags)
+ *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+
+fail:
+ /* real failure code follows */
+
+ (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
+ NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+ *minor_status = code;
+
+ return major_status;
+}
+
+static krb5_error_code
+kg_process_extension(krb5_context context,
+ krb5_auth_context auth_context,
+ int ext_type,
+ krb5_data *ext_data,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_error_code code = 0;
+
+ assert(exts != NULL);
+
+ switch (ext_type) {
+ case KRB5_GSS_EXTS_IAKERB_FINISHED:
+ if (exts->iakerb.conv == NULL) {
+ code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
+ } else {
+ krb5_key key;
+
+ code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ break;
+
+ code = iakerb_verify_finished(context, key, exts->iakerb.conv,
+ ext_data);
+ if (code == 0)
+ exts->iakerb.verified = 1;
+
+ krb5_k_free_key(context, key);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return code;
+}
+
+static OM_uint32
+kg_accept_krb5(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle, exts)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+ krb5_gss_ctx_ext_t exts;
+{
+ krb5_context context;
+ unsigned char *ptr, *ptr2;
+ char *sptr;
+ OM_uint32 tmp;
+ size_t md5len;
+ krb5_gss_cred_id_t cred = 0;
+ krb5_data ap_rep, ap_req;
+ unsigned int i;
+ krb5_error_code code;
+ krb5_address addr, *paddr;
+ krb5_authenticator *authdat = 0;
+ krb5_checksum reqcksum;
+ krb5_gss_name_t name = NULL;
+ krb5_ui_4 gss_flags = 0;
+ krb5_gss_ctx_id_rec *ctx = NULL;
+ krb5_timestamp now;
+ gss_buffer_desc token;
+ krb5_auth_context auth_context = NULL;
+ krb5_ticket * ticket = NULL;
+ int option_id;
+ krb5_data option;
+ const gss_OID_desc *mech_used = NULL;
+ OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 tmp_minor_status;
+ krb5_error krb_error_data;
+ krb5_data scratch;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t deleg_cred = NULL;
+ krb5int_access kaccess;
+ int cred_rcache = 0;
+ int no_encap = 0;
+ int token_deleg_flag = 0;
+ krb5_flags ap_req_options = 0;
+ krb5_enctype negotiated_etype;
+ krb5_authdata_context ad_context = NULL;
+ krb5_principal accprinc = NULL;
+ krb5_ap_req *request = NULL;
+
+ code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (code) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* set up returns to be freeable */
+
+ if (src_name)
+ *src_name = (gss_name_t) NULL;
+ output_token->length = 0;
+ output_token->value = NULL;
+ token.value = 0;
+ reqcksum.contents = 0;
+ ap_req.data = 0;
+ ap_rep.data = 0;
+
+ if (mech_type)
+ *mech_type = GSS_C_NULL_OID;
+ /* return a bogus cred handle */
+ if (delegated_cred_handle)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ /* handle default cred handle */
+ if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
+ GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_ACCEPT, &defcred,
+ NULL, NULL);
+ if (major_status != GSS_S_COMPLETE) {
+ code = *minor_status;
+ goto fail;
+ }
+ verifier_cred_handle = defcred;
+ }
+
+ /* Resolve any initiator state in the verifier cred and lock it. */
+ major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
+ GSS_C_NO_NAME);
+ if (GSS_ERROR(major_status)) {
+ code = *minor_status;
+ goto fail;
+ }
+ cred = (krb5_gss_cred_id_t)verifier_cred_handle;
+
+ /* make sure the supplied credentials are valid for accept */
+
+ if ((cred->usage != GSS_C_ACCEPT) &&
+ (cred->usage != GSS_C_BOTH)) {
+ code = 0;
+ major_status = GSS_S_NO_CRED;
+ goto fail;
+ }
+
+ /* verify the token's integrity, and leave the token in ap_req.
+ figure out which mech oid was used, and save it */
+
+ ptr = (unsigned char *) input_token->value;
+
+ if (!(code = g_verify_token_header(gss_mech_krb5,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_krb5;
+ } else if ((code == G_WRONG_MECH)
+ &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_iakerb;
+ } else if ((code == G_WRONG_MECH)
+ &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_krb5_wrong;
+ } else if ((code == G_WRONG_MECH) &&
+ !(code = g_verify_token_header(gss_mech_krb5_old,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ /*
+ * Previous versions of this library used the old mech_id
+ * and some broken behavior (wrong IV on checksum
+ * encryption). We support the old mech_id for
+ * compatibility, and use it to decide when to use the
+ * old behavior.
+ */
+ mech_used = gss_mech_krb5_old;
+ } else if (code == G_WRONG_TOKID) {
+ major_status = GSS_S_CONTINUE_NEEDED;
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
+ mech_used = gss_mech_krb5;
+ goto fail;
+ } else if (code == G_BAD_TOK_HEADER) {
+ /* DCE style not encapsulated */
+ ap_req.length = input_token->length;
+ ap_req.data = input_token->value;
+ mech_used = gss_mech_krb5;
+ no_encap = 1;
+ } else {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ sptr = (char *) ptr;
+ TREAD_STR(sptr, ap_req.data, ap_req.length);
+
+ /* construct the sender_addr */
+
+ if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
+ (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
+ /* XXX is this right? */
+ addr.addrtype = ADDRTYPE_INET;
+ addr.length = input_chan_bindings->initiator_address.length;
+ addr.contents = input_chan_bindings->initiator_address.value;
+
+ paddr = &addr;
+ } else {
+ paddr = NULL;
+ }
+
+ /* decode the AP_REQ message */
+ code = decode_krb5_ap_req(&ap_req, &request);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto done;
+ }
+ ticket = request->ticket;
+
+ /* decode the message */
+
+ if ((code = krb5_auth_con_init(context, &auth_context))) {
+ major_status = GSS_S_FAILURE;
+ save_error_info((OM_uint32)code, context);
+ goto fail;
+ }
+ if (cred->rcache) {
+ cred_rcache = 1;
+ if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Limit the encryption types negotiated (if requested). */
+ if (cred->req_enctypes) {
+ if ((code = krb5_auth_con_setpermetypes(context, auth_context,
+ cred->req_enctypes))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (!cred->default_identity) {
+ if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
+ cred->keytab, &ap_req_options, NULL);
+
+ krb5_free_principal(context, accprinc);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ krb5_auth_con_setflags(context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+ krb5_auth_con_getauthenticator(context, auth_context, &authdat);
+
+#if 0
+ /* make sure the necessary parts of the authdat are present */
+
+ if ((authdat->authenticator->subkey == NULL) ||
+ (authdat->ticket->enc_part2 == NULL)) {
+ code = KG_NO_SUBKEY;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+#endif
+
+ if (authdat->checksum == NULL) {
+ /*
+ * Some SMB client implementations use handcrafted GSSAPI code that
+ * does not provide a checksum. MS-KILE documents that the Microsoft
+ * implementation considers a missing checksum acceptable; the server
+ * assumes all flags are unset in this case, and does not check channel
+ * bindings.
+ */
+ gss_flags = 0;
+ } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
+ /* Samba does not send 0x8003 GSS-API checksums */
+ krb5_boolean valid;
+ krb5_key subkey;
+ krb5_data zero;
+
+ code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ zero.length = 0;
+ zero.data = "";
+
+ code = krb5_k_verify_checksum(context,
+ subkey,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+ &zero,
+ authdat->checksum,
+ &valid);
+ krb5_k_free_key(context, subkey);
+ if (code || !valid) {
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* Use ap_options from the request to guess the mutual flag. */
+ gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
+ gss_flags |= GSS_C_MUTUAL_FLAG;
+ } else {
+ /* gss krb5 v1 */
+
+ /* stash this now, for later. */
+ code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* verify that the checksum is correct */
+
+ /*
+ The checksum may be either exactly 24 bytes, in which case
+ no options are specified, or greater than 24 bytes, in which case
+ one or more options are specified. Currently, the only valid
+ option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
+ */
+
+ if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
+ (authdat->checksum->length < 24)) {
+ code = 0;
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ ptr = (unsigned char *) authdat->checksum->contents;
+
+ TREAD_INT(ptr, tmp, 0);
+
+ if (tmp != md5len) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /*
+ The following section of code attempts to implement the
+ optional channel binding facility as described in RFC2743.
+
+ Since this facility is optional channel binding may or may
+ not have been provided by either the client or the server.
+
+ If the server has specified input_chan_bindings equal to
+ GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
+ the server does provide channel bindings then we compute
+ a checksum and compare against those provided by the
+ client. */
+
+ if ((code = kg_checksum_channel_bindings(context,
+ input_chan_bindings,
+ &reqcksum))) {
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ /* Always read the clients bindings - eventhough we might ignore them */
+ TREAD_STR(ptr, ptr2, reqcksum.length);
+
+ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
+ if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
+ xfree(reqcksum.contents);
+ reqcksum.contents = 0;
+ code = 0;
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ }
+
+ xfree(reqcksum.contents);
+ reqcksum.contents = 0;
+
+ /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
+ * mask it out until we actually read a delegated credential. */
+ TREAD_INT(ptr, gss_flags, 0);
+ token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
+ gss_flags &= ~GSS_C_DELEG_FLAG;
+
+ /* if the checksum length > 24, there are options to process */
+
+ i = authdat->checksum->length - 24;
+ if (i && token_deleg_flag) {
+ if (i >= 4) {
+ TREAD_INT16(ptr, option_id, 0);
+ TREAD_INT16(ptr, option.length, 0);
+ i -= 4;
+
+ if (i < option.length) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* have to use ptr2, since option.data is wrong type and
+ macro uses ptr as both lvalue and rvalue */
+
+ TREAD_STR(ptr, ptr2, option.length);
+ option.data = (char *) ptr2;
+
+ i -= option.length;
+
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* store the delegated credential */
+
+ code = rd_and_store_for_creds(context, auth_context, &option,
+ (delegated_cred_handle) ?
+ &deleg_cred : NULL);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ gss_flags |= GSS_C_DELEG_FLAG;
+ } /* if i >= 4 */
+ /* ignore any additional trailing data, for now */
+ }
+ while (i > 0) {
+ /* Process Type-Length-Data options */
+ if (i < 8) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ TREAD_INT(ptr, option_id, 1);
+ TREAD_INT(ptr, option.length, 1);
+ i -= 8;
+ if (i < option.length) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ TREAD_STR(ptr, ptr2, option.length);
+ option.data = (char *)ptr2;
+
+ i -= option.length;
+
+ code = kg_process_extension(context, auth_context,
+ option_id, &option, exts);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ if (exts->iakerb.conv && !exts->iakerb.verified) {
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* only DCE_STYLE clients are allowed to send raw AP-REQs */
+ if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ /* create the ctx struct and start filling it in */
+
+ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+ == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
+ ctx->mech_used = (gss_OID) mech_used;
+ ctx->auth_context = auth_context;
+ ctx->initiate = 0;
+ ctx->gss_flags = (GSS_C_TRANS_FLAG |
+ ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
+ GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
+ GSS_C_EXTENDED_ERROR_FLAG)));
+ ctx->seed_init = 0;
+ ctx->cred_rcache = cred_rcache;
+
+ /* XXX move this into gss_name_t */
+ if ( (code = krb5_merge_authdata(context,
+ ticket->enc_part2->authorization_data,
+ authdat->authorization_data,
+ &ctx->authdata))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
+ &ctx->here))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
+ &ad_context))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = kg_init_name(context, authdat->client, NULL, NULL,
+ ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ /* Now owned by ctx->there */
+ authdat->client = NULL;
+ krb5_auth_con_set_authdata_context(context, auth_context, NULL);
+
+ if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* use the session key if the subkey isn't present */
+
+ if (ctx->subkey == NULL) {
+ if ((code = krb5_auth_con_getkey_k(context, auth_context,
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (ctx->subkey == NULL) {
+ /* this isn't a very good error, but it's not clear to me this
+ can actually happen */
+ major_status = GSS_S_FAILURE;
+ code = KRB5KDC_ERR_NULL_KEY;
+ goto fail;
+ }
+
+ ctx->enc = NULL;
+ ctx->seq = NULL;
+ ctx->have_acceptor_subkey = 0;
+ /* DCE_STYLE implies acceptor_subkey */
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+ code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ ctx->krb_times = ticket->enc_part2->times; /* struct copy */
+ ctx->krb_flags = ticket->enc_part2->flags;
+
+ if (delegated_cred_handle != NULL &&
+ deleg_cred == NULL && /* no unconstrained delegation */
+ cred->usage == GSS_C_BOTH &&
+ (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ /*
+ * Now, we always fabricate a delegated credentials handle
+ * containing the service ticket to ourselves, which can be
+ * used for S4U2Proxy.
+ */
+ major_status = create_constrained_deleg_creds(minor_status, cred,
+ ticket, &deleg_cred,
+ context);
+ if (GSS_ERROR(major_status))
+ goto fail;
+ ctx->gss_flags |= GSS_C_DELEG_FLAG;
+ }
+
+ {
+ krb5_int32 seq_temp;
+ krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_recv = seq_temp;
+ }
+
+ if ((code = krb5_timeofday(context, &now))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* DCE_STYLE implies mutual authentication */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
+
+ /* at this point, the entire context structure is filled in,
+ so it can be released. */
+
+ /* generate an AP_REP if necessary */
+
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+ unsigned char * ptr3;
+ krb5_int32 seq_temp;
+ int cfx_generate_subkey;
+
+ /*
+ * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
+ * because pre-CFX tokens do not indicate which key to use. (Note that
+ * DCE_STYLE implies that we will use a subkey.)
+ */
+ if (ctx->proto == 0 &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+ (ap_req_options & AP_OPTS_USE_SUBKEY)) {
+ code = (*kaccess.auth_con_get_subkey_enctype)(context,
+ auth_context,
+ &negotiated_etype);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ switch (negotiated_etype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
+ * enctype, even though RFC 4757 treats it as one. */
+ ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
+ break;
+ }
+ }
+
+ if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
+ (ap_req_options & AP_OPTS_USE_SUBKEY))
+ cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
+ else
+ cfx_generate_subkey = 0;
+
+ if (cfx_generate_subkey) {
+ krb5_int32 acflags;
+ code = krb5_auth_con_getflags(context, auth_context, &acflags);
+ if (code == 0) {
+ acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
+ code = krb5_auth_con_setflags(context, auth_context, acflags);
+ }
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_send = seq_temp & 0xffffffffL;
+
+ if (cfx_generate_subkey) {
+ /* Get the new acceptor subkey. With the code above, there
+ should always be one if we make it to this point. */
+ code = krb5_auth_con_getsendsubkey_k(context, auth_context,
+ &ctx->acceptor_subkey);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ ctx->have_acceptor_subkey = 1;
+
+ code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
+ &ctx->acceptor_subkey_cksumtype);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* the reply token hasn't been sent yet, but that's ok. */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ assert(ctx->have_acceptor_subkey);
+
+ /* in order to force acceptor subkey to be used, don't set PROT_READY */
+
+ /* Raw AP-REP is returned */
+ code = data_to_gss(&ap_rep, output_token);
+ if (code)
+ {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ctx->established = 0;
+
+ *context_handle = (gss_ctx_id_t)ctx;
+ *minor_status = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+
+ /* Only last leg should set return arguments */
+ goto fail;
+ } else
+ ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+
+ ctx->established = 1;
+
+ token.length = g_token_size(mech_used, ap_rep.length);
+
+ if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
+ == NULL) {
+ major_status = GSS_S_FAILURE;
+ code = ENOMEM;
+ goto fail;
+ }
+ ptr3 = token.value;
+ g_make_token_header(mech_used, ap_rep.length,
+ &ptr3, KG_TOK_CTX_AP_REP);
+
+ TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
+
+ ctx->established = 1;
+
+ } else {
+ token.length = 0;
+ token.value = NULL;
+ ctx->seq_send = ctx->seq_recv;
+
+ ctx->established = 1;
+ }
+
+ /* set the return arguments */
+
+ if (src_name) {
+ code = kg_duplicate_name(context, ctx->there, &name);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (mech_type)
+ *mech_type = (gss_OID) mech_used;
+
+ /* Add the maximum allowable clock skew as a grace period for context
+ * expiration, just as we do for the ticket. */
+ if (time_rec)
+ *time_rec = ctx->krb_times.endtime + context->clockskew - now;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ *context_handle = (gss_ctx_id_t)ctx;
+ *output_token = token;
+
+ if (src_name)
+ *src_name = (gss_name_t) name;
+
+ if (delegated_cred_handle)
+ *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
+
+ /* finally! */
+
+ *minor_status = 0;
+ major_status = GSS_S_COMPLETE;
+
+fail:
+ if (authdat)
+ krb5_free_authenticator(context, authdat);
+ /* The ctx structure has the handle of the auth_context */
+ if (auth_context && !ctx) {
+ if (cred_rcache)
+ (void)krb5_auth_con_setrcache(context, auth_context, NULL);
+
+ krb5_auth_con_free(context, auth_context);
+ }
+ if (reqcksum.contents)
+ xfree(reqcksum.contents);
+ if (ap_rep.data)
+ krb5_free_data_contents(context, &ap_rep);
+ if (major_status == GSS_S_COMPLETE ||
+ (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
+ ctx->k5_context = context;
+ context = NULL;
+ goto done;
+ }
+
+ /* from here on is the real "fail" code */
+
+ if (ctx)
+ (void) krb5_gss_delete_sec_context(&tmp_minor_status,
+ (gss_ctx_id_t *) &ctx, NULL);
+ if (deleg_cred) { /* free memory associated with the deleg credential */
+ if (deleg_cred->ccache)
+ (void)krb5_cc_close(context, deleg_cred->ccache);
+ if (deleg_cred->name)
+ kg_release_name(context, &deleg_cred->name);
+ xfree(deleg_cred);
+ }
+ if (token.value)
+ xfree(token.value);
+ if (name) {
+ (void) kg_release_name(context, &name);
+ }
+
+ *minor_status = code;
+
+ /* We may have failed before being able to read the GSS flags from the
+ * authenticator, so also check the request AP options. */
+ if (cred != NULL && request != NULL &&
+ ((gss_flags & GSS_C_MUTUAL_FLAG) ||
+ (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
+ major_status == GSS_S_CONTINUE_NEEDED)) {
+ unsigned int tmsglen;
+ int toktype;
+
+ /*
+ * The client is expecting a response, so we can send an
+ * error token back
+ */
+ memset(&krb_error_data, 0, sizeof(krb_error_data));
+
+ code -= ERROR_TABLE_BASE_krb5;
+ if (code < 0 || code > KRB_ERR_MAX)
+ code = 60 /* KRB_ERR_GENERIC */;
+
+ krb_error_data.error = code;
+ (void) krb5_us_timeofday(context, &krb_error_data.stime,
+ &krb_error_data.susec);
+
+ krb_error_data.server = ticket->server;
+ code = krb5_mk_error(context, &krb_error_data, &scratch);
+ if (code)
+ goto done;
+
+ tmsglen = scratch.length;
+ toktype = KG_TOK_CTX_ERROR;
+
+ token.length = g_token_size(mech_used, tmsglen);
+ token.value = gssalloc_malloc(token.length);
+ if (!token.value)
+ goto done;
+
+ ptr = token.value;
+ g_make_token_header(mech_used, tmsglen, &ptr, toktype);
+
+ TWRITE_STR(ptr, scratch.data, scratch.length);
+ krb5_free_data_contents(context, &scratch);
+
+ *output_token = token;
+ }
+
+done:
+ krb5_free_ap_req(context, request);
+ if (cred)
+ k5_mutex_unlock(&cred->lock);
+ if (defcred)
+ krb5_gss_release_cred(&tmp_minor_status, &defcred);
+ if (context) {
+ if (major_status && *minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ }
+ return (major_status);
+}
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_accept_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
+
+ /*
+ * Context handle must be unspecified. Actually, it must be
+ * non-established, but currently, accept_sec_context never returns
+ * a non-established context handle.
+ */
+ /*SUPPRESS 29*/
+ if (ctx != NULL) {
+ if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ return kg_accept_dce(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle);
+ } else {
+ *minor_status = EINVAL;
+ save_error_string(EINVAL, "accept_sec_context called with existing context handle");
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return kg_accept_krb5(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle, exts);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_accept_sec_context(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_accept_sec_context_ext(minor_status,
+ context_handle,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+}
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
new file mode 100644
index 000000000000..03ee25ec1861
--- /dev/null
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -0,0 +1,1261 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2007-2010 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 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef USE_LEASH
+#ifdef _WIN64
+#define LEASH_DLL "leashw64.dll"
+#else
+#define LEASH_DLL "leashw32.dll"
+#endif
+static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
+static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
+#endif
+
+#ifndef LEAN_CLIENT
+k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+static char *krb5_gss_keytab = NULL;
+
+/* Heimdal calls this gsskrb5_register_acceptor_identity. */
+OM_uint32
+gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ char *new = NULL, *old;
+ int err;
+
+ err = gss_krb5int_initialize_library();
+ if (err != 0)
+ return GSS_S_FAILURE;
+
+ if (value->value != NULL) {
+ new = strdup((char *)value->value);
+ if (new == NULL)
+ return GSS_S_FAILURE;
+ }
+
+ k5_mutex_lock(&gssint_krb5_keytab_lock);
+ old = krb5_gss_keytab;
+ krb5_gss_keytab = new;
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ free(old);
+ return GSS_S_COMPLETE;
+}
+
+/* Try to verify that keytab contains at least one entry for name. Return 0 if
+ * it does, KRB5_KT_NOTFOUND if it doesn't, or another error as appropriate. */
+static krb5_error_code
+check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
+{
+ krb5_error_code code;
+ krb5_keytab_entry ent;
+ krb5_kt_cursor cursor;
+ krb5_principal accprinc = NULL;
+ krb5_boolean match;
+ char *princname;
+
+ if (name->service == NULL) {
+ code = krb5_kt_get_entry(context, kt, name->princ, 0, 0, &ent);
+ if (code == 0)
+ krb5_kt_free_entry(context, &ent);
+ return code;
+ }
+
+ /* If we can't iterate through the keytab, skip this check. */
+ if (kt->ops->start_seq_get == NULL)
+ return 0;
+
+ /* Get the partial principal for the acceptor name. */
+ code = kg_acceptor_princ(context, name, &accprinc);
+ if (code)
+ return code;
+
+ /* Scan the keytab for host-based entries matching accprinc. */
+ code = krb5_kt_start_seq_get(context, kt, &cursor);
+ if (code)
+ goto cleanup;
+ while ((code = krb5_kt_next_entry(context, kt, &ent, &cursor)) == 0) {
+ match = krb5_sname_match(context, accprinc, ent.principal);
+ (void)krb5_free_keytab_entry_contents(context, &ent);
+ if (match)
+ break;
+ }
+ (void)krb5_kt_end_seq_get(context, kt, &cursor);
+ if (code == KRB5_KT_END) {
+ code = KRB5_KT_NOTFOUND;
+ if (krb5_unparse_name(context, accprinc, &princname) == 0) {
+ k5_setmsg(context, code, _("No key table entry found matching %s"),
+ princname);
+ free(princname);
+ }
+ }
+
+cleanup:
+ krb5_free_principal(context, accprinc);
+ return code;
+}
+
+/* get credentials corresponding to a key in the krb5 keytab.
+ If successful, set the keytab-specific fields in cred
+*/
+
+static OM_uint32
+acquire_accept_cred(krb5_context context, OM_uint32 *minor_status,
+ krb5_keytab req_keytab, const char *rcname,
+ krb5_gss_cred_id_rec *cred)
+{
+ OM_uint32 major;
+ krb5_error_code code;
+ krb5_keytab kt = NULL;
+ krb5_rcache rc = NULL;
+
+ assert(cred->keytab == NULL);
+
+ /* If we have an explicit rcache name, open it. */
+ if (rcname != NULL) {
+ code = krb5_rc_resolve_full(context, &rc, rcname);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ code = krb5_rc_recover_or_initialize(context, rc, context->clockskew);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ if (req_keytab != NULL) {
+ code = krb5_kt_dup(context, req_keytab, &kt);
+ } else {
+ k5_mutex_lock(&gssint_krb5_keytab_lock);
+ if (krb5_gss_keytab != NULL) {
+ code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ } else {
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ code = krb5_kt_default(context, &kt);
+ }
+ }
+ if (code) {
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+
+ if (cred->name != NULL) {
+ /* Make sure we have keys matching the desired name in the keytab. */
+ code = check_keytab(context, kt, cred->name);
+ if (code) {
+ if (code == KRB5_KT_NOTFOUND) {
+ k5_change_error_message_code(context, code, KG_KEYTAB_NOMATCH);
+ code = KG_KEYTAB_NOMATCH;
+ }
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+
+ if (rc == NULL) {
+ /* Open the replay cache for this principal. */
+ code = krb5_get_server_rcache(context, &cred->name->princ->data[0],
+ &rc);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+ } else {
+ /* Make sure we have a keytab with keys in it. */
+ code = krb5_kt_have_content(context, kt);
+ if (code) {
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ }
+
+ cred->keytab = kt;
+ kt = NULL;
+ cred->rcache = rc;
+ rc = NULL;
+ major = GSS_S_COMPLETE;
+
+cleanup:
+ if (kt != NULL)
+ krb5_kt_close(context, kt);
+ if (rc != NULL)
+ krb5_rc_close(context, rc);
+ *minor_status = code;
+ return major;
+}
+#endif /* LEAN_CLIENT */
+
+#ifdef USE_LEASH
+static krb5_error_code
+get_ccache_leash(krb5_context context, krb5_principal desired_princ,
+ krb5_ccache *ccache_out)
+{
+ krb5_error_code code;
+ krb5_ccache ccache;
+ char ccname[256] = "";
+
+ *ccache_out = NULL;
+
+ if (hLeashDLL == INVALID_HANDLE_VALUE) {
+ hLeashDLL = LoadLibrary(LEASH_DLL);
+ if (hLeashDLL != INVALID_HANDLE_VALUE) {
+ (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
+ GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
+ }
+ }
+
+ if (pLeash_AcquireInitialTicketsIfNeeded) {
+ pLeash_AcquireInitialTicketsIfNeeded(context, desired_princ, ccname,
+ sizeof(ccname));
+ if (!ccname[0])
+ return KRB5_CC_NOTFOUND;
+
+ code = krb5_cc_resolve(context, ccname, &ccache);
+ if (code)
+ return code;
+ } else {
+ /* leash dll not available, open the default credential cache. */
+ code = krb5int_cc_default(context, &ccache);
+ if (code)
+ return code;
+ }
+
+ *ccache_out = ccache;
+ return 0;
+}
+#endif /* USE_LEASH */
+
+/* Set fields in cred according to a ccache config entry whose key (in
+ * principal form) is config_princ and whose value is value. */
+static krb5_error_code
+scan_cc_config(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_const_principal config_princ, const krb5_data *value)
+{
+ krb5_error_code code;
+ krb5_data data0 = empty_data();
+
+ if (config_princ->length != 2)
+ return 0;
+ if (data_eq_string(config_princ->data[1], KRB5_CC_CONF_PROXY_IMPERSONATOR)
+ && cred->impersonator == NULL) {
+ code = krb5int_copy_data_contents_add0(context, value, &data0);
+ if (code)
+ return code;
+ code = krb5_parse_name(context, data0.data, &cred->impersonator);
+ krb5_free_data_contents(context, &data0);
+ if (code)
+ return code;
+ } else if (data_eq_string(config_princ->data[1], KRB5_CC_CONF_REFRESH_TIME)
+ && cred->refresh_time == 0) {
+ code = krb5int_copy_data_contents_add0(context, value, &data0);
+ if (code)
+ return code;
+ cred->refresh_time = atol(data0.data);
+ krb5_free_data_contents(context, &data0);
+ }
+ return 0;
+}
+
+/* Return true if it appears that we can non-interactively get initial
+ * tickets for cred. */
+static krb5_boolean
+can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_keytab_entry entry;
+
+ if (cred->password != NULL)
+ return TRUE;
+
+ if (cred->client_keytab == NULL)
+ return FALSE;
+
+ /* If we don't know the client principal yet, check for any keytab keys. */
+ if (cred->name == NULL)
+ return !krb5_kt_have_content(context, cred->client_keytab);
+
+ /* Check if we have a keytab key for the client principal. */
+ code = krb5_kt_get_entry(context, cred->client_keytab, cred->name->princ,
+ 0, 0, &entry);
+ if (code) {
+ krb5_clear_error_message(context);
+ return FALSE;
+ }
+ krb5_free_keytab_entry_contents(context, &entry);
+ return TRUE;
+}
+
+/* Scan cred->ccache for name, expiry time, impersonator, refresh time. */
+static krb5_error_code
+scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_ccache ccache = cred->ccache;
+ krb5_principal ccache_princ = NULL, tgt_princ = NULL;
+ krb5_data *realm;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ krb5_timestamp endtime;
+ krb5_boolean is_tgt;
+
+ /* Turn on NOTICKET, as we don't need session keys here. */
+ code = krb5_cc_set_flags(context, ccache, KRB5_TC_NOTICKET);
+ if (code)
+ return code;
+
+ /* Credentials cache principal must match the initiator name. */
+ code = krb5_cc_get_principal(context, ccache, &ccache_princ);
+ if (code != 0)
+ goto cleanup;
+ if (cred->name != NULL &&
+ !krb5_principal_compare(context, ccache_princ, cred->name->princ)) {
+ code = KG_CCACHE_NOMATCH;
+ goto cleanup;
+ }
+
+ /* Save the ccache principal as the credential name if not already set. */
+ if (!cred->name) {
+ code = kg_init_name(context, ccache_princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &cred->name);
+ if (code)
+ goto cleanup;
+ ccache_princ = NULL;
+ }
+
+ assert(cred->name->princ != NULL);
+ realm = krb5_princ_realm(context, cred->name->princ);
+ code = krb5_build_principal_ext(context, &tgt_princ,
+ realm->length, realm->data,
+ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+ realm->length, realm->data,
+ 0);
+ if (code)
+ return code;
+
+ /* If there's a tgt for the principal's local realm in here, use its expiry
+ * time. Otherwise use the first key. */
+ code = krb5_cc_start_seq_get(context, ccache, &cursor);
+ if (code) {
+ krb5_free_principal(context, tgt_princ);
+ return code;
+ }
+ while (!(code = krb5_cc_next_cred(context, ccache, &cursor, &creds))) {
+ if (krb5_is_config_principal(context, creds.server)) {
+ code = scan_cc_config(context, cred, creds.server, &creds.ticket);
+ krb5_free_cred_contents(context, &creds);
+ if (code)
+ break;
+ continue;
+ }
+ is_tgt = krb5_principal_compare(context, tgt_princ, creds.server);
+ endtime = creds.times.endtime;
+ krb5_free_cred_contents(context, &creds);
+ if (is_tgt)
+ cred->have_tgt = TRUE;
+ if (is_tgt || cred->expire == 0)
+ cred->expire = endtime;
+ }
+ krb5_cc_end_seq_get(context, ccache, &cursor);
+ if (code && code != KRB5_CC_END)
+ goto cleanup;
+ code = 0;
+
+ if (cred->expire == 0 && !can_get_initial_creds(context, cred)) {
+ code = KG_EMPTY_CCACHE;
+ goto cleanup;
+ }
+
+cleanup:
+ (void)krb5_cc_set_flags(context, ccache, 0);
+ krb5_free_principal(context, ccache_princ);
+ krb5_free_principal(context, tgt_princ);
+ return code;
+}
+
+/* Find an existing or destination ccache for cred->name. */
+static krb5_error_code
+get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_boolean can_get, have_collection;
+ krb5_ccache defcc = NULL;
+ krb5_principal princ = NULL;
+ const char *cctype;
+
+ assert(cred->name != NULL && cred->ccache == NULL);
+#ifdef USE_LEASH
+ code = get_ccache_leash(context, cred->name->princ, &cred->ccache);
+ return code ? code : scan_ccache(context, cred);
+#else
+ /* Check first whether we can acquire tickets, to avoid overwriting the
+ * extended error message from krb5_cc_cache_match. */
+ can_get = can_get_initial_creds(context, cred);
+
+ /* Look for an existing cache for the client principal. */
+ code = krb5_cc_cache_match(context, cred->name->princ, &cred->ccache);
+ if (code == 0)
+ return scan_ccache(context, cred);
+ if (code != KRB5_CC_NOTFOUND || !can_get)
+ return code;
+ krb5_clear_error_message(context);
+
+ /* There is no existing ccache, but we can acquire credentials. Get the
+ * default ccache to help decide where we should put them. */
+ code = krb5_cc_default(context, &defcc);
+ if (code)
+ return code;
+ cctype = krb5_cc_get_type(context, defcc);
+ have_collection = krb5_cc_support_switch(context, cctype);
+
+ /* We can use an empty default ccache if we're using a password or if
+ * there's no collection. */
+ if (cred->password != NULL || !have_collection) {
+ if (krb5_cc_get_principal(context, defcc, &princ) == KRB5_FCC_NOFILE) {
+ cred->ccache = defcc;
+ defcc = NULL;
+ }
+ krb5_clear_error_message(context);
+ }
+
+ /* Otherwise, try to use a new cache in the collection. */
+ if (cred->ccache == NULL) {
+ if (!have_collection) {
+ code = KG_CCACHE_NOMATCH;
+ goto cleanup;
+ }
+ code = krb5_cc_new_unique(context, cctype, NULL, &cred->ccache);
+ if (code)
+ goto cleanup;
+ }
+
+cleanup:
+ krb5_free_principal(context, princ);
+ if (defcc != NULL)
+ krb5_cc_close(context, defcc);
+ return code;
+#endif /* not USE_LEASH */
+}
+
+/* Try to set cred->name using the client keytab. */
+static krb5_error_code
+get_name_from_client_keytab(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_principal princ;
+
+ assert(cred->name == NULL);
+
+ if (cred->client_keytab == NULL)
+ return KRB5_KT_NOTFOUND;
+
+ code = k5_kt_get_principal(context, cred->client_keytab, &princ);
+ if (code)
+ return code;
+ code = kg_init_name(context, princ, NULL, NULL, NULL, KG_INIT_NAME_NO_COPY,
+ &cred->name);
+ if (code) {
+ krb5_free_principal(context, princ);
+ return code;
+ }
+ return 0;
+}
+
+/* Make a note in ccache that we should attempt to refresh it from the client
+ * keytab at refresh_time. */
+static void
+set_refresh_time(krb5_context context, krb5_ccache ccache,
+ krb5_timestamp refresh_time)
+{
+ char buf[128];
+ krb5_data d;
+
+ snprintf(buf, sizeof(buf), "%ld", (long)refresh_time);
+ d = string2data(buf);
+ (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME,
+ &d);
+ krb5_clear_error_message(context);
+}
+
+/* Return true if it's time to refresh cred from the client keytab. If
+ * returning true, avoid retrying for 30 seconds. */
+krb5_boolean
+kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_timestamp now;
+
+ if (krb5_timeofday(context, &now))
+ return FALSE;
+ if (cred->refresh_time != 0 && now >= cred->refresh_time) {
+ set_refresh_time(context, cred->ccache, cred->refresh_time + 30);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* If appropriate, make a note to refresh cred from the client keytab when it
+ * is halfway to expired. */
+void
+kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_ticket_times *times)
+{
+ krb5_timestamp refresh;
+
+ /* For now, we only mark keytab-acquired credentials for refresh. */
+ if (cred->password != NULL)
+ return;
+
+ /* Make a note to refresh these when they are halfway to expired. */
+ refresh = times->starttime + (times->endtime - times->starttime) / 2;
+ set_refresh_time(context, cred->ccache, refresh);
+}
+
+/* Get initial credentials using the supplied password or client keytab. */
+static krb5_error_code
+get_initial_cred(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_get_init_creds_opt *opt = NULL;
+ krb5_creds creds;
+
+ code = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (code)
+ return code;
+ code = krb5_get_init_creds_opt_set_out_ccache(context, opt, cred->ccache);
+ if (code)
+ goto cleanup;
+ if (cred->password != NULL) {
+ code = krb5_get_init_creds_password(context, &creds, cred->name->princ,
+ cred->password, NULL, NULL, 0,
+ NULL, opt);
+ } else if (cred->client_keytab != NULL) {
+ code = krb5_get_init_creds_keytab(context, &creds, cred->name->princ,
+ cred->client_keytab, 0, NULL, opt);
+ } else {
+ code = KRB5_KT_NOTFOUND;
+ }
+ if (code)
+ goto cleanup;
+ kg_cred_set_initial_refresh(context, cred, &creds.times);
+ cred->have_tgt = TRUE;
+ cred->expire = creds.times.endtime;
+ krb5_free_cred_contents(context, &creds);
+cleanup:
+ krb5_get_init_creds_opt_free(context, opt);
+ return code;
+}
+
+/* Get initial credentials if we ought to and are able to. */
+static krb5_error_code
+maybe_get_initial_cred(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+
+ /* Don't get creds if we don't know the name or are doing IAKERB. */
+ if (cred->name == NULL || cred->iakerb_mech)
+ return 0;
+
+ /* Get creds if we have none or if it's time to refresh. */
+ if (cred->expire == 0 || kg_cred_time_to_refresh(context, cred)) {
+ code = get_initial_cred(context, cred);
+ /* If we were trying to refresh and failed, we can keep going. */
+ if (code && cred->expire == 0)
+ return code;
+ krb5_clear_error_message(context);
+ }
+ return 0;
+}
+
+static OM_uint32
+acquire_init_cred(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_ccache req_ccache,
+ gss_buffer_t password,
+ krb5_keytab client_keytab,
+ krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_data pwdata, pwcopy;
+ int caller_ccname = 0;
+
+ /* Get ccache from caller if available. */
+ if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
+ return GSS_S_FAILURE;
+ if (GSS_ERROR(kg_caller_provided_ccache_name(minor_status,
+ &caller_ccname)))
+ return GSS_S_FAILURE;
+
+ if (password != GSS_C_NO_BUFFER) {
+ pwdata = make_data(password->value, password->length);
+ code = krb5int_copy_data_contents_add0(context, &pwdata, &pwcopy);
+ if (code)
+ goto error;
+ cred->password = pwcopy.data;
+
+ /* We will fetch the credential into a private memory ccache. */
+ assert(req_ccache == NULL);
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code)
+ goto error;
+ cred->destroy_ccache = 1;
+ } else if (req_ccache != NULL) {
+ code = krb5_cc_dup(context, req_ccache, &cred->ccache);
+ if (code)
+ goto error;
+ } else if (caller_ccname) {
+ /* Caller's ccache name has been set as the context default. */
+ code = krb5int_cc_default(context, &cred->ccache);
+ if (code)
+ goto error;
+ }
+
+ if (client_keytab != NULL) {
+ code = krb5_kt_dup(context, client_keytab, &cred->client_keytab);
+ } else {
+ code = krb5_kt_client_default(context, &cred->client_keytab);
+ if (code) {
+ /* Treat resolution failure similarly to a client keytab which
+ * resolves but doesn't exist or has no content. */
+ TRACE_GSS_CLIENT_KEYTAB_FAIL(context, code);
+ krb5_clear_error_message(context);
+ code = 0;
+ }
+ }
+ if (code)
+ goto error;
+
+ if (cred->ccache != NULL) {
+ /* The caller specified a ccache; check what's in it. */
+ code = scan_ccache(context, cred);
+ if (code == KRB5_FCC_NOFILE) {
+ /* See if we can get initial creds. If the caller didn't specify
+ * a name, pick one from the client keytab. */
+ if (cred->name == NULL) {
+ if (!get_name_from_client_keytab(context, cred))
+ code = 0;
+ } else if (can_get_initial_creds(context, cred)) {
+ code = 0;
+ }
+ }
+ if (code)
+ goto error;
+ } else if (cred->name != NULL) {
+ /* The caller specified a name but not a ccache; pick a cache. */
+ code = get_cache_for_name(context, cred);
+ if (code)
+ goto error;
+ }
+
+#ifndef USE_LEASH
+ /* If we haven't picked a name, make sure we have or can get any creds,
+ * unless we're using Leash and might be able to get them interactively. */
+ if (cred->name == NULL && !can_get_initial_creds(context, cred)) {
+ code = krb5_cccol_have_content(context);
+ if (code)
+ goto error;
+ }
+#endif
+
+ code = maybe_get_initial_cred(context, cred);
+ if (code)
+ goto error;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+error:
+ *minor_status = code;
+ return GSS_S_CRED_UNAVAIL;
+}
+
+static OM_uint32
+acquire_cred_context(krb5_context context, OM_uint32 *minor_status,
+ gss_name_t desired_name, gss_buffer_t password,
+ OM_uint32 time_req, gss_cred_usage_t cred_usage,
+ krb5_ccache ccache, krb5_keytab client_keytab,
+ krb5_keytab keytab, const char *rcname,
+ krb5_boolean iakerb, gss_cred_id_t *output_cred_handle,
+ OM_uint32 *time_rec)
+{
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_gss_name_t name = (krb5_gss_name_t)desired_name;
+ OM_uint32 ret;
+ krb5_error_code code = 0;
+
+ /* make sure all outputs are valid */
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (time_rec)
+ *time_rec = 0;
+
+ /* create the gss cred structure */
+ cred = k5alloc(sizeof(krb5_gss_cred_id_rec), &code);
+ if (cred == NULL)
+ goto krb_error_out;
+
+ cred->usage = cred_usage;
+ cred->name = NULL;
+ cred->impersonator = NULL;
+ cred->iakerb_mech = iakerb;
+ cred->default_identity = (name == NULL);
+#ifndef LEAN_CLIENT
+ cred->keytab = NULL;
+#endif /* LEAN_CLIENT */
+ cred->destroy_ccache = 0;
+ cred->suppress_ci_flags = 0;
+ cred->ccache = NULL;
+
+ code = k5_mutex_init(&cred->lock);
+ if (code)
+ goto krb_error_out;
+
+ switch (cred_usage) {
+ case GSS_C_INITIATE:
+ case GSS_C_ACCEPT:
+ case GSS_C_BOTH:
+ break;
+ default:
+ ret = GSS_S_FAILURE;
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ goto error_out;
+ }
+
+ if (name != NULL) {
+ code = kg_duplicate_name(context, name, &cred->name);
+ if (code)
+ goto krb_error_out;
+ }
+
+#ifndef LEAN_CLIENT
+ /*
+ * If requested, acquire credentials for accepting. This will fill
+ * in cred->name if desired_princ is specified.
+ */
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
+ ret = acquire_accept_cred(context, minor_status, keytab, rcname, cred);
+ if (ret != GSS_S_COMPLETE)
+ goto error_out;
+ }
+#endif /* LEAN_CLIENT */
+
+ /*
+ * If requested, acquire credentials for initiation. This will fill
+ * in cred->name if it wasn't set above.
+ */
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
+ ret = acquire_init_cred(context, minor_status, ccache, password,
+ client_keytab, cred);
+ if (ret != GSS_S_COMPLETE)
+ goto error_out;
+ }
+
+ assert(cred->default_identity || cred->name != NULL);
+
+ /*** at this point, the cred structure has been completely created */
+
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (time_rec)
+ *time_rec = GSS_C_INDEFINITE;
+ } else {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto krb_error_out;
+
+ if (time_rec) {
+ /* Resolve cred now to determine the expiration time. */
+ ret = kg_cred_resolve(minor_status, context, (gss_cred_id_t)cred,
+ GSS_C_NO_NAME);
+ if (GSS_ERROR(ret))
+ goto error_out;
+ *time_rec = (cred->expire > now) ? (cred->expire - now) : 0;
+ k5_mutex_unlock(&cred->lock);
+ }
+ }
+
+ *minor_status = 0;
+ *output_cred_handle = (gss_cred_id_t) cred;
+
+ return GSS_S_COMPLETE;
+
+krb_error_out:
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+
+error_out:
+ if (cred != NULL) {
+ if (cred->ccache) {
+ if (cred->destroy_ccache)
+ krb5_cc_destroy(context, cred->ccache);
+ else
+ krb5_cc_close(context, cred->ccache);
+ }
+ if (cred->client_keytab)
+ krb5_kt_close(context, cred->client_keytab);
+#ifndef LEAN_CLIENT
+ if (cred->keytab)
+ krb5_kt_close(context, cred->keytab);
+#endif /* LEAN_CLIENT */
+ if (cred->rcache)
+ krb5_rc_close(context, cred->rcache);
+ if (cred->name)
+ kg_release_name(context, &cred->name);
+ krb5_free_principal(context, cred->impersonator);
+ zapfreestr(cred->password);
+ k5_mutex_destroy(&cred->lock);
+ xfree(cred);
+ }
+ save_error_info(*minor_status, context);
+ return ret;
+}
+
+static OM_uint32
+acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ gss_buffer_t password, OM_uint32 time_req,
+ gss_cred_usage_t cred_usage, krb5_ccache ccache,
+ krb5_keytab keytab, krb5_boolean iakerb,
+ gss_cred_id_t *output_cred_handle, OM_uint32 *time_rec)
+{
+ krb5_context context = NULL;
+ krb5_error_code code = 0;
+ OM_uint32 ret;
+
+ code = gss_krb5int_initialize_library();
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ ret = acquire_cred_context(context, minor_status, desired_name, password,
+ time_req, cred_usage, ccache, NULL, keytab,
+ NULL, iakerb, output_cred_handle, time_rec);
+
+out:
+ krb5_free_context(context);
+ return ret;
+}
+
+/*
+ * Resolve the name and ccache for an initiator credential if it has not yet
+ * been done. If specified, use the target name to pick an appropriate ccache
+ * within the collection. Validates cred_handle and leaves it locked on
+ * success.
+ */
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name)
+{
+ OM_uint32 maj;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle;
+ krb5_gss_name_t tname = (krb5_gss_name_t)target_name;
+ krb5_principal client_princ;
+
+ *minor_status = 0;
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj != 0)
+ return maj;
+ k5_mutex_assert_locked(&cred->lock);
+
+ if (cred->usage == GSS_C_ACCEPT || cred->name != NULL)
+ return GSS_S_COMPLETE;
+ /* acquire_init_cred should have set both name and ccache, or neither. */
+ assert(cred->ccache == NULL);
+
+ if (tname != NULL) {
+ /* Use the target name to select an existing ccache or a principal. */
+ code = krb5_cc_select(context, tname->princ, &cred->ccache,
+ &client_princ);
+ if (code && code != KRB5_CC_NOTFOUND)
+ goto kerr;
+ if (client_princ != NULL) {
+ code = kg_init_name(context, client_princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &cred->name);
+ if (code) {
+ krb5_free_principal(context, client_princ);
+ goto kerr;
+ }
+ }
+ if (cred->ccache != NULL) {
+ code = scan_ccache(context, cred);
+ if (code)
+ goto kerr;
+ }
+ }
+
+ /* If we still haven't picked a client principal, try using an existing
+ * default ccache. (On Windows, this may acquire initial creds.) */
+ if (cred->name == NULL) {
+ code = krb5int_cc_default(context, &cred->ccache);
+ if (code)
+ goto kerr;
+ code = scan_ccache(context, cred);
+ if (code == KRB5_FCC_NOFILE) {
+ /* Default ccache doesn't exist; fall through to client keytab. */
+ krb5_cc_close(context, cred->ccache);
+ cred->ccache = NULL;
+ } else if (code) {
+ goto kerr;
+ }
+ }
+
+ /* If that didn't work, try getting a name from the client keytab. */
+ if (cred->name == NULL) {
+ code = get_name_from_client_keytab(context, cred);
+ if (code) {
+ code = KG_EMPTY_CCACHE;
+ goto kerr;
+ }
+ }
+
+ if (cred->name != NULL && cred->ccache == NULL) {
+ /* Pick a cache for the name we chose (from krb5_cc_select or from the
+ * client keytab). */
+ code = get_cache_for_name(context, cred);
+ if (code)
+ goto kerr;
+ }
+
+ /* Resolve name to ccache and possibly get initial credentials. */
+ code = maybe_get_initial_cred(context, cred);
+ if (code)
+ goto kerr;
+
+ return GSS_S_COMPLETE;
+
+kerr:
+ k5_mutex_unlock(&cred->lock);
+ save_error_info(code, context);
+ *minor_status = code;
+ return GSS_S_CRED_UNAVAIL;
+}
+
+OM_uint32
+gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+ krb5_context context;
+ krb5_rcache rcache;
+
+ assert(value->length == sizeof(rcache));
+
+ if (value->length != sizeof(rcache))
+ return GSS_S_FAILURE;
+
+ rcache = (krb5_rcache)value->value;
+
+ cred = (krb5_gss_cred_id_t)*cred_handle;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ if (cred->rcache != NULL) {
+ code = krb5_rc_close(context, cred->rcache);
+ if (code) {
+ *minor_status = code;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+ }
+
+ cred->rcache = rcache;
+
+ krb5_free_context(context);
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * krb5 and IAKERB mech API functions follow. The mechglue always passes null
+ * desired_mechs and actual_mechs, so we ignore those parameters.
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ OM_uint32 time_req, gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs, OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, NULL, time_req, cred_usage,
+ NULL, NULL, FALSE, output_cred_handle, time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ OM_uint32 time_req, gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs, OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, NULL, time_req, cred_usage,
+ NULL, NULL, TRUE, output_cred_handle, time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password, time_req,
+ cred_usage, NULL, NULL, FALSE, output_cred_handle,
+ time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password, time_req,
+ cred_usage, NULL, NULL, TRUE, output_cred_handle,
+ time_rec);
+}
+
+OM_uint32
+gss_krb5int_import_cred(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ struct krb5_gss_import_cred_req *req;
+ krb5_gss_name_rec name;
+ OM_uint32 time_rec;
+ krb5_error_code code;
+ gss_cred_usage_t usage;
+ gss_name_t desired_name = GSS_C_NO_NAME;
+
+ assert(value->length == sizeof(*req));
+
+ if (value->length != sizeof(*req))
+ return GSS_S_FAILURE;
+
+ req = (struct krb5_gss_import_cred_req *)value->value;
+
+ if (req->id != NULL) {
+ usage = (req->keytab != NULL) ? GSS_C_BOTH : GSS_C_INITIATE;
+ } else if (req->keytab != NULL) {
+ usage = GSS_C_ACCEPT;
+ } else {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ if (req->keytab_principal != NULL) {
+ memset(&name, 0, sizeof(name));
+ code = k5_mutex_init(&name.lock);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ name.princ = req->keytab_principal;
+ desired_name = (gss_name_t)&name;
+ }
+
+ code = acquire_cred(minor_status, desired_name, NULL, GSS_C_INDEFINITE,
+ usage, req->id, req->keytab, FALSE, cred_handle,
+ &time_rec);
+ if (req->keytab_principal != NULL)
+ k5_mutex_destroy(&name.lock);
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ krb5_context context = NULL;
+ krb5_error_code code = 0;
+ krb5_keytab client_keytab = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_ccache ccache = NULL;
+ const char *rcname, *value;
+ OM_uint32 ret;
+
+ code = gss_krb5int_initialize_library();
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_CCACHE_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_cc_resolve(context, value, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_CLI_KEYTAB_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_kt_resolve(context, value, &client_keytab);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_KEYTAB_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_kt_resolve(context, value, &keytab);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_RCACHE_URN, &rcname);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ ret = acquire_cred_context(context, minor_status, desired_name, NULL,
+ time_req, cred_usage, ccache, client_keytab,
+ keytab, rcname, 0, output_cred_handle,
+ time_rec);
+
+out:
+ if (ccache != NULL)
+ krb5_cc_close(context, ccache);
+ if (client_keytab != NULL)
+ krb5_kt_close(context, client_keytab);
+ if (keytab != NULL)
+ krb5_kt_close(context, keytab);
+ krb5_free_context(context);
+ return ret;
+}
diff --git a/src/lib/gssapi/krb5/canon_name.c b/src/lib/gssapi/krb5/canon_name.c
new file mode 100644
index 000000000000..81b08a534ec1
--- /dev/null
+++ b/src/lib/gssapi/krb5/canon_name.c
@@ -0,0 +1,44 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/canon_name.c */
+/*
+ * Copyright 1997 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* This is trivial since we're a single mechanism implementation */
+
+OM_uint32 krb5_gss_canonicalize_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ const gss_OID mech_type,
+ gss_name_t *output_name)
+{
+ if ((mech_type != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ return(krb5_gss_duplicate_name(minor_status, input_name, output_name));
+}
diff --git a/src/lib/gssapi/krb5/compare_name.c b/src/lib/gssapi/krb5/compare_name.c
new file mode 100644
index 000000000000..3f3788d2bf1c
--- /dev/null
+++ b/src/lib/gssapi/krb5/compare_name.c
@@ -0,0 +1,52 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_compare_name(minor_status, name1, name2, name_equal)
+ OM_uint32 *minor_status;
+ gss_name_t name1;
+ gss_name_t name2;
+ int *name_equal;
+{
+ krb5_context context;
+ krb5_error_code code;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ *minor_status = 0;
+ *name_equal = kg_compare_name(context,
+ (krb5_gss_name_t)name1,
+ (krb5_gss_name_t)name2);
+ krb5_free_context(context);
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
new file mode 100644
index 000000000000..a18cfb05b743
--- /dev/null
+++ b/src/lib/gssapi/krb5/context_time.c
@@ -0,0 +1,63 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_context_time(minor_status, context_handle, time_rec)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ OM_uint32 *time_rec;
+{
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ if ((code = krb5_timeofday(ctx->k5_context, &now))) {
+ *minor_status = code;
+ save_error_info(*minor_status, ctx->k5_context);
+ return(GSS_S_FAILURE);
+ }
+
+ if ((lifetime = ctx->krb_times.endtime - now) <= 0) {
+ *time_rec = 0;
+ *minor_status = 0;
+ return(GSS_S_CONTEXT_EXPIRED);
+ } else {
+ *time_rec = lifetime;
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+}
diff --git a/src/lib/gssapi/krb5/copy_ccache.c b/src/lib/gssapi/krb5/copy_ccache.c
new file mode 100644
index 000000000000..f3d7666135cd
--- /dev/null
+++ b/src/lib/gssapi/krb5/copy_ccache.c
@@ -0,0 +1,60 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include "gssapiP_krb5.h"
+
+OM_uint32
+gss_krb5int_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t k5creds;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ krb5_error_code code;
+ krb5_context context;
+ krb5_ccache out_ccache;
+
+ assert(value->length == sizeof(out_ccache));
+
+ if (value->length != sizeof(out_ccache))
+ return GSS_S_FAILURE;
+
+ out_ccache = (krb5_ccache)value->value;
+
+ /* cred handle will have been validated by gssspi_set_cred_option() */
+ k5creds = (krb5_gss_cred_id_t) *cred_handle;
+ k5_mutex_lock(&k5creds->lock);
+ if (k5creds->usage == GSS_C_ACCEPT) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor);
+ if (code) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor,
+ &creds)) {
+ code = krb5_cc_store_cred(context, out_ccache, &creds);
+ krb5_free_cred_contents(context, &creds);
+ }
+ krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ if (code)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return code ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/cred_store.c b/src/lib/gssapi/krb5/cred_store.c
new file mode 100644
index 000000000000..008dd208bf0c
--- /dev/null
+++ b/src/lib/gssapi/krb5/cred_store.c
@@ -0,0 +1,50 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+ const char *type, const char **value)
+{
+ OM_uint32 i;
+
+ if (value == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ *value = NULL;
+
+ if (cred_store == GSS_C_NO_CRED_STORE)
+ return GSS_S_COMPLETE;
+
+ for (i = 0; i < cred_store->count; i++) {
+ if (strcmp(cred_store->elements[i].key, type) == 0) {
+ if (*value != NULL)
+ return GSS_S_DUPLICATE_ELEMENT;
+ *value = cred_store->elements[i].value;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c
new file mode 100644
index 000000000000..4b9dfae0d515
--- /dev/null
+++ b/src/lib/gssapi/krb5/delete_sec_context.c
@@ -0,0 +1,99 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_sec_context(minor_status, context_handle, output_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_buffer_t output_token;
+{
+ krb5_context context;
+ krb5_gss_ctx_id_rec *ctx;
+
+ if (output_token) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ /*SUPPRESS 29*/
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+ context = ctx->k5_context;
+
+ /* free all the context state */
+
+ if (ctx->seqstate)
+ g_seqstate_free(ctx->seqstate);
+
+ if (ctx->enc)
+ krb5_k_free_key(context, ctx->enc);
+
+ if (ctx->seq)
+ krb5_k_free_key(context, ctx->seq);
+
+ if (ctx->here)
+ kg_release_name(context, &ctx->here);
+ if (ctx->there)
+ kg_release_name(context, &ctx->there);
+ if (ctx->subkey)
+ krb5_k_free_key(context, ctx->subkey);
+ if (ctx->acceptor_subkey)
+ krb5_k_free_key(context, ctx->acceptor_subkey);
+
+ if (ctx->auth_context) {
+ if (ctx->cred_rcache)
+ (void)krb5_auth_con_setrcache(context, ctx->auth_context, NULL);
+
+ krb5_auth_con_free(context, ctx->auth_context);
+ }
+
+ if (ctx->mech_used)
+ krb5_gss_release_oid(minor_status, &ctx->mech_used);
+
+ if (ctx->authdata)
+ krb5_free_authdata(context, ctx->authdata);
+
+ if (ctx->k5_context)
+ krb5_free_context(ctx->k5_context);
+
+ /* Zero out context */
+ zap(ctx, sizeof(*ctx));
+ xfree(ctx);
+
+ /* zero the handle itself */
+
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/deps b/src/lib/gssapi/krb5/deps
new file mode 100644
index 000000000000..f42f40ae7727
--- /dev/null
+++ b/src/lib/gssapi/krb5/deps
@@ -0,0 +1,756 @@
+#
+# Generated makefile dependencies follow.
+#
+accept_sec_context.so accept_sec_context.po $(OUTPRE)accept_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h accept_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+acquire_cred.so acquire_cred.po $(OUTPRE)acquire_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h acquire_cred.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+canon_name.so canon_name.po $(OUTPRE)canon_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h canon_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+compare_name.so compare_name.po $(OUTPRE)compare_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h compare_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+context_time.so context_time.po $(OUTPRE)context_time.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h context_time.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+copy_ccache.so copy_ccache.po $(OUTPRE)copy_ccache.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h copy_ccache.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+cred_store.so cred_store.po $(OUTPRE)cred_store.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h cred_store.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+delete_sec_context.so delete_sec_context.po $(OUTPRE)delete_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h delete_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+disp_name.so disp_name.po $(OUTPRE)disp_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h disp_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+disp_status.so disp_status.po $(OUTPRE)disp_status.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h disp_status.c error_map.h \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+duplicate_name.so duplicate_name.po $(OUTPRE)duplicate_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h duplicate_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+export_cred.so export_cred.po $(OUTPRE)export_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-json.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h ../generic/gssapi_err_generic.h \
+ export_cred.c gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+export_name.so export_name.po $(OUTPRE)export_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h export_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+export_sec_context.so export_sec_context.po $(OUTPRE)export_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h export_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+get_tkt_flags.so get_tkt_flags.po $(OUTPRE)get_tkt_flags.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h get_tkt_flags.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+gssapi_krb5.so gssapi_krb5.po $(OUTPRE)gssapi_krb5.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../mechglue/mechglue.h $(srcdir)/../mechglue/mglueP.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.c gssapi_krb5.h
+iakerb.so iakerb.po $(OUTPRE)iakerb.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h iakerb.c
+import_cred.so import_cred.po $(OUTPRE)import_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-json.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h ../generic/gssapi_err_generic.h \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h import_cred.c
+import_name.so import_name.po $(OUTPRE)import_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h import_name.c
+import_sec_context.so import_sec_context.po $(OUTPRE)import_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h import_sec_context.c
+indicate_mechs.so indicate_mechs.po $(OUTPRE)indicate_mechs.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../mechglue/mechglue.h $(srcdir)/../mechglue/mglueP.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h indicate_mechs.c
+init_sec_context.so init_sec_context.po $(OUTPRE)init_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h init_sec_context.c
+inq_context.so inq_context.po $(OUTPRE)inq_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_context.c
+inq_cred.so inq_cred.po $(OUTPRE)inq_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_cred.c
+inq_names.so inq_names.po $(OUTPRE)inq_names.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_names.c
+k5seal.so k5seal.po $(OUTPRE)k5seal.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5seal.c
+k5sealiov.so k5sealiov.po $(OUTPRE)k5sealiov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealiov.c
+k5sealv3.so k5sealv3.po $(OUTPRE)k5sealv3.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealv3.c
+k5sealv3iov.so k5sealv3iov.po $(OUTPRE)k5sealv3iov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealv3iov.c
+k5unseal.so k5unseal.po $(OUTPRE)k5unseal.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5unseal.c
+k5unsealiov.so k5unsealiov.po $(OUTPRE)k5unsealiov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5unsealiov.c
+krb5_gss_glue.so krb5_gss_glue.po $(OUTPRE)krb5_gss_glue.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h krb5_gss_glue.c
+lucid_context.so lucid_context.po $(OUTPRE)lucid_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h lucid_context.c
+naming_exts.so naming_exts.po $(OUTPRE)naming_exts.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h naming_exts.c
+prf.so prf.po $(OUTPRE)prf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h prf.c
+process_context_token.so process_context_token.po $(OUTPRE)process_context_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h process_context_token.c
+rel_cred.so rel_cred.po $(OUTPRE)rel_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_cred.c
+rel_oid.so rel_oid.po $(OUTPRE)rel_oid.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_oid.c
+rel_name.so rel_name.po $(OUTPRE)rel_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_name.c
+s4u_gss_glue.so s4u_gss_glue.po $(OUTPRE)s4u_gss_glue.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h s4u_gss_glue.c
+set_allowable_enctypes.so set_allowable_enctypes.po \
+ $(OUTPRE)set_allowable_enctypes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h set_allowable_enctypes.c
+ser_sctx.so ser_sctx.po $(OUTPRE)ser_sctx.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h ser_sctx.c
+set_ccache.so set_ccache.po $(OUTPRE)set_ccache.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h set_ccache.c
+store_cred.so store_cred.po $(OUTPRE)store_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h store_cred.c
+util_cksum.so util_cksum.po $(OUTPRE)util_cksum.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_cksum.c
+util_crypt.so util_crypt.po $(OUTPRE)util_crypt.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_crypt.c
+util_seed.so util_seed.po $(OUTPRE)util_seed.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_seed.c
+util_seqnum.so util_seqnum.po $(OUTPRE)util_seqnum.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_seqnum.c
+val_cred.so val_cred.po $(OUTPRE)val_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h val_cred.c
+wrap_size_limit.so wrap_size_limit.po $(OUTPRE)wrap_size_limit.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h wrap_size_limit.c
diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c
new file mode 100644
index 000000000000..b097bf0e2181
--- /dev/null
+++ b/src/lib/gssapi/krb5/disp_name.c
@@ -0,0 +1,81 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_name(minor_status, input_name, output_name_buffer,
+ output_name_type)
+ OM_uint32 *minor_status;
+ gss_name_t input_name;
+ gss_buffer_t output_name_buffer;
+ gss_OID *output_name_type;
+{
+ krb5_context context;
+ krb5_error_code code;
+ char *str;
+ krb5_gss_name_t k5name = (krb5_gss_name_t) input_name;
+ gss_OID nametype = (gss_OID) gss_nt_krb5_name;
+
+ output_name_buffer->length = 0;
+ output_name_buffer->value = NULL;
+ if (output_name_type)
+ *output_name_type = GSS_C_NO_OID;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (krb5_princ_type(context, k5name->princ) == KRB5_NT_WELLKNOWN) {
+ if (krb5_principal_compare(context, k5name->princ,
+ krb5_anonymous_principal()))
+ nametype = GSS_C_NT_ANONYMOUS;
+ }
+
+ if ((code = krb5_unparse_name(context,
+ ((krb5_gss_name_t) input_name)->princ,
+ &str))) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+
+ if (! g_make_string_buffer(str, output_name_buffer)) {
+ krb5_free_unparsed_name(context, str);
+ krb5_free_context(context);
+
+ *minor_status = (OM_uint32) G_BUFFER_ALLOC;
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_free_unparsed_name(context, str);
+ krb5_free_context(context);
+
+ *minor_status = 0;
+ if (output_name_type)
+ *output_name_type = (gss_OID) nametype;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/disp_status.c b/src/lib/gssapi/krb5/disp_status.c
new file mode 100644
index 000000000000..6ff62a9d8415
--- /dev/null
+++ b/src/lib/gssapi/krb5/disp_status.c
@@ -0,0 +1,200 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+#include "com_err.h"
+
+/* XXXX internationalization!! */
+
+static inline int
+compare_OM_uint32 (OM_uint32 a, OM_uint32 b)
+{
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+static inline void
+free_string (char *s)
+{
+ free(s);
+}
+#include "error_map.h"
+#include <stdio.h>
+char *get_error_message(OM_uint32 minor_code)
+{
+ gsserrmap *p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ char *msg = NULL;
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, p=%p)", __FUNCTION__, (unsigned long) minor_code,
+ (void *) p);
+#endif
+ if (p) {
+ char **v = gsserrmap_find(p, minor_code);
+ if (v) {
+ msg = *v;
+#ifdef DEBUG
+ fprintf(stderr, " FOUND!");
+#endif
+ }
+ }
+ if (msg == 0)
+ msg = (char *)error_message((krb5_error_code)minor_code);
+#ifdef DEBUG
+ fprintf(stderr, " -> %p/%s\n", (void *) msg, msg);
+#endif
+ return msg;
+}
+#define save_error_string_nocopy gss_krb5_save_error_string_nocopy
+static int save_error_string_nocopy(OM_uint32 minor_code, char *msg)
+{
+ gsserrmap *p;
+ int ret;
+
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, %s)", __FUNCTION__, (unsigned long) minor_code, msg);
+#endif
+ p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ if (!p) {
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ ret = 1;
+ goto fail;
+ }
+ if (gsserrmap_init(p) != 0) {
+ free(p);
+ p = NULL;
+ ret = 1;
+ goto fail;
+ }
+ if (k5_setspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE, p) != 0) {
+ gsserrmap_destroy(p);
+ free(p);
+ p = NULL;
+ ret = 1;
+ goto fail;
+ }
+ }
+ ret = gsserrmap_replace_or_insert(p, minor_code, msg);
+fail:
+#ifdef DEBUG
+ fprintf(stderr, " p=%p %s\n", (void *)p, ret ? "FAIL" : "SUCCESS");
+#endif
+ return ret;
+}
+void save_error_string(OM_uint32 minor_code, char *msg)
+{
+ char *s = strdup(msg);
+ if (s) {
+ if (save_error_string_nocopy(minor_code, s) != 0)
+ free(s);
+ }
+}
+void save_error_message(OM_uint32 minor_code, const char *format, ...)
+{
+ char *s;
+ int n;
+ va_list ap;
+
+ va_start(ap, format);
+ n = vasprintf(&s, format, ap);
+ va_end(ap);
+ if (n >= 0) {
+ if (save_error_string_nocopy(minor_code, s) != 0)
+ free(s);
+ }
+}
+void krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx)
+{
+ char *s;
+
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, ctx=%p)\n", __FUNCTION__,
+ (unsigned long) minor_code, (void *)ctx);
+#endif
+ s = (char *)krb5_get_error_message(ctx, (krb5_error_code)minor_code);
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, ctx=%p) saving: %s\n", __FUNCTION__,
+ (unsigned long) minor_code, (void *)ctx, s);
+#endif
+ save_error_string(minor_code, s);
+ /* The get_error_message call above resets the error message in
+ ctx. Put it back, in case we make this call again *sigh*. */
+ k5_setmsg(ctx, (krb5_error_code)minor_code, "%s", s);
+ krb5_free_error_message(ctx, s);
+}
+void krb5_gss_delete_error_info(void *p)
+{
+ gsserrmap_destroy(p);
+ free(p);
+}
+
+/**/
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_status(minor_status, status_value, status_type,
+ mech_type, message_context, status_string)
+ OM_uint32 *minor_status;
+ OM_uint32 status_value;
+ int status_type;
+ gss_OID mech_type;
+ OM_uint32 *message_context;
+ gss_buffer_t status_string;
+{
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if ((mech_type != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type) &&
+ !g_OID_equal(gss_mech_iakerb, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ if (status_type == GSS_C_GSS_CODE) {
+ return(g_display_major_status(minor_status, status_value,
+ message_context, status_string));
+ } else if (status_type == GSS_C_MECH_CODE) {
+ (void) gss_krb5int_initialize_library();
+
+ if (*message_context) {
+ *minor_status = (OM_uint32) G_BAD_MSG_CTX;
+ return(GSS_S_FAILURE);
+ }
+
+ /* If this fails, there's not much we can do... */
+ if (!g_make_string_buffer(krb5_gss_get_error_message(status_value),
+ status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ } else {
+ *minor_status = 0;
+ return(GSS_S_BAD_STATUS);
+ }
+}
diff --git a/src/lib/gssapi/krb5/duplicate_name.c b/src/lib/gssapi/krb5/duplicate_name.c
new file mode 100644
index 000000000000..b88d97d9d617
--- /dev/null
+++ b/src/lib/gssapi/krb5/duplicate_name.c
@@ -0,0 +1,59 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/duplicate_name.c */
+/*
+ * Copyright 1997,2007 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_duplicate_name(OM_uint32 *minor_status, const gss_name_t input_name,
+ gss_name_t *dest_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t princ, outprinc;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ if (minor_status)
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ princ = (krb5_gss_name_t)input_name;
+ code = kg_duplicate_name(context, princ, &outprinc);
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ krb5_free_context(context);
+ *dest_name = (gss_name_t) outprinc;
+ return(GSS_S_COMPLETE);
+
+}
diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c
new file mode 100644
index 000000000000..652b2604bda3
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_cred.c
@@ -0,0 +1,481 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_cred.c - krb5 export_cred implementation */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "k5-json.h"
+#include "gssapiP_krb5.h"
+
+/* Return a JSON null or array value representing princ. */
+static krb5_error_code
+json_principal(krb5_context context, krb5_principal princ,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str = NULL;
+ char *princname;
+
+ *val_out = NULL;
+ if (princ == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = krb5_unparse_name(context, princ, &princname);
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(princname, &str);
+ krb5_free_unparsed_name(context, princname);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a json null or array value representing etypes. */
+static krb5_error_code
+json_etypes(krb5_enctype *etypes, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_number num;
+ k5_json_array array;
+
+ *val_out = NULL;
+ if (etypes == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *etypes != 0; etypes++) {
+ ret = k5_json_number_create(*etypes, &num);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, num);
+ k5_json_release(num);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON null or array value representing name. */
+static krb5_error_code
+json_kgname(krb5_context context, krb5_gss_name_t name, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array = NULL;
+ k5_json_value princ;
+
+ *val_out = NULL;
+ if (name == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = json_principal(context, name->princ, &princ);
+ if (ret)
+ return ret;
+ ret = k5_json_array_fmt(&array, "vss", princ, name->service, name->host);
+ k5_json_release(princ);
+ *val_out = array;
+ return ret;
+}
+
+/* Return a JSON null or string value representing keytab. */
+static krb5_error_code
+json_keytab(krb5_context context, krb5_keytab keytab, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str;
+ char name[1024];
+
+ *val_out = NULL;
+ if (keytab == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(name, &str);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a JSON null or string value representing rcache. */
+static krb5_error_code
+json_rcache(krb5_context context, krb5_rcache rcache, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str = NULL;
+ char *name;
+
+ if (rcache == NULL)
+ return k5_json_null_create_val(val_out);
+ if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache),
+ krb5_rc_get_name(context, rcache)) < 0)
+ return ENOMEM;
+ ret = k5_json_string_create(name, &str);
+ free(name);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a JSON array value representing keyblock. */
+static krb5_error_code
+json_keyblock(krb5_keyblock *kb, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", kb->enctype, (void *)kb->contents,
+ (size_t)kb->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON array value representing addr. */
+static krb5_error_code
+json_address(krb5_address *addr, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", addr->addrtype,
+ (void *)addr->contents, (size_t)addr->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON null or array value representing addrs. */
+static krb5_error_code
+json_addresses(krb5_address **addrs, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ if (addrs == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *addrs != NULL; addrs++) {
+ ret = json_address(*addrs, &val);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON array value representing ad. */
+static krb5_error_code
+json_authdata_element(krb5_authdata *ad, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", ad->ad_type, (void *)ad->contents,
+ (size_t)ad->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON null or array value representing authdata. */
+static krb5_error_code
+json_authdata(krb5_authdata **authdata, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ if (authdata == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *authdata != NULL; authdata++) {
+ ret = json_authdata_element(*authdata, &val);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON array value representing creds. */
+static krb5_error_code
+json_creds(krb5_context context, krb5_creds *creds, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value client = NULL, server = NULL, keyblock = NULL, addrs = NULL;
+ k5_json_value authdata = NULL;
+
+ *val_out = NULL;
+ ret = json_principal(context, creds->client, &client);
+ if (ret)
+ goto cleanup;
+ ret = json_principal(context, creds->server, &server);
+ if (ret)
+ goto cleanup;
+ ret = json_keyblock(&creds->keyblock, &keyblock);
+ if (ret)
+ goto cleanup;
+ ret = json_addresses(creds->addresses, &addrs);
+ if (ret)
+ goto cleanup;
+ ret = json_authdata(creds->authdata, &authdata);
+ if (ret)
+ goto cleanup;
+
+ ret = k5_json_array_fmt(&array, "vvviiiibivBBv", client, server, keyblock,
+ creds->times.authtime, creds->times.starttime,
+ creds->times.endtime, creds->times.renew_till,
+ creds->is_skey, creds->ticket_flags, addrs,
+ (void *)creds->ticket.data,
+ (size_t)creds->ticket.length,
+ (void *)creds->second_ticket.data,
+ (size_t)creds->second_ticket.length, authdata);
+ if (ret)
+ goto cleanup;
+ *val_out = array;
+
+cleanup:
+ k5_json_release(client);
+ k5_json_release(server);
+ k5_json_release(keyblock);
+ k5_json_release(addrs);
+ k5_json_release(authdata);
+ return ret;
+}
+
+/* Return a JSON array value representing the contents of ccache. */
+static krb5_error_code
+json_ccache_contents(krb5_context context, krb5_ccache ccache,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ krb5_principal princ;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+
+ /* Put the principal in the first array entry. */
+ ret = krb5_cc_get_principal(context, ccache, &princ);
+ if (ret)
+ goto err;
+ ret = json_principal(context, princ, &val);
+ krb5_free_principal(context, princ);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+
+ /* Put credentials in the remaining array entries. */
+ ret = krb5_cc_start_seq_get(context, ccache, &cursor);
+ if (ret)
+ goto err;
+ while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
+ ret = json_creds(context, &creds, &val);
+ krb5_free_cred_contents(context, &creds);
+ if (ret)
+ break;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ break;
+ }
+ krb5_cc_end_seq_get(context, ccache, &cursor);
+ if (ret != KRB5_CC_END)
+ goto err;
+ *val_out = array;
+ return 0;
+
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON null, string, or array value representing ccache. */
+static krb5_error_code
+json_ccache(krb5_context context, krb5_ccache ccache, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str;
+ char *name;
+
+ *val_out = NULL;
+ if (ccache == NULL)
+ return k5_json_null_create_val(val_out);
+ if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) {
+ return json_ccache_contents(context, ccache, val_out);
+ } else {
+ ret = krb5_cc_get_full_name(context, ccache, &name);
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(name, &str);
+ free(name);
+ *val_out = str;
+ return ret;
+ }
+}
+
+/* Return a JSON array value representing cred. */
+static krb5_error_code
+json_kgcred(krb5_context context, krb5_gss_cred_id_t cred,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value name = NULL, imp = NULL, keytab = NULL, rcache = NULL;
+ k5_json_value ccache = NULL, ckeytab = NULL, etypes = NULL;
+
+ *val_out = NULL;
+ ret = json_kgname(context, cred->name, &name);
+ if (ret)
+ goto cleanup;
+ ret = json_principal(context, cred->impersonator, &imp);
+ if (ret)
+ goto cleanup;
+ ret = json_keytab(context, cred->keytab, &keytab);
+ if (ret)
+ goto cleanup;
+ ret = json_rcache(context, cred->rcache, &rcache);
+ if (ret)
+ goto cleanup;
+ ret = json_ccache(context, cred->ccache, &ccache);
+ if (ret)
+ goto cleanup;
+ ret = json_keytab(context, cred->client_keytab, &ckeytab);
+ if (ret)
+ goto cleanup;
+ ret = json_etypes(cred->req_enctypes, &etypes);
+ if (ret)
+ goto cleanup;
+
+ ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp,
+ cred->default_identity, cred->iakerb_mech, keytab,
+ rcache, ccache, ckeytab, cred->have_tgt,
+ cred->expire, cred->refresh_time, etypes,
+ cred->password);
+ if (ret)
+ goto cleanup;
+ *val_out = array;
+
+cleanup:
+ k5_json_release(name);
+ k5_json_release(imp);
+ k5_json_release(keytab);
+ k5_json_release(rcache);
+ k5_json_release(ccache);
+ k5_json_release(ckeytab);
+ k5_json_release(etypes);
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ krb5_context context;
+ krb5_error_code ret;
+ krb5_gss_cred_id_t cred;
+ k5_json_array array = NULL;
+ k5_json_value jcred = NULL;
+ char *str = NULL;
+ krb5_data d;
+
+ ret = krb5_gss_init_context(&context);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* Validate and lock cred_handle. */
+ status = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (status != GSS_S_COMPLETE)
+ return status;
+ cred = (krb5_gss_cred_id_t)cred_handle;
+
+ if (json_kgcred(context, cred, &jcred))
+ goto oom;
+ if (k5_json_array_fmt(&array, "sv", CRED_EXPORT_MAGIC, jcred))
+ goto oom;
+ if (k5_json_encode(array, &str))
+ goto oom;
+ d = string2data(str);
+ if (data_to_gss(&d, token))
+ goto oom;
+ str = NULL;
+
+cleanup:
+ free(str);
+ k5_mutex_unlock(&cred->lock);
+ k5_json_release(array);
+ k5_json_release(jcred);
+ krb5_free_context(context);
+ return status;
+
+oom:
+ *minor_status = ENOMEM;
+ status = GSS_S_FAILURE;
+ goto cleanup;
+}
diff --git a/src/lib/gssapi/krb5/export_name.c b/src/lib/gssapi/krb5/export_name.c
new file mode 100644
index 000000000000..485ebfb6cdf3
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_name.c
@@ -0,0 +1,88 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_name.c */
+/*
+ * Copyright 1997, 2007 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name(OM_uint32 *minor_status, const gss_name_t input_name,
+ gss_buffer_t exported_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ size_t length;
+ char *str;
+ unsigned char *cp;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ if (minor_status)
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ exported_name->length = 0;
+ exported_name->value = NULL;
+
+ if ((code = krb5_unparse_name(context, ((krb5_gss_name_t) input_name)->princ,
+ &str))) {
+ if (minor_status)
+ *minor_status = code;
+ save_error_info((OM_uint32)code, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_free_context(context);
+ length = strlen(str);
+ exported_name->length = 10 + length + gss_mech_krb5->length;
+ exported_name->value = gssalloc_malloc(exported_name->length);
+ if (!exported_name->value) {
+ free(str);
+ if (minor_status)
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ cp = exported_name->value;
+
+ /* Note: we assume the OID will be less than 128 bytes... */
+ *cp++ = 0x04; *cp++ = 0x01;
+ store_16_be(gss_mech_krb5->length+2, cp);
+ cp += 2;
+ *cp++ = 0x06;
+ *cp++ = (gss_mech_krb5->length) & 0xFF;
+ memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
+ cp += gss_mech_krb5->length;
+ store_32_be(length, cp);
+ cp += 4;
+ memcpy(cp, str, length);
+
+ free(str);
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c
new file mode 100644
index 000000000000..49bd76d2bc21
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_sec_context.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_sec_context.c - Externalize a security context */
+/*
+ * Copyright 1995, 2008 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.
+ */
+
+#include "gssapiP_krb5.h"
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_buffer_t interprocess_token;
+{
+ krb5_context context = NULL;
+ krb5_error_code kret;
+ OM_uint32 retval;
+ size_t bufsize, blen;
+ krb5_gss_ctx_id_t ctx;
+ krb5_octet *obuffer, *obp;
+
+ /* Assume a tragic failure */
+ obuffer = (krb5_octet *) NULL;
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+ if (ctx->terminated) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return (GSS_S_NO_CONTEXT);
+ }
+
+ context = ctx->k5_context;
+ kret = krb5_gss_ser_init(context);
+ if (kret)
+ goto error_out;
+
+ /* Determine size needed for externalization of context */
+ bufsize = 0;
+ if ((kret = kg_ctx_size(context, (krb5_pointer) ctx,
+ &bufsize)))
+ goto error_out;
+
+ /* Allocate the buffer */
+ if ((obuffer = gssalloc_malloc(bufsize)) == NULL) {
+ kret = ENOMEM;
+ goto error_out;
+ }
+
+ obp = obuffer;
+ blen = bufsize;
+ /* Externalize the context */
+ if ((kret = kg_ctx_externalize(context,
+ (krb5_pointer) ctx, &obp, &blen)))
+ goto error_out;
+
+ /* Success! Return the buffer */
+ interprocess_token->length = bufsize - blen;
+ interprocess_token->value = obuffer;
+ *minor_status = 0;
+ retval = GSS_S_COMPLETE;
+
+ /* Now, clean up the context state */
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ return (GSS_S_COMPLETE);
+
+error_out:
+ if (retval != GSS_S_COMPLETE)
+ if (kret != 0 && context != 0)
+ save_error_info((OM_uint32)kret, context);
+ if (obuffer && bufsize) {
+ zap(obuffer, bufsize);
+ xfree(obuffer);
+ }
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+#endif /* LEAN_CLIENT */
diff --git a/src/lib/gssapi/krb5/get_tkt_flags.c b/src/lib/gssapi/krb5/get_tkt_flags.c
new file mode 100644
index 000000000000..636fc04db44c
--- /dev/null
+++ b/src/lib/gssapi/krb5/get_tkt_flags.c
@@ -0,0 +1,45 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+gss_krb5int_get_tkt_flags(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_buffer_desc rep;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ rep.value = &ctx->krb_flags;
+ rep.length = sizeof(ctx->krb_flags);
+
+ return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+}
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
new file mode 100644
index 000000000000..d7bdef7e28a3
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -0,0 +1,1428 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2008 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 1993 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.
+ */
+
+#ifndef _GSSAPIP_KRB5_H_
+#define _GSSAPIP_KRB5_H_
+
+#include <k5-int.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* work around sunos braindamage */
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+
+#include "gssapiP_generic.h"
+
+/* The include of gssapi_krb5.h will dtrt with the above #defines in
+ * effect.
+ */
+#include "gssapi_krb5.h"
+#include "gssapi_err_krb5.h"
+#include "gssapi_ext.h"
+
+/* for debugging */
+#undef CFX_EXERCISE
+
+/** constants **/
+
+#define GSS_MECH_KRB5_OID_LENGTH 9
+#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
+
+#define GSS_MECH_KRB5_OLD_OID_LENGTH 5
+#define GSS_MECH_KRB5_OLD_OID "\053\005\001\005\002"
+
+/* Incorrect krb5 mech OID emitted by MS. */
+#define GSS_MECH_KRB5_WRONG_OID_LENGTH 9
+#define GSS_MECH_KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002"
+
+/* IAKERB variant */
+#define GSS_MECH_IAKERB_OID_LENGTH 6
+#define GSS_MECH_IAKERB_OID "\053\006\001\005\002\005"
+
+extern const gss_OID_set kg_all_mechs;
+
+#define CKSUMTYPE_KG_CB 0x8003
+
+#define KG_TOK_CTX_AP_REQ 0x0100
+#define KG_TOK_CTX_AP_REP 0x0200
+#define KG_TOK_CTX_ERROR 0x0300
+#define KG_TOK_SIGN_MSG 0x0101
+#define KG_TOK_SEAL_MSG 0x0201
+#define KG_TOK_MIC_MSG 0x0101
+#define KG_TOK_WRAP_MSG 0x0201
+#define KG_TOK_DEL_CTX 0x0102
+#define KG2_TOK_MIC_MSG 0x0404
+#define KG2_TOK_WRAP_MSG 0x0504
+#define KG2_TOK_DEL_CTX 0x0405
+#define IAKERB_TOK_PROXY 0x0501
+
+#define KRB5_GSS_FOR_CREDS_OPTION 1
+
+#define KG2_RESP_FLAG_ERROR 0x0001
+#define KG2_RESP_FLAG_DELEG_OK 0x0002
+
+/** CFX flags **/
+#define FLAG_SENDER_IS_ACCEPTOR 0x01
+#define FLAG_WRAP_CONFIDENTIAL 0x02
+#define FLAG_ACCEPTOR_SUBKEY 0x04
+
+/* These are to be stored in little-endian order, i.e., des-mac is
+ stored as 02 00. */
+enum sgn_alg {
+ SGN_ALG_DES_MAC_MD5 = 0x0000,
+ SGN_ALG_MD2_5 = 0x0001,
+ SGN_ALG_DES_MAC = 0x0002,
+ SGN_ALG_3 = 0x0003, /* not published */
+ SGN_ALG_HMAC_MD5 = 0x0011, /* microsoft w2k; */
+ SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004
+};
+enum seal_alg {
+ SEAL_ALG_NONE = 0xffff,
+ SEAL_ALG_DES = 0x0000,
+ SEAL_ALG_1 = 0x0001, /* not published */
+ SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; */
+ SEAL_ALG_DES3KD = 0x0002
+};
+
+/* for 3DES */
+#define KG_USAGE_SEAL 22
+#define KG_USAGE_SIGN 23
+#define KG_USAGE_SEQ 24
+
+/* for draft-ietf-krb-wg-gssapi-cfx-01 */
+#define KG_USAGE_ACCEPTOR_SEAL 22
+#define KG_USAGE_ACCEPTOR_SIGN 23
+#define KG_USAGE_INITIATOR_SEAL 24
+#define KG_USAGE_INITIATOR_SIGN 25
+
+enum qop {
+ GSS_KRB5_INTEG_C_QOP_MD5 = 0x0001, /* *partial* MD5 = "MD2.5" */
+ GSS_KRB5_INTEG_C_QOP_DES_MD5 = 0x0002,
+ GSS_KRB5_INTEG_C_QOP_DES_MAC = 0x0003,
+ GSS_KRB5_INTEG_C_QOP_HMAC_SHA1 = 0x0004,
+ GSS_KRB5_INTEG_C_QOP_MASK = 0x00ff,
+ GSS_KRB5_CONF_C_QOP_DES = 0x0100,
+ GSS_KRB5_CONF_C_QOP_DES3_KD = 0x0200,
+ GSS_KRB5_CONF_C_QOP_MASK = 0xff00
+};
+
+/** internal types **/
+
+typedef struct _krb5_gss_name_rec {
+ krb5_principal princ; /* immutable */
+ char *service; /* immutable */
+ char *host; /* immutable */
+ k5_mutex_t lock; /* protects ad_context only for now */
+ krb5_authdata_context ad_context;
+} krb5_gss_name_rec, *krb5_gss_name_t;
+
+typedef struct _krb5_gss_cred_id_rec {
+ /* protect against simultaneous accesses */
+ k5_mutex_t lock;
+
+ /* name/type of credential */
+ gss_cred_usage_t usage;
+ krb5_gss_name_t name;
+ krb5_principal impersonator;
+ unsigned int default_identity : 1;
+ unsigned int iakerb_mech : 1;
+ unsigned int destroy_ccache : 1;
+ unsigned int suppress_ci_flags : 1;
+
+ /* keytab (accept) data */
+ krb5_keytab keytab;
+ krb5_rcache rcache;
+
+ /* ccache (init) data */
+ krb5_ccache ccache;
+ krb5_keytab client_keytab;
+ krb5_boolean have_tgt;
+ krb5_timestamp expire;
+ krb5_timestamp refresh_time;
+ krb5_enctype *req_enctypes; /* limit negotiated enctypes to this list */
+ char *password;
+} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t;
+
+typedef struct _krb5_gss_ctx_ext_rec {
+ struct {
+ krb5_data *conv;
+ int verified;
+ } iakerb;
+} krb5_gss_ctx_ext_rec, *krb5_gss_ctx_ext_t;
+
+typedef struct _krb5_gss_ctx_id_rec {
+ krb5_magic magic;
+ unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
+ unsigned int established : 1;
+ unsigned int have_acceptor_subkey : 1;
+ unsigned int seed_init : 1; /* XXX tested but never actually set */
+ unsigned int terminated : 1;
+ OM_uint32 gss_flags;
+ unsigned char seed[16];
+ krb5_gss_name_t here;
+ krb5_gss_name_t there;
+ krb5_key subkey; /* One of two potential keys to use with RFC 4121
+ * packets; this key must always be set. */
+ int signalg;
+ size_t cksum_size;
+ int sealalg;
+ krb5_key enc; /* RFC 1964 encryption key; seq xored with a constant
+ * for DES, seq for other RFC 1964 enctypes */
+ krb5_key seq; /* RFC 1964 sequencing key */
+ krb5_ticket_times krb_times;
+ 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;
+ uint64_t seq_recv;
+ g_seqnum_state seqstate;
+ krb5_context k5_context;
+ krb5_auth_context auth_context;
+ gss_OID_desc *mech_used;
+ /* Protocol spec revision for sending packets
+ 0 => RFC 1964 with 3DES and RC4 enhancements
+ 1 => RFC 4121
+ No others defined so far. It is always permitted to receive
+ tokens in RFC 4121 format. If enc is non-null, receiving RFC
+ 1964 tokens is permitted.*/
+ int proto;
+ krb5_cksumtype cksumtype; /* for "main" subkey */
+ krb5_key acceptor_subkey; /* CFX only */
+ krb5_cksumtype acceptor_subkey_cksumtype;
+ int cred_rcache; /* did we get rcache from creds? */
+ krb5_authdata **authdata;
+} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
+
+extern g_set kg_vdb;
+
+#ifndef LEAN_CLIENT
+extern k5_mutex_t gssint_krb5_keytab_lock;
+#endif /* LEAN_CLIENT */
+
+/** helper functions **/
+
+OM_uint32 kg_get_defcred
+(OM_uint32 *minor_status,
+ gss_cred_id_t *cred);
+
+krb5_error_code kg_checksum_channel_bindings
+(krb5_context context, gss_channel_bindings_t cb,
+ krb5_checksum *cksum);
+
+krb5_error_code kg_make_seq_num (krb5_context context,
+ krb5_key key,
+ int direction, krb5_ui_4 seqnum, unsigned char *cksum,
+ unsigned char *buf);
+
+krb5_error_code kg_get_seq_num (krb5_context context,
+ krb5_key key,
+ unsigned char *cksum, unsigned char *buf, int *direction,
+ krb5_ui_4 *seqnum);
+
+krb5_error_code kg_make_seed (krb5_context context,
+ krb5_key key,
+ unsigned char *seed);
+
+krb5_error_code
+kg_setup_keys(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ krb5_key subkey,
+ krb5_cksumtype *cksumtype);
+
+int kg_confounder_size (krb5_context context, krb5_enctype enctype);
+
+krb5_error_code kg_make_confounder (krb5_context context,
+ krb5_enctype enctype, unsigned char *buf);
+
+krb5_error_code kg_encrypt (krb5_context context,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ krb5_const_pointer in,
+ krb5_pointer out,
+ unsigned int length);
+
+/* Encrypt length bytes at ptr in place, with the given key and usage. If
+ * iv is not NULL, use it as the cipher state. */
+krb5_error_code kg_encrypt_inplace(krb5_context context, krb5_key key,
+ int usage, krb5_pointer iv,
+ krb5_pointer ptr, unsigned int length);
+
+krb5_error_code kg_encrypt_iov (krb5_context context,
+ int proto, int dce_style,
+ size_t ec, size_t rrc,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code
+kg_arcfour_docrypt (const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ const unsigned char *input_buf, size_t input_len,
+ unsigned char *output_buf);
+
+krb5_error_code
+kg_arcfour_docrypt_iov (krb5_context context,
+ const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code kg_decrypt (krb5_context context,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ krb5_const_pointer in,
+ krb5_pointer out,
+ unsigned int length);
+
+krb5_error_code kg_decrypt_iov (krb5_context context,
+ int proto, int dce_style,
+ size_t ec, size_t rrc,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 kg_seal (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer,
+ int toktype);
+
+OM_uint32 kg_unseal (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_token_buffer,
+ gss_buffer_t message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype);
+
+OM_uint32 kg_seal_size (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 output_size,
+ OM_uint32 *input_size);
+
+krb5_error_code kg_ctx_size (krb5_context kcontext,
+ krb5_pointer arg,
+ size_t *sizep);
+
+krb5_error_code kg_ctx_externalize (krb5_context kcontext,
+ krb5_pointer arg,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+krb5_error_code kg_ctx_internalize (krb5_context kcontext,
+ krb5_pointer *argp,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+OM_uint32 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status);
+
+OM_uint32 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
+ int *out_caller_provided_name);
+
+OM_uint32 kg_get_ccache_name (OM_uint32 *minor_status,
+ const char **out_name);
+
+OM_uint32 kg_set_ccache_name (OM_uint32 *minor_status,
+ const char *name);
+
+/* AEAD */
+
+krb5_error_code gss_krb5int_make_seal_token_v3_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 gss_krb5int_unseal_v3_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype);
+
+gss_iov_buffer_t kg_locate_iov (gss_iov_buffer_desc *iov,
+ int iov_count,
+ OM_uint32 type);
+
+gss_iov_buffer_t kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count,
+ int toktype);
+
+void kg_iov_msglen(gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t *data_length,
+ size_t *assoc_data_length);
+
+void kg_release_iov(gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code kg_make_checksum_iov_v1(krb5_context context,
+ krb5_cksumtype type,
+ size_t token_cksum_len,
+ krb5_key seq,
+ krb5_key enc, /* for conf len */
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_checksum *checksum);
+
+krb5_error_code kg_make_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+krb5_error_code kg_verify_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean *valid);
+
+OM_uint32 kg_seal_iov (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 kg_unseal_iov (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 kg_seal_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+krb5_cryptotype kg_translate_flag_iov(OM_uint32 type);
+
+OM_uint32 kg_fixup_padding_iov(OM_uint32 *minor_status,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_boolean kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count);
+
+krb5_error_code kg_allocate_iov(gss_iov_buffer_t iov, size_t size);
+
+krb5_error_code
+krb5_to_gss_cred(krb5_context context,
+ krb5_creds *creds,
+ krb5_gss_cred_id_t *out_cred);
+
+krb5_boolean
+kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred);
+
+void
+kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_ticket_times *times);
+
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name);
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV iakerb_gss_acquire_cred
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_release_cred
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t* /* cred_handle */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_init_sec_context
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 krb5_gss_init_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ krb5_gss_ctx_ext_t /* exts */
+);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV krb5_gss_accept_sec_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t* /* delegated_cred_handle */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_accept_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t*, /* delegated_cred_handle */
+ krb5_gss_ctx_ext_t/*exts */
+);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_sec_context_by_oid
+(OM_uint32*, /* minor_status */
+ const gss_ctx_id_t,
+ /* context_handle */
+ const gss_OID, /* desired_object */
+ gss_buffer_set_t* /* data_set */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_set_sec_context_option
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ const gss_OID, /* desired_object */
+ const gss_buffer_t/* value */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_process_context_token
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t /* token_buffer */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_delete_sec_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_buffer_t /* output_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_context_time
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_display_status
+(OM_uint32*, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32*, /* message_context */
+ gss_buffer_t /* status_string */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_indicate_mechs
+(OM_uint32*, /* minor_status */
+ gss_OID_set* /* mech_set */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_compare_name
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* name1 */
+ gss_name_t, /* name2 */
+ int* /* name_equal */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_display_name
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID* /* output_name_type */
+);
+
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_name
+(OM_uint32*, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ gss_name_t* /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_release_name
+(OM_uint32*, /* minor_status */
+ gss_name_t* /* input_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_cred
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ gss_cred_usage_t*,/* cred_usage */
+ gss_OID_set * /* mechanisms */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_name_t*, /* initiator_name */
+ gss_name_t*, /* acceptor_name */
+ OM_uint32*, /* lifetime_rec */
+ gss_OID*, /* mech_type */
+ OM_uint32*, /* ret_flags */
+ int*, /* locally_initiated */
+ int* /* open */
+);
+
+/* New V2 entry points */
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov_length
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* message_token */
+ gss_qop_t * /* qop_state */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_iov_length
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_unwrap
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ gss_qop_t * /* qop_state */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_unwrap_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int *, /* conf_state */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_size_limit
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 * /* max_input_size */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_name_object
+(OM_uint32 *, /* minor_status */
+ void *, /* input_name */
+ gss_OID, /* input_name_type */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_export_name_object
+(OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_OID, /* desired_name_type */
+ void * * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_cred_by_mech
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t * /* cred_usage */
+);
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV krb5_gss_export_sec_context
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* interprocess_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_sec_context
+(OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+);
+#endif /* LEAN_CLIENT */
+
+krb5_error_code krb5_gss_ser_init(krb5_context);
+
+OM_uint32 krb5_gss_release_oid
+(OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_internal_release_oid
+(OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_names_for_mech
+(OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+);
+
+OM_uint32 krb5_gss_canonicalize_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ const gss_OID, /* mech_type */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_export_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_duplicate_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_name_t * /* dest_name */
+);
+
+OM_uint32 krb5_gss_validate_cred
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t /* cred */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
+ gss_cred_id_t /* cred_handle */,
+ krb5_context /* context */);
+
+gss_OID krb5_gss_convert_static_mech_oid(gss_OID oid);
+
+krb5_error_code gss_krb5int_make_seal_token_v3(krb5_context,
+ krb5_gss_ctx_id_rec *,
+ const gss_buffer_desc *,
+ gss_buffer_t,
+ int, int);
+
+OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ unsigned char *ptr,
+ unsigned int bodysize,
+ gss_buffer_t message_buffer,
+ int *conf_state, gss_qop_t *qop_state,
+ int toktype);
+
+int gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc);
+
+/* naming_exts.c */
+#define KG_INIT_NAME_NO_COPY 0x1
+
+krb5_error_code
+kg_init_name(krb5_context context, krb5_principal principal,
+ char *service, char *host, krb5_authdata_context ad_context,
+ krb5_flags flags, krb5_gss_name_t *name);
+
+krb5_error_code
+kg_release_name(krb5_context context, krb5_gss_name_t *name);
+
+krb5_error_code
+kg_duplicate_name(krb5_context context, const krb5_gss_name_t src,
+ krb5_gss_name_t *dst);
+
+krb5_boolean
+kg_compare_name(krb5_context context,
+ krb5_gss_name_t name1,
+ krb5_gss_name_t name2);
+
+krb5_boolean
+kg_acceptor_princ(krb5_context context, krb5_gss_name_t name,
+ krb5_principal *princ_out);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_name_ext(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored);
+
+/* s4u_gss_glue.c */
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context);
+
+/*
+ * These take unglued krb5-mech-specific contexts.
+ */
+
+#define GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH 11
+#define GSS_KRB5_GET_TKT_FLAGS_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x01"
+
+OM_uint32 gss_krb5int_get_tkt_flags
+(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+#define GSS_KRB5_COPY_CCACHE_OID_LENGTH 11
+#define GSS_KRB5_COPY_CCACHE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x02"
+
+OM_uint32 gss_krb5int_copy_ccache
+(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#define GSS_KRB5_CCACHE_NAME_OID_LENGTH 11
+#define GSS_KRB5_CCACHE_NAME_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x03"
+
+struct krb5_gss_ccache_name_req {
+ const char *name;
+ const char **out_name;
+};
+
+OM_uint32
+gss_krb5int_ccache_name(OM_uint32 *minor_status, const gss_OID, const gss_OID,
+ const gss_buffer_t);
+
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
+
+OM_uint32
+gss_krb5int_inq_session_key(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH 11
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x04"
+
+struct krb5_gss_set_allowable_enctypes_req {
+ OM_uint32 num_ktypes;
+ krb5_enctype *ktypes;
+};
+
+OM_uint32
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t *cred,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06"
+
+OM_uint32
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07"
+
+OM_uint32
+gss_krb5int_free_lucid_sec_context(OM_uint32 *, const gss_OID,
+ const gss_OID, gss_buffer_t);
+
+extern k5_mutex_t kg_kdc_flag_mutex;
+krb5_error_code krb5_gss_init_context (krb5_context *ctxp);
+
+#define GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_USE_KDC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x08"
+
+OM_uint32 krb5int_gss_use_kdc_context(OM_uint32 *, const gss_OID,
+ const gss_OID, gss_buffer_t);
+
+krb5_error_code krb5_gss_use_kdc_context(void);
+
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH 11
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x09"
+
+OM_uint32
+gss_krb5int_register_acceptor_identity(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a"
+
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *ad_data);
+
+#define GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH 11
+#define GSS_KRB5_SET_CRED_RCACHE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0b"
+
+OM_uint32
+gss_krb5int_set_cred_rcache(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
+
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
+ const gss_ctx_id_t,
+ const gss_OID,
+ gss_buffer_set_t *);
+
+#define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11
+#define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
+
+struct krb5_gss_import_cred_req {
+ krb5_ccache id;
+ krb5_principal keytab_principal;
+ krb5_keytab keytab;
+};
+
+OM_uint32
+gss_krb5int_import_cred(OM_uint32 *minor_status,
+ gss_cred_id_t *cred,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#ifdef _GSS_STATIC_LINK
+int gss_krb5int_lib_init(void);
+void gss_krb5int_lib_fini(void);
+#endif /* _GSS_STATIC_LINK */
+
+OM_uint32 gss_krb5int_initialize_library(void);
+void gss_krb5int_cleanup_library(void);
+
+/* For error message handling. */
+/* Returns a shared string, not a private copy! */
+extern char *
+krb5_gss_get_error_message(OM_uint32 minor_code);
+extern void
+krb5_gss_save_error_string(OM_uint32 minor_code, char *msg);
+extern void
+krb5_gss_save_error_message(OM_uint32 minor_code, const char *format, ...)
+#if !defined(__cplusplus) && (__GNUC__ > 2)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ ;
+ extern void
+ krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx);
+#define get_error_message krb5_gss_get_error_message
+#define save_error_string krb5_gss_save_error_string
+#define save_error_message krb5_gss_save_error_message
+#ifdef KRB5_KERNEL
+/* Error messages aren't needed in the kernel, so reduce dependencies. */
+#define save_error_info(x,y)
+#else
+#define save_error_info krb5_gss_save_error_info
+#endif
+extern void krb5_gss_delete_error_info(void *p);
+
+/* Prefix concatenated with Kerberos encryption type */
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
+
+/* IAKERB */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handler,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token);
+
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished);
+
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished);
+
+/*
+ * Transfer contents of a krb5_data to a gss_buffer and invalidate the source
+ * On unix, this is a simple pointer copy
+ * On windows, memory is reallocated and copied.
+ */
+static inline krb5_error_code
+data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer)
+{
+ krb5_error_code code = 0;
+ output_buffer->length = input_k5data->length;
+#if defined(_WIN32) || defined(DEBUG_GSSALLOC)
+ if (output_buffer->length > 0) {
+ output_buffer->value = gssalloc_malloc(output_buffer->length);
+ if (output_buffer->value)
+ memcpy(output_buffer->value, input_k5data->data, output_buffer->length);
+ else
+ code = ENOMEM;
+ } else {
+ output_buffer->value = NULL;
+ }
+ free(input_k5data->data);
+#else
+ output_buffer->value = input_k5data->data;
+#endif
+ *input_k5data = empty_data();
+ return code;
+}
+
+#define KRB5_GSS_EXTS_IAKERB_FINISHED 1
+
+
+/* Credential store extensions */
+
+#define KRB5_CS_CLI_KEYTAB_URN "client_keytab"
+#define KRB5_CS_KEYTAB_URN "keytab"
+#define KRB5_CS_CCACHE_URN "ccache"
+#define KRB5_CS_RCACHE_URN "rcache"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+ const char *type, const char **value);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_cred_usage_t, /* input_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t *); /* cred_usage_stored */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_name_t *src_name,
+ gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+ gss_OID *mech_type, OM_uint32 *ctx_flags,
+ int *locally_initiated, int *opened);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_buffer_t message_buffer,
+ gss_buffer_t message_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+ gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer, int *conf_state,
+ gss_buffer_t output_message_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer, int *conf_state,
+ gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int *conf_state, gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, OM_uint32 req_output_size,
+ OM_uint32 *max_input_size);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int prf_key, const gss_buffer_t prf_in,
+ ssize_t desired_output_len, gss_buffer_t prf_out);
+
+/* Magic string to identify exported krb5 GSS credentials. Increment this if
+ * the format changes. */
+#define CRED_EXPORT_MAGIC "K5C1"
+
+#endif /* _GSSAPIP_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et
new file mode 100644
index 000000000000..6396d5902009
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et
@@ -0,0 +1,42 @@
+#
+# Copyright 1993 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.
+#
+
+error_table k5g
+
+error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name"
+error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name"
+error_code KG_TGT_MISSING, "Credential cache has no TGT"
+error_code KG_NO_SUBKEY, "Authenticator has no subkey"
+error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established"
+error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token"
+error_code KG_BAD_LENGTH, "Invalid field length in token"
+error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context"
+error_code KG_CONTEXT, "Bad magic number for krb5_gss_ctx_id_t"
+error_code KG_CRED, "Bad magic number for krb5_gss_cred_id_t"
+error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc"
+error_code KG_BAD_SEQ, "Sequence number in token is corrupt"
+error_code KG_EMPTY_CCACHE, "Credential cache is empty"
+error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
+error_code KG_LUCID_VERSION, "Requested lucid context version not supported"
+error_code KG_INPUT_TOO_LONG, "PRF input too long"
+error_code KG_IAKERB_CONTEXT, "Bad magic number for iakerb_ctx_id_t"
+end
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
new file mode 100644
index 000000000000..99092ccab16b
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -0,0 +1,1159 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+
+/* For declaration of krb5_ser_context_init */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#include "mglueP.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#endif
+
+/** exported constants defined in gssapi_krb5{,_nx}.h **/
+
+/* these are bogus, but will compile */
+
+/*
+ * The OID of the draft krb5 mechanism, assigned by IETF, is:
+ * iso(1) org(3) dod(5) internet(1) security(5)
+ * kerberosv5(2) = 1.3.5.1.5.2
+ * The OID of the krb5_name type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
+ * The OID of the krb5_principal type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
+ * The OID of the proposed standard krb5 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) = 1.2.840.113554.1.2.2
+ * The OID of the proposed standard krb5 v2 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5v2(3) = 1.2.840.113554.1.2.3
+ * Provisionally reserved for Kerberos session key algorithm
+ * identifiers is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_enctype(4) = 1.2.840.113554.1.2.2.4
+ * Provisionally reserved for Kerberos mechanism-specific APIs:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_gssapi_ext(5) = 1.2.840.113554.1.2.2.5
+ */
+
+/*
+ * Encoding rules: The first two values are encoded in one byte as 40
+ * * value1 + value2. Subsequent values are encoded base 128, most
+ * significant digit first, with the high bit (\200) set on all octets
+ * except the last in each value's encoding.
+ */
+
+#define NO_CI_FLAGS_X_OID_LENGTH 6
+#define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d"
+
+const gss_OID_desc krb5_gss_oid_array[] = {
+ /* this is the official, rfc-specified OID */
+ {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
+ /* this pre-RFC mech OID */
+ {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
+ /* this is the unofficial, incorrect mech OID emitted by MS */
+ {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
+ /* IAKERB OID */
+ {GSS_MECH_IAKERB_OID_LENGTH, GSS_MECH_IAKERB_OID},
+ /* this is the v2 assigned OID */
+ {9, "\052\206\110\206\367\022\001\002\003"},
+ /* these two are name type OID's */
+ /* 2.1.1. Kerberos Principal Name Form: (rfc 1964)
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+ {10, "\052\206\110\206\367\022\001\002\002\001"},
+ /* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
+ {10, "\052\206\110\206\367\022\001\002\002\002"},
+ {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+ { 0, 0 }
+};
+
+#define kg_oids ((gss_OID)krb5_gss_oid_array)
+
+const gss_OID gss_mech_krb5 = &kg_oids[0];
+const gss_OID gss_mech_krb5_old = &kg_oids[1];
+const gss_OID gss_mech_krb5_wrong = &kg_oids[2];
+const gss_OID gss_mech_iakerb = &kg_oids[3];
+
+
+const gss_OID gss_nt_krb5_name = &kg_oids[5];
+const gss_OID gss_nt_krb5_principal = &kg_oids[6];
+const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &kg_oids[5];
+
+const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X = &kg_oids[7];
+
+static const gss_OID_set_desc oidsets[] = {
+ {1, &kg_oids[0]}, /* RFC OID */
+ {1, &kg_oids[1]}, /* pre-RFC OID */
+ {3, &kg_oids[0]}, /* all names for krb5 mech */
+ {4, &kg_oids[0]}, /* all krb5 names and IAKERB */
+};
+
+#define kg_oidsets ((gss_OID_set)oidsets)
+
+const gss_OID_set gss_mech_set_krb5 = &kg_oidsets[0];
+const gss_OID_set gss_mech_set_krb5_old = &kg_oidsets[1];
+const gss_OID_set gss_mech_set_krb5_both = &kg_oidsets[2];
+const gss_OID_set kg_all_mechs = &kg_oidsets[3];
+
+g_set kg_vdb = G_SET_INIT;
+
+/** default credential support */
+
+/*
+ * init_sec_context() will explicitly re-acquire default credentials,
+ * so handling the expiration/invalidation condition here isn't needed.
+ */
+OM_uint32
+kg_get_defcred(minor_status, cred)
+ OM_uint32 *minor_status;
+ gss_cred_id_t *cred;
+{
+ OM_uint32 major;
+
+ if ((major = krb5_gss_acquire_cred(minor_status,
+ (gss_name_t) NULL, GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET, GSS_C_INITIATE,
+ cred, NULL, NULL)) && GSS_ERROR(major)) {
+ return(major);
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
+{
+ OM_uint32 err = 0;
+
+ /*
+ * Sync up the context ccache name with the GSSAPI ccache name.
+ * If kg_ccache_name is NULL -- normal unless someone has called
+ * gss_krb5_ccache_name() -- then the system default ccache will
+ * be picked up and used by resetting the context default ccache.
+ * This is needed for platforms which support multiple ccaches.
+ */
+
+ if (!err) {
+ /* if NULL, resets the context default ccache */
+ err = krb5_cc_set_default_name(context,
+ (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+/* This function returns whether or not the caller set a cccache name. Used by
+ * gss_acquire_cred to figure out if the caller wants to only look at this
+ * ccache or search the cache collection for the desired name */
+OM_uint32
+kg_caller_provided_ccache_name (OM_uint32 *minor_status,
+ int *out_caller_provided_name)
+{
+ if (out_caller_provided_name) {
+ *out_caller_provided_name =
+ (k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME) != NULL);
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+kg_get_ccache_name (OM_uint32 *minor_status, const char **out_name)
+{
+ const char *name = NULL;
+ OM_uint32 err = 0;
+ char *kg_ccache_name;
+
+ kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+
+ if (kg_ccache_name != NULL) {
+ name = strdup(kg_ccache_name);
+ if (name == NULL)
+ err = ENOMEM;
+ } else {
+ krb5_context context = NULL;
+
+ /* Reset the context default ccache (see text above), and then
+ retrieve it. */
+ err = krb5_gss_init_context(&context);
+ if (!err)
+ err = krb5_cc_set_default_name (context, NULL);
+ if (!err) {
+ name = krb5_cc_default_name(context);
+ if (name) {
+ name = strdup(name);
+ if (name == NULL)
+ err = ENOMEM;
+ }
+ }
+ if (err && context)
+ save_error_info(err, context);
+ if (context)
+ krb5_free_context(context);
+ }
+
+ if (!err) {
+ if (out_name) {
+ *out_name = name;
+ }
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+OM_uint32
+kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
+{
+ char *new_name = NULL;
+ char *swap = NULL;
+ char *kg_ccache_name;
+ krb5_error_code kerr;
+
+ if (name) {
+ new_name = strdup(name);
+ if (new_name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+ swap = kg_ccache_name;
+ kg_ccache_name = new_name;
+ new_name = swap;
+ kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
+ if (kerr != 0) {
+ /* Can't store, so free up the storage. */
+ free(kg_ccache_name);
+ /* ??? free(new_name); */
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+
+ free (new_name);
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+#define g_OID_prefix_equal(o1, o2) \
+ (((o1)->length >= (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
+/*
+ * gss_inquire_sec_context_by_oid() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+} krb5_gss_inquire_sec_context_by_oid_ops[] = {
+ {
+ {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
+ gss_krb5int_get_tkt_flags
+ },
+ {
+ {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
+ gss_krb5int_extract_authz_data_from_sec_context
+ },
+ {
+ {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
+ gss_krb5int_inq_session_key
+ },
+ {
+ {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
+ gss_krb5int_export_lucid_sec_context
+ },
+ {
+ {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
+ gss_krb5int_extract_authtime_from_sec_context
+ }
+};
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (data_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established)
+ return GSS_S_NO_CONTEXT;
+
+ for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
+ sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
+ return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
+ context_handle,
+ desired_object,
+ data_set);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gss_inquire_cred_by_oid() methods
+ */
+#if 0
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *);
+} krb5_gss_inquire_cred_by_oid_ops[] = {
+};
+#endif
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+#if 0
+ size_t i;
+#endif
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (data_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = (OM_uint32)KRB5_NOCREDS_SUPPLIED;
+ return GSS_S_NO_CRED;
+ }
+
+ major_status = krb5_gss_validate_cred(minor_status, cred_handle);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+#if 0
+ for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/
+ sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) {
+ return (*krb5_gss_inquire_cred_by_oid_ops[i].func)(minor_status,
+ cred_handle,
+ desired_object,
+ data_set);
+ }
+ }
+#endif
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gss_set_sec_context_option() methods
+ * (Disabled until we have something to populate the array.)
+ */
+#if 0
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
+} krb5_gss_set_sec_context_option_ops[] = {
+};
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+#if 0
+ size_t i;
+#endif
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+#if 0
+ for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
+ sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
+ return (*krb5_gss_set_sec_context_option_ops[i].func)(minor_status,
+ context_handle,
+ desired_object,
+ value);
+ }
+ }
+#endif
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+static OM_uint32
+no_ci_flags(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t cred;
+
+ cred = (krb5_gss_cred_id_t) *cred_handle;
+ cred->suppress_ci_flags = 1;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+/*
+ * gssspi_set_cred_option() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
+} krb5_gssspi_set_cred_option_ops[] = {
+ {
+ {GSS_KRB5_COPY_CCACHE_OID_LENGTH, GSS_KRB5_COPY_CCACHE_OID},
+ gss_krb5int_copy_ccache
+ },
+ {
+ {GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID},
+ gss_krb5int_set_allowable_enctypes
+ },
+ {
+ {GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
+ gss_krb5int_set_cred_rcache
+ },
+ {
+ {GSS_KRB5_IMPORT_CRED_OID_LENGTH, GSS_KRB5_IMPORT_CRED_OID},
+ gss_krb5int_import_cred
+ },
+ {
+ {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+ no_ci_flags
+ },
+};
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gssspi_set_cred_option(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (*cred_handle != GSS_C_NO_CREDENTIAL) {
+ major_status = krb5_gss_validate_cred(minor_status, *cred_handle);
+ if (GSS_ERROR(major_status))
+ return major_status;
+ }
+
+ for (i = 0; i < sizeof(krb5_gssspi_set_cred_option_ops)/
+ sizeof(krb5_gssspi_set_cred_option_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gssspi_set_cred_option_ops[i].oid)) {
+ return (*krb5_gssspi_set_cred_option_ops[i].func)(minor_status,
+ cred_handle,
+ desired_object,
+ value);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gssspi_mech_invoke() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
+} krb5_gssspi_mech_invoke_ops[] = {
+ {
+ {GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID},
+ gss_krb5int_register_acceptor_identity
+ },
+ {
+ {GSS_KRB5_CCACHE_NAME_OID_LENGTH, GSS_KRB5_CCACHE_NAME_OID},
+ gss_krb5int_ccache_name
+ },
+ {
+ {GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID},
+ gss_krb5int_free_lucid_sec_context
+ },
+#ifndef _WIN32
+ {
+ {GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
+ krb5int_gss_use_kdc_context
+ },
+#endif
+};
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gssspi_mech_invoke (OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_mech == GSS_C_NO_OID)
+ return GSS_S_BAD_MECH;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ for (i = 0; i < sizeof(krb5_gssspi_mech_invoke_ops)/
+ sizeof(krb5_gssspi_mech_invoke_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gssspi_mech_invoke_ops[i].oid)) {
+ return (*krb5_gssspi_mech_invoke_ops[i].func)(minor_status,
+ desired_mech,
+ desired_object,
+ value);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+#define GS2_KRB5_SASL_NAME "GS2-KRB5"
+#define GS2_KRB5_SASL_NAME_LEN (sizeof(GS2_KRB5_SASL_NAME) - 1)
+
+#define GS2_IAKERB_SASL_NAME "GS2-IAKERB"
+#define GS2_IAKERB_SASL_NAME_LEN (sizeof(GS2_IAKERB_SASL_NAME) - 1)
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type)
+{
+ *minor_status = 0;
+
+ if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN &&
+ memcmp(sasl_mech_name->value,
+ GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) {
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_krb5;
+ return GSS_S_COMPLETE;
+ } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN &&
+ memcmp(sasl_mech_name->value,
+ GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) {
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ return GSS_S_COMPLETE;
+ }
+
+ return GSS_S_BAD_MECH;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description)
+{
+ if (g_OID_equal(desired_mech, gss_mech_iakerb)) {
+ if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) ||
+ !g_make_string_buffer("iakerb", mech_name) ||
+ !g_make_string_buffer("Initial and Pass Through Authentication "
+ "Kerberos Mechanism (IAKERB)",
+ mech_description))
+ goto fail;
+ } else {
+ if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) ||
+ !g_make_string_buffer("krb5", mech_name) ||
+ !g_make_string_buffer("Kerberos 5 GSS-API Mechanism",
+ mech_description))
+ goto fail;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+fail:
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
+ gss_const_OID mech,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs)
+{
+ OM_uint32 major, tmpMinor;
+
+ if (mech_attrs == NULL) {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ major = gss_create_empty_oid_set(minor_status, mech_attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+#define MA_SUPPORTED(ma) do { \
+ major = gss_add_oid_set_member(minor_status, (gss_OID)ma, \
+ mech_attrs); \
+ if (GSS_ERROR(major)) \
+ goto cleanup; \
+ } while (0)
+
+ MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
+ MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
+ MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
+ MA_SUPPORTED(GSS_C_MA_DELEG_CRED);
+ MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
+ MA_SUPPORTED(GSS_C_MA_CONF_PROT);
+ MA_SUPPORTED(GSS_C_MA_MIC);
+ MA_SUPPORTED(GSS_C_MA_WRAP);
+ MA_SUPPORTED(GSS_C_MA_PROT_READY);
+ MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
+ MA_SUPPORTED(GSS_C_MA_OOS_DET);
+ MA_SUPPORTED(GSS_C_MA_CBINDINGS);
+ MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
+
+ if (g_OID_equal(mech, gss_mech_iakerb)) {
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
+ MA_SUPPORTED(GSS_C_MA_NOT_DFLT_MECH);
+ } else if (!g_OID_equal(mech, gss_mech_krb5)) {
+ MA_SUPPORTED(GSS_C_MA_DEPRECATED);
+ }
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_oid_set(&tmpMinor, mech_attrs);
+
+ return major;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_localname(OM_uint32 *minor,
+ const gss_name_t pname,
+ const gss_const_OID mech_type,
+ gss_buffer_t localname)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char lname[BUFSIZ];
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)pname;
+
+ code = krb5_aname_to_localname(context, kname->princ,
+ sizeof(lname), lname);
+ if (code != 0) {
+ *minor = KRB5_NO_LOCALNAME;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+
+ krb5_free_context(context);
+ localname->value = gssalloc_strdup(lname);
+ localname->length = strlen(lname);
+
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_authorize_localname(OM_uint32 *minor,
+ const gss_name_t pname,
+ gss_const_buffer_t local_user,
+ gss_const_OID name_type)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *user;
+ int user_ok;
+
+ if (name_type != GSS_C_NO_OID &&
+ !g_OID_equal(name_type, GSS_C_NT_USER_NAME)) {
+ return GSS_S_BAD_NAMETYPE;
+ }
+
+ kname = (krb5_gss_name_t)pname;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ user = k5memdup0(local_user->value, local_user->length, &code);
+ if (user == NULL) {
+ *minor = code;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+ user_ok = krb5_kuserok(context, kname->princ, user);
+
+ free(user);
+ krb5_free_context(context);
+
+ *minor = 0;
+ return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED;
+}
+
+static struct gss_config krb5_mechanism = {
+ { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+ NULL,
+ krb5_gss_acquire_cred,
+ krb5_gss_release_cred,
+ krb5_gss_init_sec_context,
+#ifdef LEAN_CLIENT
+ NULL,
+#else
+ krb5_gss_accept_sec_context,
+#endif
+ krb5_gss_process_context_token,
+ krb5_gss_delete_sec_context,
+ krb5_gss_context_time,
+ krb5_gss_get_mic,
+ krb5_gss_verify_mic,
+#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ krb5_gss_wrap,
+#endif
+#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ krb5_gss_unwrap,
+#endif
+ krb5_gss_display_status,
+ krb5_gss_indicate_mechs,
+ krb5_gss_compare_name,
+ krb5_gss_display_name,
+ krb5_gss_import_name,
+ krb5_gss_release_name,
+ krb5_gss_inquire_cred,
+ NULL, /* add_cred */
+#ifdef LEAN_CLIENT
+ NULL,
+ NULL,
+#else
+ krb5_gss_export_sec_context,
+ krb5_gss_import_sec_context,
+#endif
+ krb5_gss_inquire_cred_by_mech,
+ krb5_gss_inquire_names_for_mech,
+ krb5_gss_inquire_context,
+ krb5_gss_internal_release_oid,
+ krb5_gss_wrap_size_limit,
+ krb5_gss_localname,
+
+ krb5_gss_authorize_localname,
+ krb5_gss_export_name,
+ krb5_gss_duplicate_name,
+ krb5_gss_store_cred,
+ krb5_gss_inquire_sec_context_by_oid,
+ krb5_gss_inquire_cred_by_oid,
+ krb5_gss_set_sec_context_option,
+ krb5_gssspi_set_cred_option,
+ krb5_gssspi_mech_invoke,
+ NULL, /* wrap_aead */
+ NULL, /* unwrap_aead */
+ krb5_gss_wrap_iov,
+ krb5_gss_unwrap_iov,
+ krb5_gss_wrap_iov_length,
+ NULL, /* complete_auth_token */
+ krb5_gss_acquire_cred_impersonate_name,
+ NULL, /* krb5_gss_add_cred_impersonate_name */
+ NULL, /* display_name_ext */
+ krb5_gss_inquire_name,
+ krb5_gss_get_name_attribute,
+ krb5_gss_set_name_attribute,
+ krb5_gss_delete_name_attribute,
+ krb5_gss_export_name_composite,
+ krb5_gss_map_name_to_any,
+ krb5_gss_release_any_name_mapping,
+ krb5_gss_pseudo_random,
+ NULL, /* set_neg_mechs */
+ krb5_gss_inquire_saslname_for_mech,
+ krb5_gss_inquire_mech_for_saslname,
+ krb5_gss_inquire_attrs_for_mech,
+ krb5_gss_acquire_cred_from,
+ krb5_gss_store_cred_into,
+ krb5_gss_acquire_cred_with_password,
+ krb5_gss_export_cred,
+ krb5_gss_import_cred,
+ NULL, /* import_sec_context_by_mech */
+ NULL, /* import_name_by_mech */
+ NULL, /* import_cred_by_mech */
+ krb5_gss_get_mic_iov,
+ krb5_gss_verify_mic_iov,
+ krb5_gss_get_mic_iov_length,
+};
+
+/* Functions which use security contexts or acquire creds are IAKERB-specific;
+ * other functions can borrow from the krb5 mech. */
+static struct gss_config iakerb_mechanism = {
+ { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+ NULL,
+ iakerb_gss_acquire_cred,
+ krb5_gss_release_cred,
+ iakerb_gss_init_sec_context,
+#ifdef LEAN_CLIENT
+ NULL,
+#else
+ iakerb_gss_accept_sec_context,
+#endif
+ iakerb_gss_process_context_token,
+ iakerb_gss_delete_sec_context,
+ iakerb_gss_context_time,
+ iakerb_gss_get_mic,
+ iakerb_gss_verify_mic,
+#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ iakerb_gss_wrap,
+#endif
+#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ iakerb_gss_unwrap,
+#endif
+ krb5_gss_display_status,
+ krb5_gss_indicate_mechs,
+ krb5_gss_compare_name,
+ krb5_gss_display_name,
+ krb5_gss_import_name,
+ krb5_gss_release_name,
+ krb5_gss_inquire_cred,
+ NULL, /* add_cred */
+#ifdef LEAN_CLIENT
+ NULL,
+ NULL,
+#else
+ iakerb_gss_export_sec_context,
+ iakerb_gss_import_sec_context,
+#endif
+ krb5_gss_inquire_cred_by_mech,
+ krb5_gss_inquire_names_for_mech,
+ iakerb_gss_inquire_context,
+ krb5_gss_internal_release_oid,
+ iakerb_gss_wrap_size_limit,
+ krb5_gss_localname,
+ krb5_gss_authorize_localname,
+ krb5_gss_export_name,
+ krb5_gss_duplicate_name,
+ krb5_gss_store_cred,
+ iakerb_gss_inquire_sec_context_by_oid,
+ krb5_gss_inquire_cred_by_oid,
+ iakerb_gss_set_sec_context_option,
+ krb5_gssspi_set_cred_option,
+ krb5_gssspi_mech_invoke,
+ NULL, /* wrap_aead */
+ NULL, /* unwrap_aead */
+ iakerb_gss_wrap_iov,
+ iakerb_gss_unwrap_iov,
+ iakerb_gss_wrap_iov_length,
+ NULL, /* complete_auth_token */
+ NULL, /* acquire_cred_impersonate_name */
+ NULL, /* add_cred_impersonate_name */
+ NULL, /* display_name_ext */
+ krb5_gss_inquire_name,
+ krb5_gss_get_name_attribute,
+ krb5_gss_set_name_attribute,
+ krb5_gss_delete_name_attribute,
+ krb5_gss_export_name_composite,
+ krb5_gss_map_name_to_any,
+ krb5_gss_release_any_name_mapping,
+ iakerb_gss_pseudo_random,
+ NULL, /* set_neg_mechs */
+ krb5_gss_inquire_saslname_for_mech,
+ krb5_gss_inquire_mech_for_saslname,
+ krb5_gss_inquire_attrs_for_mech,
+ krb5_gss_acquire_cred_from,
+ krb5_gss_store_cred_into,
+ iakerb_gss_acquire_cred_with_password,
+ krb5_gss_export_cred,
+ krb5_gss_import_cred,
+ NULL, /* import_sec_context_by_mech */
+ NULL, /* import_name_by_mech */
+ NULL, /* import_cred_by_mech */
+ iakerb_gss_get_mic_iov,
+ iakerb_gss_verify_mic_iov,
+ iakerb_gss_get_mic_iov_length,
+};
+
+#ifdef _GSS_STATIC_LINK
+#include "mglueP.h"
+static int gss_iakerbmechglue_init(void)
+{
+ struct gss_mech_config mech_iakerb;
+
+ memset(&mech_iakerb, 0, sizeof(mech_iakerb));
+ mech_iakerb.mech = &iakerb_mechanism;
+
+ mech_iakerb.mechNameStr = "iakerb";
+ mech_iakerb.mech_type = (gss_OID)gss_mech_iakerb;
+ gssint_register_mechinfo(&mech_iakerb);
+
+ return 0;
+}
+
+static int gss_krb5mechglue_init(void)
+{
+ struct gss_mech_config mech_krb5;
+
+ memset(&mech_krb5, 0, sizeof(mech_krb5));
+ mech_krb5.mech = &krb5_mechanism;
+
+ mech_krb5.mechNameStr = "kerberos_v5";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5;
+ gssint_register_mechinfo(&mech_krb5);
+
+ mech_krb5.mechNameStr = "kerberos_v5_old";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5_old;
+ gssint_register_mechinfo(&mech_krb5);
+
+ mech_krb5.mechNameStr = "mskrb";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5_wrong;
+ gssint_register_mechinfo(&mech_krb5);
+
+ return 0;
+}
+#else
+MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
+MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
+
+gss_mechanism KRB5_CALLCONV
+gss_mech_initialize(void)
+{
+ return &krb5_mechanism;
+}
+#endif /* _GSS_STATIC_LINK */
+
+int gss_krb5int_lib_init(void)
+{
+ int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_init\n");
+#endif
+
+ add_error_table(&et_k5g_error_table);
+
+#ifndef LEAN_CLIENT
+ err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
+ if (err)
+ return err;
+#endif /* LEAN_CLIENT */
+ err = k5_key_register(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, free);
+ if (err)
+ return err;
+ err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free);
+ if (err)
+ return err;
+ err = k5_key_register(K5_KEY_GSS_KRB5_ERROR_MESSAGE,
+ krb5_gss_delete_error_info);
+ if (err)
+ return err;
+#ifndef _WIN32
+ err = k5_mutex_finish_init(&kg_kdc_flag_mutex);
+ if (err)
+ return err;
+ err = k5_mutex_finish_init(&kg_vdb.mutex);
+ if (err)
+ return err;
+#endif
+#ifdef _GSS_STATIC_LINK
+ err = gss_krb5mechglue_init();
+ if (err)
+ return err;
+ err = gss_iakerbmechglue_init();
+ if (err)
+ return err;
+#endif
+
+ return 0;
+}
+
+void gss_krb5int_lib_fini(void)
+{
+#ifndef _GSS_STATIC_LINK
+ if (!INITIALIZER_RAN(gss_krb5int_lib_init) || PROGRAM_EXITING()) {
+# ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_fini: skipping\n");
+# endif
+ return;
+ }
+#endif
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_fini\n");
+#endif
+ remove_error_table(&et_k5g_error_table);
+
+ k5_key_delete(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+ k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
+ k5_key_delete(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ k5_mutex_destroy(&kg_vdb.mutex);
+#ifndef _WIN32
+ k5_mutex_destroy(&kg_kdc_flag_mutex);
+#endif
+#ifndef LEAN_CLIENT
+ k5_mutex_destroy(&gssint_krb5_keytab_lock);
+#endif /* LEAN_CLIENT */
+}
+
+#ifdef _GSS_STATIC_LINK
+extern OM_uint32 gssint_lib_init(void);
+#endif
+
+OM_uint32 gss_krb5int_initialize_library (void)
+{
+#ifdef _GSS_STATIC_LINK
+ return gssint_mechglue_initialize_library();
+#else
+ return CALL_INIT_FUNCTION(gss_krb5int_lib_init);
+#endif
+}
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
new file mode 100644
index 000000000000..390b00032cce
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -0,0 +1,281 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#ifndef _GSSAPI_KRB5_H_
+#define _GSSAPI_KRB5_H_
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+#include <krb5.h>
+#include <stdint.h>
+
+/* C++ friendlyness */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Reserved static storage for GSS_oids. See rfc 1964 for more details. */
+
+/* 2.1.1. Kerberos Principal Name Form: */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+
+/* 2.1.2. Host-Based Service Name Form */
+#define GSS_KRB5_NT_HOSTBASED_SERVICE_NAME GSS_C_NT_HOSTBASED_SERVICE
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The previously recommended symbolic
+ * name for this type is "GSS_KRB5_NT_HOSTBASED_SERVICE_NAME". The
+ * currently preferred symbolic name for this type is
+ * "GSS_C_NT_HOSTBASED_SERVICE". */
+
+/* 2.2.1. User Name Form */
+#define GSS_KRB5_NT_USER_NAME GSS_C_NT_USER_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}. The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME". */
+
+/* 2.2.2. Machine UID Form */
+#define GSS_KRB5_NT_MACHINE_UID_NAME GSS_C_NT_MACHINE_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME". */
+
+/* 2.2.3. String UID Form */
+#define GSS_KRB5_NT_STRING_UID_NAME GSS_C_NT_STRING_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME". */
+
+GSS_DLLIMP extern const gss_OID gss_mech_krb5;
+GSS_DLLIMP extern const gss_OID gss_mech_krb5_old;
+GSS_DLLIMP extern const gss_OID gss_mech_krb5_wrong;
+GSS_DLLIMP extern const gss_OID gss_mech_iakerb;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5_old;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5_both;
+
+GSS_DLLIMP extern const gss_OID gss_nt_krb5_name;
+GSS_DLLIMP extern const gss_OID gss_nt_krb5_principal;
+
+GSS_DLLIMP extern const gss_OID_desc krb5_gss_oid_array[];
+
+/*
+ * This OID can be used with gss_set_cred_option() to suppress the
+ * confidentiality and integrity flags from being asserted in initial context
+ * tokens.
+ *
+ * iso(1) member-body(2) Sweden(752) Stockholm University(43) Heimdal GSS-API
+ * Extensions(13) no_ci_flags(29)
+ */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X;
+
+#define gss_krb5_nt_general_name gss_nt_krb5_name
+#define gss_krb5_nt_principal gss_nt_krb5_principal
+#define gss_krb5_nt_service_name gss_nt_service_name
+#define gss_krb5_nt_user_name gss_nt_user_name
+#define gss_krb5_nt_machine_uid_name gss_nt_machine_uid_name
+#define gss_krb5_nt_string_uid_name gss_nt_string_uid_name
+
+typedef struct gss_krb5_lucid_key {
+ OM_uint32 type; /* key encryption type */
+ OM_uint32 length; /* length of key data */
+ void * data; /* actual key data */
+} gss_krb5_lucid_key_t;
+
+typedef struct gss_krb5_rfc1964_keydata {
+ OM_uint32 sign_alg; /* signing algorthm */
+ OM_uint32 seal_alg; /* seal/encrypt algorithm */
+ gss_krb5_lucid_key_t ctx_key;
+ /* Context key
+ (Kerberos session key or subkey) */
+} gss_krb5_rfc1964_keydata_t;
+
+typedef struct gss_krb5_cfx_keydata {
+ OM_uint32 have_acceptor_subkey;
+ /* 1 if there is an acceptor_subkey
+ present, 0 otherwise */
+ gss_krb5_lucid_key_t ctx_key;
+ /* Context key
+ (Kerberos session key or subkey) */
+ gss_krb5_lucid_key_t acceptor_subkey;
+ /* acceptor-asserted subkey or
+ 0's if no acceptor subkey */
+} gss_krb5_cfx_keydata_t;
+
+typedef struct gss_krb5_lucid_context_v1 {
+ OM_uint32 version; /* Structure version number (1)
+ MUST be at beginning of struct! */
+ OM_uint32 initiate; /* Are we the initiator? */
+ OM_uint32 endtime; /* expiration time of context */
+ uint64_t send_seq; /* sender sequence number */
+ uint64_t recv_seq; /* receive sequence number */
+ OM_uint32 protocol; /* 0: rfc1964,
+ 1: draft-ietf-krb-wg-gssapi-cfx-07 */
+ /*
+ * if (protocol == 0) rfc1964_kd should be used
+ * and cfx_kd contents are invalid and should be zero
+ * if (protocol == 1) cfx_kd should be used
+ * and rfc1964_kd contents are invalid and should be zero
+ */
+ gss_krb5_rfc1964_keydata_t rfc1964_kd;
+ gss_krb5_cfx_keydata_t cfx_kd;
+} gss_krb5_lucid_context_v1_t;
+
+/*
+ * Mask for determining the version of a lucid context structure. Callers
+ * should not require this.
+ */
+typedef struct gss_krb5_lucid_context_version {
+ OM_uint32 version; /* Structure version number */
+} gss_krb5_lucid_context_version_t;
+
+
+
+
+/* Alias for Heimdal compat. */
+#define gsskrb5_register_acceptor_identity krb5_gss_register_acceptor_identity
+
+OM_uint32 KRB5_CALLCONV krb5_gss_register_acceptor_identity(const char *);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_get_tkt_flags(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_ccache_name(
+ OM_uint32 *minor_status, const char *name,
+ const char **out_name);
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred' must be a valid credential handle obtained via
+ * gss_acquire_cred(). It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may have been called to get a handle to
+ * the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes);
+
+/*
+ * Returns a non-opaque (lucid) version of the internal context
+ * information.
+ *
+ * Note that context_handle must not be used again by the caller
+ * after this call. The GSS implementation is free to release any
+ * resources associated with the original context. It is up to the
+ * GSS implementation whether it returns pointers to existing data,
+ * or copies of the data. The caller should treat the returned
+ * lucid context as read-only.
+ *
+ * The caller must call gss_krb5_free_lucid_context() to free
+ * the context and allocated resources when it is finished with it.
+ *
+ * 'version' is an integer indicating the requested version of the lucid
+ * context. If the implementation does not understand the requested version,
+ * it will return an error.
+ *
+ * For example:
+ * void *return_ctx;
+ * gss_krb5_lucid_context_v1_t *ctx;
+ * OM_uint32 min_stat, maj_stat;
+ * OM_uint32 vers;
+ * gss_ctx_id_t *ctx_handle;
+ *
+ * maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
+ * ctx_handle, 1, &return_ctx);
+ * // Verify success
+ * ctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx);
+
+/*
+ * Frees the allocated storage associated with an
+ * exported struct gss_krb5_lucid_context.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status,
+ void *kctx);
+
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int ad_type,
+ gss_buffer_t ad_data);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ krb5_rcache rcache);
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *, gss_ctx_id_t, krb5_timestamp *);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_import_cred(OM_uint32 *minor_status,
+ krb5_ccache id,
+ krb5_principal keytab_principal,
+ krb5_keytab keytab,
+ gss_cred_id_t *cred);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _GSSAPI_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
new file mode 100644
index 000000000000..2dc4d0c1a4d5
--- /dev/null
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -0,0 +1,1329 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/*
+ * IAKERB implementation
+ */
+
+extern int gssint_get_der_length(unsigned char **, OM_uint32, unsigned int*);
+
+enum iakerb_state {
+ IAKERB_AS_REQ, /* acquiring ticket with initial creds */
+ IAKERB_TGS_REQ, /* acquiring ticket with TGT */
+ IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */
+};
+
+struct _iakerb_ctx_id_rec {
+ krb5_magic magic; /* KG_IAKERB_CONTEXT */
+ krb5_context k5c;
+ gss_cred_id_t defcred; /* Initiator only */
+ enum iakerb_state state; /* Initiator only */
+ krb5_init_creds_context icc; /* Initiator only */
+ krb5_tkt_creds_context tcc; /* Initiator only */
+ gss_ctx_id_t gssc;
+ krb5_data conv; /* conversation for checksumming */
+ unsigned int count; /* number of round trips */
+ int initiate;
+ int established;
+ krb5_get_init_creds_opt *gic_opts;
+};
+
+#define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS )
+
+typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec;
+typedef iakerb_ctx_id_rec *iakerb_ctx_id_t;
+
+/*
+ * Release an IAKERB context
+ */
+static void
+iakerb_release_context(iakerb_ctx_id_t ctx)
+{
+ OM_uint32 tmp;
+
+ if (ctx == NULL)
+ return;
+
+ krb5_gss_release_cred(&tmp, &ctx->defcred);
+ krb5_init_creds_free(ctx->k5c, ctx->icc);
+ krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
+ krb5_gss_delete_sec_context(&tmp, &ctx->gssc, NULL);
+ krb5_free_data_contents(ctx->k5c, &ctx->conv);
+ krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts);
+ krb5_free_context(ctx->k5c);
+ free(ctx);
+}
+
+/*
+ * Create a IAKERB-FINISHED structure containing a checksum of
+ * the entire IAKERB exchange.
+ */
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished)
+{
+ krb5_error_code code;
+ krb5_iakerb_finished iaf;
+
+ *finished = NULL;
+
+ memset(&iaf, 0, sizeof(iaf));
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = krb5_k_make_checksum(context, 0, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf.checksum);
+ if (code != 0)
+ return code;
+
+ code = encode_krb5_iakerb_finished(&iaf, finished);
+
+ krb5_free_checksum_contents(context, &iaf.checksum);
+
+ return code;
+}
+
+/*
+ * Verify a IAKERB-FINISHED structure submitted by the initiator
+ */
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished)
+{
+ krb5_error_code code;
+ krb5_iakerb_finished *iaf;
+ krb5_boolean valid = FALSE;
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = decode_krb5_iakerb_finished(finished, &iaf);
+ if (code != 0)
+ return code;
+
+ code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf->checksum, &valid);
+ if (code == 0 && valid == FALSE)
+ code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+ krb5_free_iakerb_finished(context, iaf);
+
+ return code;
+}
+
+/*
+ * Save a token for future checksumming.
+ */
+static krb5_error_code
+iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token)
+{
+ char *p;
+
+ p = realloc(ctx->conv.data, ctx->conv.length + token->length);
+ if (p == NULL)
+ return ENOMEM;
+
+ memcpy(p + ctx->conv.length, token->value, token->length);
+ ctx->conv.data = p;
+ ctx->conv.length += token->length;
+
+ return 0;
+}
+
+/*
+ * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_parse_token(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t token,
+ krb5_data *realm,
+ krb5_data **cookie,
+ krb5_data *request)
+{
+ krb5_error_code code;
+ krb5_iakerb_header *iah = NULL;
+ unsigned int bodysize, lenlen;
+ int length;
+ unsigned char *ptr;
+ int flags = 0;
+ krb5_data data;
+
+ if (token == GSS_C_NO_BUFFER || token->length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ if (initialContextToken)
+ flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
+
+ ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, flags);
+ if (code != 0)
+ goto cleanup;
+
+ data.data = (char *)ptr;
+
+ if (bodysize-- == 0 || *ptr++ != 0x30 /* SEQUENCE */) {
+ code = ASN1_BAD_ID;
+ goto cleanup;
+ }
+
+ length = gssint_get_der_length(&ptr, bodysize, &lenlen);
+ if (length < 0 || bodysize - lenlen < (unsigned int)length) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+ data.length = 1 /* SEQUENCE */ + lenlen + length;
+
+ ptr += length;
+ bodysize -= (lenlen + length);
+
+ code = decode_krb5_iakerb_header(&data, &iah);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm != NULL) {
+ *realm = iah->target_realm;
+ iah->target_realm.data = NULL;
+ }
+
+ if (cookie != NULL) {
+ *cookie = iah->cookie;
+ iah->cookie = NULL;
+ }
+
+ request->data = (char *)ptr;
+ request->length = bodysize;
+
+ assert(request->data + request->length ==
+ (char *)token->value + token->length);
+
+cleanup:
+ krb5_free_iakerb_header(ctx->k5c, iah);
+
+ return code;
+}
+
+/*
+ * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_make_token(iakerb_ctx_id_t ctx,
+ krb5_data *realm,
+ krb5_data *cookie,
+ krb5_data *request,
+ int initialContextToken,
+ gss_buffer_t token)
+{
+ krb5_error_code code;
+ krb5_iakerb_header iah;
+ krb5_data *data = NULL;
+ char *p;
+ unsigned int tokenSize;
+ unsigned char *q;
+
+ token->value = NULL;
+ token->length = 0;
+
+ /*
+ * Assemble the IAKERB-HEADER from the realm and cookie
+ */
+ memset(&iah, 0, sizeof(iah));
+ iah.target_realm = *realm;
+ iah.cookie = cookie;
+
+ code = encode_krb5_iakerb_header(&iah, &data);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Concatenate Kerberos request.
+ */
+ p = realloc(data->data, data->length + request->length);
+ if (p == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ data->data = p;
+
+ if (request->length > 0)
+ memcpy(data->data + data->length, request->data, request->length);
+ data->length += request->length;
+
+ if (initialContextToken)
+ tokenSize = g_token_size(gss_mech_iakerb, data->length);
+ else
+ tokenSize = 2 + data->length;
+
+ token->value = q = gssalloc_malloc(tokenSize);
+ if (q == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ token->length = tokenSize;
+
+ if (initialContextToken) {
+ g_make_token_header(gss_mech_iakerb, data->length, &q,
+ IAKERB_TOK_PROXY);
+ } else {
+ store_16_be(IAKERB_TOK_PROXY, q);
+ q += 2;
+ }
+ memcpy(q, data->data, data->length);
+ q += data->length;
+
+ assert(q == (unsigned char *)token->value + token->length);
+
+cleanup:
+ krb5_free_data(ctx->k5c, data);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and send the contained KDC
+ * request to the KDC for the realm.
+ *
+ * Wrap the KDC reply in output_token.
+ */
+static krb5_error_code
+iakerb_acceptor_step(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code;
+ krb5_data request = empty_data(), reply = empty_data();
+ krb5_data realm = empty_data();
+ OM_uint32 tmp;
+ int tcp_only, use_master;
+ krb5_ui_4 kdc_code;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (ctx->count >= IAKERB_MAX_HOPS) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+
+ code = iakerb_parse_token(ctx, initialContextToken, input_token, &realm,
+ NULL, &request);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm.length == 0 || request.length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+
+ for (tcp_only = 0; tcp_only <= 1; tcp_only++) {
+ use_master = 0;
+ code = krb5_sendto_kdc(ctx->k5c, &request, &realm,
+ &reply, &use_master, tcp_only);
+ if (code == 0 && krb5_is_krb_error(&reply)) {
+ krb5_error *error;
+
+ code = decode_krb5_error(&reply, &error);
+ if (code != 0)
+ goto cleanup;
+ kdc_code = error->error;
+ krb5_free_error(ctx->k5c, error);
+ if (kdc_code == KRB_ERR_RESPONSE_TOO_BIG) {
+ krb5_free_data_contents(ctx->k5c, &reply);
+ reply = empty_data();
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) {
+ krb5_error error;
+
+ memset(&error, 0, sizeof(error));
+ if (code == KRB5_KDC_UNREACH)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE;
+ else if (code == KRB5_REALM_UNKNOWN)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NOT_FOUND;
+
+ code = krb5_mk_error(ctx->k5c, &error, &reply);
+ if (code != 0)
+ goto cleanup;
+ } else if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_token(ctx, &realm, NULL, &reply, 0, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ /* request is a pointer into input_token, no need to free */
+ krb5_free_data_contents(ctx->k5c, &realm);
+ krb5_free_data_contents(ctx->k5c, &reply);
+
+ return code;
+}
+
+/*
+ * Initialise the krb5_init_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ OM_uint32 time_req)
+{
+ krb5_error_code code;
+
+ if (cred->iakerb_mech == 0) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE)
+ krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req);
+
+ code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts,
+ cred->ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_init_creds_init(ctx->k5c,
+ cred->name->princ,
+ NULL, /* prompter */
+ NULL, /* data */
+ 0, /* start_time */
+ ctx->gic_opts,
+ &ctx->icc);
+ if (code != 0)
+ goto cleanup;
+
+ if (cred->password != NULL) {
+ code = krb5_init_creds_set_password(ctx->k5c, ctx->icc,
+ cred->password);
+ } else if (cred->client_keytab != NULL) {
+ code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc,
+ cred->client_keytab);
+ } else {
+ code = KRB5_KT_NOTFOUND;
+ }
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ return code;
+}
+
+/*
+ * Initialise the krb5_tkt_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req)
+
+{
+ krb5_error_code code;
+ krb5_creds creds;
+ krb5_timestamp now;
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ memset(&creds, 0, sizeof(creds));
+
+ creds.client = cred->name->princ;
+ creds.server = name->princ;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ creds.times.endtime = now + time_req;
+ }
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_init(ctx->k5c, cred->ccache, &creds, 0, &ctx->tcc);
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, creds.authdata);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and process the KDC
+ * response.
+ *
+ * Emit the next KDC request, if any, in output_token.
+ */
+static krb5_error_code
+iakerb_initiator_step(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code = 0;
+ krb5_data in = empty_data(), out = empty_data(), realm = empty_data();
+ krb5_data *cookie = NULL;
+ OM_uint32 tmp;
+ unsigned int flags = 0;
+ krb5_ticket_times times;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (input_token != GSS_C_NO_BUFFER) {
+ code = iakerb_parse_token(ctx, 0, input_token, NULL, &cookie, &in);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ switch (ctx->state) {
+ case IAKERB_AS_REQ:
+ if (ctx->icc == NULL) {
+ code = iakerb_init_creds_ctx(ctx, cred, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_init_creds_step(ctx->k5c, ctx->icc, &in, &out, &realm,
+ &flags);
+ if (code != 0) {
+ if (cred->have_tgt) {
+ /* We were trying to refresh; keep going with current creds. */
+ ctx->state = IAKERB_TGS_REQ;
+ krb5_clear_error_message(ctx->k5c);
+ } else {
+ goto cleanup;
+ }
+ } else if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) {
+ krb5_init_creds_get_times(ctx->k5c, ctx->icc, &times);
+ kg_cred_set_initial_refresh(ctx->k5c, cred, &times);
+ cred->expire = times.endtime;
+
+ krb5_init_creds_free(ctx->k5c, ctx->icc);
+ ctx->icc = NULL;
+
+ ctx->state = IAKERB_TGS_REQ;
+ } else
+ break;
+ in = empty_data();
+ /* Done with AS request; fall through to TGS request. */
+ case IAKERB_TGS_REQ:
+ if (ctx->tcc == NULL) {
+ code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_step(ctx->k5c, ctx->tcc, &in, &out, &realm,
+ &flags);
+ if (code != 0)
+ goto cleanup;
+ if (!(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) {
+ krb5_tkt_creds_get_times(ctx->k5c, ctx->tcc, &times);
+ cred->expire = times.endtime;
+
+ krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
+ ctx->tcc = NULL;
+
+ ctx->state = IAKERB_AP_REQ;
+ } else
+ break;
+ /* Done with TGS request; fall through to AP request. */
+ case IAKERB_AP_REQ:
+ break;
+ }
+
+ if (out.length != 0) {
+ assert(ctx->state != IAKERB_AP_REQ);
+
+ code = iakerb_make_token(ctx, &realm, cookie, &out,
+ (input_token == GSS_C_NO_BUFFER),
+ output_token);
+ if (code != 0)
+ goto cleanup;
+
+ /* Save the token for generating a future checksum */
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+ }
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ krb5_free_data(ctx->k5c, cookie);
+ krb5_free_data_contents(ctx->k5c, &out);
+ krb5_free_data_contents(ctx->k5c, &realm);
+
+ return code;
+}
+
+/*
+ * Determine the starting IAKERB state for a context. If we already
+ * have a ticket, we may not need to do IAKERB at all.
+ */
+static krb5_error_code
+iakerb_get_initial_state(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t target,
+ OM_uint32 time_req,
+ enum iakerb_state *state)
+{
+ krb5_creds in_creds, *out_creds = NULL;
+ krb5_error_code code;
+
+ memset(&in_creds, 0, sizeof(in_creds));
+
+ in_creds.client = cred->name->princ;
+ in_creds.server = target->princ;
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ in_creds.times.endtime = now + time_req;
+ }
+
+ /* Make an AS request if we have no creds or it's time to refresh them. */
+ if (cred->expire == 0 || kg_cred_time_to_refresh(ctx->k5c, cred)) {
+ *state = IAKERB_AS_REQ;
+ code = 0;
+ goto cleanup;
+ }
+
+ code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED, cred->ccache,
+ &in_creds, &out_creds);
+ if (code == KRB5_CC_NOTFOUND || code == KRB5_CC_NOT_KTYPE) {
+ *state = cred->have_tgt ? IAKERB_TGS_REQ : IAKERB_AS_REQ;
+ code = 0;
+ } else if (code == 0) {
+ *state = IAKERB_AP_REQ;
+ krb5_free_creds(ctx->k5c, out_creds);
+ }
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, in_creds.authdata);
+
+ return code;
+}
+
+/*
+ * Allocate and initialise an IAKERB context
+ */
+static krb5_error_code
+iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate)
+{
+ iakerb_ctx_id_t ctx;
+ krb5_error_code code;
+
+ *pctx = NULL;
+
+ ctx = k5alloc(sizeof(*ctx), &code);
+ if (ctx == NULL)
+ goto cleanup;
+ ctx->defcred = GSS_C_NO_CREDENTIAL;
+ ctx->magic = KG_IAKERB_CONTEXT;
+ ctx->state = IAKERB_AS_REQ;
+ ctx->count = 0;
+ ctx->initiate = initiate;
+ ctx->established = 0;
+
+ code = krb5_gss_init_context(&ctx->k5c);
+ if (code != 0)
+ goto cleanup;
+
+ *pctx = ctx;
+
+cleanup:
+ if (code != 0)
+ iakerb_release_context(ctx);
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ *minor_status = 0;
+ *context_handle = GSS_C_NO_CONTEXT;
+ iakerb_release_context(iakerb_ctx);
+
+ return GSS_S_COMPLETE;
+}
+
+static krb5_boolean
+iakerb_is_iakerb_token(const gss_buffer_t token)
+{
+ krb5_error_code code;
+ unsigned int bodysize = token->length;
+ unsigned char *ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, 0);
+
+ return (code == 0);
+}
+
+static void
+iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts)
+{
+ memset(exts, 0, sizeof(*exts));
+
+ if (ctx->conv.length != 0)
+ exts->iakerb.conv = &ctx->conv;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 code;
+ iakerb_ctx_id_t ctx;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx, 0);
+ if (code != 0)
+ goto cleanup;
+
+ } else
+ ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (iakerb_is_iakerb_token(input_token)) {
+ if (ctx->gssc != GSS_C_NO_CONTEXT) {
+ /* We shouldn't get an IAKERB token now. */
+ code = G_WRONG_TOKID;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ code = iakerb_acceptor_step(ctx, initialContextToken,
+ input_token, output_token);
+ if (code == (OM_uint32)KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0)
+ goto cleanup;
+ if (initialContextToken) {
+ *context_handle = (gss_ctx_id_t)ctx;
+ ctx = NULL;
+ }
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ } else {
+ krb5_gss_ctx_ext_rec exts;
+
+ iakerb_make_exts(ctx, &exts);
+
+ major_status = krb5_gss_accept_sec_context_ext(&code,
+ &ctx->gssc,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ NULL,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+ if (major_status == GSS_S_COMPLETE)
+ ctx->established = 1;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_krb5;
+ }
+
+cleanup:
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ *minor_status = code;
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ krb5_error_code code;
+ iakerb_ctx_id_t ctx;
+ krb5_gss_cred_id_t kcred;
+ krb5_gss_name_t kname;
+ krb5_boolean cred_locked = FALSE;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx, 1);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = iakerb_gss_acquire_cred(minor_status, NULL,
+ GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET,
+ GSS_C_INITIATE,
+ &ctx->defcred, NULL, NULL);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+ claimant_cred_handle = ctx->defcred;
+ }
+ } else {
+ ctx = (iakerb_ctx_id_t)*context_handle;
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
+ claimant_cred_handle = ctx->defcred;
+ }
+
+ kname = (krb5_gss_name_t)target_name;
+
+ major_status = kg_cred_resolve(minor_status, ctx->k5c,
+ claimant_cred_handle, target_name);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+ cred_locked = TRUE;
+ kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
+
+ major_status = GSS_S_FAILURE;
+
+ if (initialContextToken) {
+ code = iakerb_get_initial_state(ctx, kcred, kname, time_req,
+ &ctx->state);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ *context_handle = (gss_ctx_id_t)ctx;
+ }
+
+ if (ctx->state != IAKERB_AP_REQ) {
+ /* We need to do IAKERB. */
+ code = iakerb_initiator_step(ctx,
+ kcred,
+ kname,
+ time_req,
+ input_token,
+ output_token);
+ if (code == KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ }
+
+ if (ctx->state == IAKERB_AP_REQ) {
+ krb5_gss_ctx_ext_rec exts;
+
+ if (cred_locked) {
+ k5_mutex_unlock(&kcred->lock);
+ cred_locked = FALSE;
+ }
+
+ iakerb_make_exts(ctx, &exts);
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ input_token = GSS_C_NO_BUFFER;
+
+ /* IAKERB is finished, or we skipped to Kerberos directly. */
+ major_status = krb5_gss_init_sec_context_ext(minor_status,
+ (gss_cred_id_t) kcred,
+ &ctx->gssc,
+ target_name,
+ (gss_OID)gss_mech_iakerb,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ NULL,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+ if (major_status == GSS_S_COMPLETE)
+ ctx->established = 1;
+ if (actual_mech_type != NULL)
+ *actual_mech_type = (gss_OID)gss_mech_krb5;
+ } else {
+ if (actual_mech_type != NULL)
+ *actual_mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ }
+
+cleanup:
+ if (cred_locked)
+ k5_mutex_unlock(&kcred->lock);
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer, int *conf_state,
+ gss_qop_t *qop_state)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer,
+ output_message_buffer, conf_state, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer, int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ return krb5_gss_process_context_token(minor_status, ctx->gssc,
+ token_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_context_time(minor_status, ctx->gssc, time_rec);
+}
+
+#ifndef LEAN_CLIENT
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 maj;
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
+
+ /* We don't currently support exporting partially established contexts. */
+ if (!ctx->established)
+ return GSS_S_UNAVAILABLE;
+
+ maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc,
+ interprocess_token);
+ if (ctx->gssc == GSS_C_NO_CONTEXT) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ return maj;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+ gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 maj, tmpmin;
+ krb5_error_code code;
+ gss_ctx_id_t gssc;
+ krb5_gss_ctx_id_t kctx;
+ iakerb_ctx_id_t ctx;
+
+ maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
+ if (maj != GSS_S_COMPLETE)
+ return maj;
+ kctx = (krb5_gss_ctx_id_t)gssc;
+
+ if (!kctx->established) {
+ /* We don't currently support importing partially established
+ * contexts. */
+ krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+ return GSS_S_FAILURE;
+ }
+
+ code = iakerb_alloc_context(&ctx, kctx->initiate);
+ if (code != 0) {
+ krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ ctx->gssc = gssc;
+ ctx->established = 1;
+ *context_handle = (gss_ctx_id_t)ctx;
+ return GSS_S_COMPLETE;
+}
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_name_t *src_name,
+ gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+ gss_OID *mech_type, OM_uint32 *ctx_flags,
+ int *initiate, int *opened)
+{
+ OM_uint32 ret;
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (targ_name != NULL)
+ *targ_name = GSS_C_NO_NAME;
+ if (lifetime_rec != NULL)
+ *lifetime_rec = 0;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ if (ctx_flags != NULL)
+ *ctx_flags = 0;
+ if (initiate != NULL)
+ *initiate = ctx->initiate;
+ if (opened != NULL)
+ *opened = ctx->established;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_COMPLETE;
+
+ ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name,
+ targ_name, lifetime_rec, mech_type,
+ ctx_flags, initiate, opened);
+
+ if (!ctx->established) {
+ /* Report IAKERB as the mech OID until the context is established. */
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+
+ /* We don't support exporting partially-established contexts. */
+ if (ctx_flags != NULL)
+ *ctx_flags &= ~GSS_C_TRANS_FLAG;
+ }
+
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag,
+ qop_req, req_output_size, max_input_size);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer,
+ message_token);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+ gss_qop_t *qop_state)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer,
+ token_buffer, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_UNAVAILABLE;
+
+ return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc,
+ desired_object, data_set);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_UNAVAILABLE;
+
+ return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc,
+ desired_object, value);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int *conf_state, gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state,
+ iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag,
+ qop_req, conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int prf_key, const gss_buffer_t prf_in,
+ ssize_t desired_output_len, gss_buffer_t prf_out)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in,
+ desired_output_len, prf_out);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov,
+ iov_count);
+}
diff --git a/src/lib/gssapi/krb5/import_cred.c b/src/lib/gssapi/krb5/import_cred.c
new file mode 100644
index 000000000000..f0a0373bfb79
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_cred.c
@@ -0,0 +1,648 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/import_cred.c - krb5 import_cred implementation */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "k5-json.h"
+#include "gssapiP_krb5.h"
+
+/* Return the idx element of array if it is of type tid; otherwise return
+ * NULL. The caller is responsible for checking the array length. */
+static k5_json_value
+check_element(k5_json_array array, size_t idx, k5_json_tid tid)
+{
+ k5_json_value v;
+
+ v = k5_json_array_get(array, idx);
+ return (k5_json_get_tid(v) == tid) ? v : NULL;
+}
+
+/* All of the json_to_x functions return 0 on success, -1 on failure (either
+ * from running out of memory or from defective input). */
+
+/* Convert a JSON value to a C string or to NULL. */
+static int
+json_to_optional_string(k5_json_value v, char **string_out)
+{
+ *string_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ *string_out = strdup(k5_json_string_utf8(v));
+ return (*string_out == NULL) ? -1 : 0;
+}
+
+/* Convert a JSON value to a principal or to NULL. */
+static int
+json_to_principal(krb5_context context, k5_json_value v,
+ krb5_principal *princ_out)
+{
+ *princ_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_parse_name(context, k5_json_string_utf8(v), princ_out))
+ return -1;
+ return 0;
+}
+
+/* Convert a JSON value to a zero-terminated enctypes list or to NULL. */
+static int
+json_to_etypes(k5_json_value v, krb5_enctype **etypes_out)
+{
+ krb5_enctype *etypes = NULL;
+ k5_json_array array;
+ k5_json_number n;
+ size_t len, i;
+
+ *etypes_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ etypes = calloc(len + 1, sizeof(*etypes));
+ for (i = 0; i < len; i++) {
+ n = check_element(array, i, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ etypes[i] = k5_json_number_value(n);
+ }
+ *etypes_out = etypes;
+ return 0;
+
+invalid:
+ free(etypes);
+ return -1;
+}
+
+/* Convert a JSON value to a krb5 GSS name or to NULL. */
+static int
+json_to_kgname(krb5_context context, k5_json_value v,
+ krb5_gss_name_t *name_out)
+{
+ k5_json_array array;
+ krb5_gss_name_t name = NULL;
+
+ *name_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 3)
+ return -1;
+ name = calloc(1, sizeof(*name));
+ if (name == NULL)
+ return -1;
+ if (k5_mutex_init(&name->lock)) {
+ free(name);
+ return -1;
+ }
+
+ if (json_to_principal(context, k5_json_array_get(array, 0), &name->princ))
+ goto invalid;
+ if (json_to_optional_string(k5_json_array_get(array, 1), &name->service))
+ goto invalid;
+ if (json_to_optional_string(k5_json_array_get(array, 2), &name->host))
+ goto invalid;
+
+ *name_out = name;
+ return 0;
+
+invalid:
+ kg_release_name(context, &name);
+ return -1;
+}
+
+/* Convert a JSON value to a keytab handle or to NULL. */
+static int
+json_to_keytab(krb5_context context, k5_json_value v, krb5_keytab *keytab_out)
+{
+ *keytab_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_kt_resolve(context, k5_json_string_utf8(v), keytab_out))
+ return -1;
+ return 0;
+}
+
+/* Convert a JSON value to an rcache handle or to NULL. */
+static int
+json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out)
+{
+ krb5_rcache rcache;
+
+ *rcache_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_rc_resolve_full(context, &rcache, (char *)k5_json_string_utf8(v)))
+ return -1;
+ if (krb5_rc_recover_or_initialize(context, rcache, context->clockskew)) {
+ krb5_rc_close(context, rcache);
+ return -1;
+ }
+ *rcache_out = rcache;
+ return 0;
+}
+
+/* Convert a JSON value to a keyblock, filling in keyblock. */
+static int
+json_to_keyblock(k5_json_value v, krb5_keyblock *keyblock)
+{
+ k5_json_array array;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ memset(keyblock, 0, sizeof(*keyblock));
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ keyblock->enctype = k5_json_number_value(n);
+
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+ if (k5_json_string_unbase64(s, &keyblock->contents, &len))
+ return -1;
+ keyblock->length = len;
+ keyblock->magic = KV5M_KEYBLOCK;
+ return 0;
+}
+
+/* Convert a JSON value to a krb5 address. */
+static int
+json_to_address(k5_json_value v, krb5_address **addr_out)
+{
+ k5_json_array array;
+ krb5_address *addr = NULL;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ *addr_out = NULL;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+
+ addr = malloc(sizeof(*addr));
+ if (addr == NULL)
+ return -1;
+ addr->addrtype = k5_json_number_value(n);
+ if (k5_json_string_unbase64(s, &addr->contents, &len)) {
+ free(addr);
+ return -1;
+ }
+ addr->length = len;
+ addr->magic = KV5M_ADDRESS;
+ *addr_out = addr;
+ return 0;
+}
+
+/* Convert a JSON value to a null-terminated list of krb5 addresses or to
+ * NULL. */
+static int
+json_to_addresses(krb5_context context, k5_json_value v,
+ krb5_address ***addresses_out)
+{
+ k5_json_array array;
+ krb5_address **addrs = NULL;
+ size_t len, i;
+
+ *addresses_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ addrs = calloc(len + 1, sizeof(*addrs));
+ for (i = 0; i < len; i++) {
+ if (json_to_address(k5_json_array_get(array, i), &addrs[i]))
+ goto invalid;
+ }
+ addrs[i] = NULL;
+ *addresses_out = addrs;
+ return 0;
+
+invalid:
+ krb5_free_addresses(context, addrs);
+ return -1;
+}
+
+/* Convert a JSON value to an authdata element. */
+static int
+json_to_authdata_element(k5_json_value v, krb5_authdata **ad_out)
+{
+ k5_json_array array;
+ krb5_authdata *ad = NULL;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ *ad_out = NULL;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+
+ ad = malloc(sizeof(*ad));
+ if (ad == NULL)
+ return -1;
+ ad->ad_type = k5_json_number_value(n);
+ if (k5_json_string_unbase64(s, &ad->contents, &len)) {
+ free(ad);
+ return -1;
+ }
+ ad->length = len;
+ ad->magic = KV5M_AUTHDATA;
+ *ad_out = ad;
+ return 0;
+}
+
+/* Convert a JSON value to a null-terminated authdata list or to NULL. */
+static int
+json_to_authdata(krb5_context context, k5_json_value v,
+ krb5_authdata ***authdata_out)
+{
+ k5_json_array array;
+ krb5_authdata **authdata = NULL;
+ size_t len, i;
+
+ *authdata_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ authdata = calloc(len + 1, sizeof(*authdata));
+ for (i = 0; i < len; i++) {
+ if (json_to_authdata_element(k5_json_array_get(array, i),
+ &authdata[i]))
+ goto invalid;
+ }
+ authdata[i] = NULL;
+ *authdata_out = authdata;
+ return 0;
+
+invalid:
+ krb5_free_authdata(context, authdata);
+ return -1;
+}
+
+/* Convert a JSON value to a krb5 credential structure, filling in creds. */
+static int
+json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds)
+{
+ k5_json_array array;
+ k5_json_number n;
+ k5_json_bool b;
+ k5_json_string s;
+ unsigned char *data;
+ size_t len;
+
+ memset(creds, 0, sizeof(*creds));
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 13)
+ return -1;
+
+ if (json_to_principal(context, k5_json_array_get(array, 0),
+ &creds->client))
+ goto invalid;
+
+ if (json_to_principal(context, k5_json_array_get(array, 1),
+ &creds->server))
+ goto invalid;
+
+ if (json_to_keyblock(k5_json_array_get(array, 2), &creds->keyblock))
+ goto invalid;
+
+ n = check_element(array, 3, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.authtime = k5_json_number_value(n);
+
+ n = check_element(array, 4, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.starttime = k5_json_number_value(n);
+
+ n = check_element(array, 5, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.endtime = k5_json_number_value(n);
+
+ n = check_element(array, 6, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.renew_till = k5_json_number_value(n);
+
+ b = check_element(array, 7, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ creds->is_skey = k5_json_bool_value(b);
+
+ n = check_element(array, 8, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->ticket_flags = k5_json_number_value(n);
+
+ if (json_to_addresses(context, k5_json_array_get(array, 9),
+ &creds->addresses))
+ goto invalid;
+
+ s = check_element(array, 10, K5_JSON_TID_STRING);
+ if (s == NULL)
+ goto invalid;
+ if (k5_json_string_unbase64(s, &data, &len))
+ goto invalid;
+ creds->ticket.data = (char *)data;
+ creds->ticket.length = len;
+
+ s = check_element(array, 11, K5_JSON_TID_STRING);
+ if (s == NULL)
+ goto invalid;
+ if (k5_json_string_unbase64(s, &data, &len))
+ goto invalid;
+ creds->second_ticket.data = (char *)data;
+ creds->second_ticket.length = len;
+
+ if (json_to_authdata(context, k5_json_array_get(array, 12),
+ &creds->authdata))
+ goto invalid;
+
+ creds->magic = KV5M_CREDS;
+ return 0;
+
+invalid:
+ krb5_free_cred_contents(context, creds);
+ memset(creds, 0, sizeof(*creds));
+ return -1;
+}
+
+/* Convert a JSON value to a ccache handle or to NULL. Set *new_out to true if
+ * the ccache handle is a newly created memory ccache, false otherwise. */
+static int
+json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out,
+ krb5_boolean *new_out)
+{
+ krb5_error_code ret;
+ krb5_ccache ccache = NULL;
+ krb5_principal princ;
+ krb5_creds creds;
+ k5_json_array array;
+ size_t i, len;
+
+ *ccache_out = NULL;
+ *new_out = FALSE;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) == K5_JSON_TID_STRING) {
+ /* We got a reference to an external ccache; just resolve it. */
+ return krb5_cc_resolve(context, k5_json_string_utf8(v), ccache_out) ?
+ -1 : 0;
+ }
+
+ /* We got the contents of a memory ccache. */
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ if (len < 1)
+ return -1;
+
+ /* Initialize a new memory ccache using the principal in the first array
+ * entry.*/
+ if (krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))
+ return -1;
+ if (json_to_principal(context, k5_json_array_get(array, 0), &princ))
+ goto invalid;
+ ret = krb5_cc_initialize(context, ccache, princ);
+ krb5_free_principal(context, princ);
+ if (ret)
+ goto invalid;
+
+ /* Add remaining array entries to the ccache as credentials. */
+ for (i = 1; i < len; i++) {
+ if (json_to_creds(context, k5_json_array_get(array, i), &creds))
+ goto invalid;
+ ret = krb5_cc_store_cred(context, ccache, &creds);
+ krb5_free_cred_contents(context, &creds);
+ if (ret)
+ goto invalid;
+ }
+
+ *ccache_out = ccache;
+ *new_out = TRUE;
+ return 0;
+
+invalid:
+ (void)krb5_cc_destroy(context, ccache);
+ return -1;
+}
+
+/* Convert a JSON array value to a krb5 GSS credential. */
+static int
+json_to_kgcred(krb5_context context, k5_json_array array,
+ krb5_gss_cred_id_t *cred_out)
+{
+ krb5_gss_cred_id_t cred;
+ k5_json_number n;
+ k5_json_bool b;
+ krb5_boolean is_new;
+ OM_uint32 tmp;
+
+ *cred_out = NULL;
+ if (k5_json_array_length(array) != 14)
+ return -1;
+
+ cred = calloc(1, sizeof(*cred));
+ if (cred == NULL)
+ return -1;
+ if (k5_mutex_init(&cred->lock)) {
+ free(cred);
+ return -1;
+ }
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->usage = k5_json_number_value(n);
+
+ if (json_to_kgname(context, k5_json_array_get(array, 1), &cred->name))
+ goto invalid;
+
+ if (json_to_principal(context, k5_json_array_get(array, 2),
+ &cred->impersonator))
+ goto invalid;
+
+ b = check_element(array, 3, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->default_identity = k5_json_bool_value(b);
+
+ b = check_element(array, 4, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->iakerb_mech = k5_json_bool_value(b);
+
+ if (json_to_keytab(context, k5_json_array_get(array, 5), &cred->keytab))
+ goto invalid;
+
+ if (json_to_rcache(context, k5_json_array_get(array, 6), &cred->rcache))
+ goto invalid;
+
+ if (json_to_ccache(context, k5_json_array_get(array, 7), &cred->ccache,
+ &is_new))
+ goto invalid;
+ cred->destroy_ccache = is_new;
+
+ if (json_to_keytab(context, k5_json_array_get(array, 8),
+ &cred->client_keytab))
+ goto invalid;
+
+ b = check_element(array, 9, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->have_tgt = k5_json_bool_value(b);
+
+ n = check_element(array, 10, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->expire = k5_json_number_value(n);
+
+ n = check_element(array, 11, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->refresh_time = k5_json_number_value(n);
+
+ if (json_to_etypes(k5_json_array_get(array, 12), &cred->req_enctypes))
+ goto invalid;
+
+ if (json_to_optional_string(k5_json_array_get(array, 13), &cred->password))
+ goto invalid;
+
+ *cred_out = cred;
+ return 0;
+
+invalid:
+ (void)krb5_gss_release_cred(&tmp, (gss_cred_id_t *)&cred);
+ return -1;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ krb5_context context;
+ krb5_error_code ret;
+ krb5_gss_cred_id_t cred;
+ k5_json_value v = NULL;
+ k5_json_array array;
+ k5_json_string str;
+ char *copy = NULL;
+
+ ret = krb5_gss_init_context(&context);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* Decode token. */
+ copy = k5memdup0(token->value, token->length, &ret);
+ if (copy == NULL) {
+ status = GSS_S_FAILURE;
+ *minor_status = ret;
+ goto cleanup;
+ }
+ if (k5_json_decode(copy, &v))
+ goto invalid;
+
+ /* Decode the CRED_EXPORT_MAGIC array wrapper. */
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ goto invalid;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ goto invalid;
+ str = check_element(array, 0, K5_JSON_TID_STRING);
+ if (str == NULL ||
+ strcmp(k5_json_string_utf8(str), CRED_EXPORT_MAGIC) != 0)
+ goto invalid;
+ if (json_to_kgcred(context, k5_json_array_get(array, 1), &cred))
+ goto invalid;
+
+ *cred_handle = (gss_cred_id_t)cred;
+
+cleanup:
+ free(copy);
+ k5_json_release(v);
+ krb5_free_context(context);
+ return status;
+
+invalid:
+ status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+}
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
new file mode 100644
index 000000000000..3f5492b99f6b
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -0,0 +1,332 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * errors:
+ * GSS_S_BAD_NAMETYPE if the type is bogus
+ * GSS_S_BAD_NAME if the type is good but the name is bogus
+ * GSS_S_FAILURE if memory allocation fails
+ */
+
+/*
+ * Import serialized authdata context
+ */
+static krb5_error_code
+import_name_composite(krb5_context context,
+ unsigned char *enc_data, size_t enc_length,
+ krb5_authdata_context *pad_context)
+{
+ krb5_authdata_context ad_context;
+ krb5_error_code code;
+ krb5_data data;
+
+ if (enc_length == 0)
+ return 0;
+
+ code = krb5_authdata_context_init(context, &ad_context);
+ if (code != 0)
+ return code;
+
+ data.data = (char *)enc_data;
+ data.length = enc_length;
+
+ code = krb5_authdata_import_attributes(context,
+ ad_context,
+ AD_USAGE_MASK,
+ &data);
+ if (code != 0) {
+ krb5_authdata_context_free(context, ad_context);
+ return code;
+ }
+
+ *pad_context = ad_context;
+
+ return 0;
+}
+
+/* Split a host-based name "service[@host]" into allocated strings
+ * placed in *service_out and *host_out (possibly NULL). */
+static krb5_error_code
+parse_hostbased(const char *str, size_t len,
+ char **service_out, char **host_out)
+{
+ const char *at;
+ size_t servicelen, hostlen;
+ char *service, *host = NULL;
+
+ *service_out = *host_out = NULL;
+
+ /* Find the bound of the service name and copy it. */
+ at = memchr(str, '@', len);
+ servicelen = (at == NULL) ? len : (size_t)(at - str);
+ service = xmalloc(servicelen + 1);
+ if (service == NULL)
+ return ENOMEM;
+ memcpy(service, str, servicelen);
+ service[servicelen] = '\0';
+
+ /* If present, copy the hostname. */
+ if (at != NULL) {
+ hostlen = len - servicelen - 1;
+ host = malloc(hostlen + 1);
+ if (host == NULL) {
+ free(service);
+ return ENOMEM;
+ }
+ memcpy(host, at + 1, hostlen);
+ host[hostlen] = '\0';
+ }
+
+ *service_out = service;
+ *host_out = host;
+ return 0;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name)
+ OM_uint32 *minor_status;
+ gss_buffer_t input_name_buffer;
+ gss_OID input_name_type;
+ gss_name_t *output_name;
+{
+ krb5_context context;
+ krb5_principal princ = NULL;
+ krb5_error_code code;
+ unsigned char *cp, *end;
+ char *tmp = NULL, *tmp2 = NULL, *service = NULL, *host = NULL, *stringrep;
+ ssize_t length;
+#ifndef NO_PASSWORD
+ struct passwd *pw;
+#endif
+ int is_composite = 0;
+ krb5_authdata_context ad_context = NULL;
+ OM_uint32 status = GSS_S_FAILURE;
+ krb5_gss_name_t name;
+
+ *output_name = NULL;
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code)
+ goto cleanup;
+
+ if ((input_name_type != GSS_C_NULL_OID) &&
+ (g_OID_equal(input_name_type, gss_nt_service_name) ||
+ g_OID_equal(input_name_type, gss_nt_service_name_v2))) {
+ /* Split the name into service and host (or NULL). */
+ code = parse_hostbased(input_name_buffer->value,
+ input_name_buffer->length, &service, &host);
+ if (code)
+ goto cleanup;
+
+ /*
+ * Compute the initiator target name. In some cases this is a waste of
+ * getaddrinfo/getnameinfo queries, but computing the name when we need
+ * it would require a lot of code changes.
+ */
+ code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
+ &princ);
+ if (code)
+ goto cleanup;
+ } else if ((input_name_type != GSS_C_NULL_OID) &&
+ (g_OID_equal(input_name_type, gss_nt_krb5_principal))) {
+ krb5_principal input;
+
+ if (input_name_buffer->length != sizeof(krb5_principal)) {
+ code = G_WRONG_SIZE;
+ status = GSS_S_BAD_NAME;
+ goto cleanup;
+ }
+
+ input = *((krb5_principal *) input_name_buffer->value);
+
+ code = krb5_copy_principal(context, input, &princ);
+ if (code)
+ goto cleanup;
+ } else if ((input_name_type != NULL) &&
+ g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
+ code = krb5_copy_principal(context, krb5_anonymous_principal(),
+ &princ);
+ if (code)
+ goto cleanup;
+ } else {
+#ifndef NO_PASSWORD
+ uid_t uid;
+ struct passwd pwx;
+ char pwbuf[BUFSIZ];
+#endif
+
+ stringrep = NULL;
+
+ tmp = k5memdup0(input_name_buffer->value, input_name_buffer->length,
+ &code);
+ if (tmp == NULL)
+ goto cleanup;
+ tmp2 = NULL;
+
+ /* Find the appropriate string rep to pass into parse_name. */
+ if ((input_name_type == GSS_C_NULL_OID) ||
+ g_OID_equal(input_name_type, gss_nt_krb5_name) ||
+ g_OID_equal(input_name_type, gss_nt_user_name)) {
+ stringrep = (char *) tmp;
+#ifndef NO_PASSWORD
+ } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
+ uid = *(uid_t *) input_name_buffer->value;
+ do_getpwuid:
+ if (k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) == 0)
+ stringrep = pw->pw_name;
+ else
+ code = G_NOUSER;
+ } else if (g_OID_equal(input_name_type, gss_nt_string_uid_name)) {
+ uid = atoi(tmp);
+ goto do_getpwuid;
+#endif
+ } else if (g_OID_equal(input_name_type, gss_nt_exported_name) ||
+ g_OID_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) {
+#define BOUNDS_CHECK(cp, end, n) \
+ do { if ((end) - (cp) < (n)) goto fail_name; } while (0)
+ cp = (unsigned char *)tmp;
+ end = cp + input_name_buffer->length;
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x04)
+ goto fail_name;
+ switch (*cp++) {
+ case 0x01:
+ break;
+ case 0x02:
+ is_composite++;
+ break;
+ default:
+ goto fail_name;
+ }
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x00)
+ goto fail_name;
+ length = *cp++;
+ if (length != (ssize_t)gss_mech_krb5->length+2)
+ goto fail_name;
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x06)
+ goto fail_name;
+ length = *cp++;
+ if (length != (ssize_t)gss_mech_krb5->length)
+ goto fail_name;
+
+ BOUNDS_CHECK(cp, end, length);
+ if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
+ goto fail_name;
+ cp += length;
+
+ BOUNDS_CHECK(cp, end, 4);
+ length = *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+
+ BOUNDS_CHECK(cp, end, length);
+ tmp2 = k5alloc(length + 1, &code);
+ if (tmp2 == NULL)
+ goto cleanup;
+ strncpy(tmp2, (char *)cp, length);
+ tmp2[length] = 0;
+ stringrep = tmp2;
+ cp += length;
+
+ if (is_composite) {
+ BOUNDS_CHECK(cp, end, 4);
+ length = *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+
+ BOUNDS_CHECK(cp, end, length);
+ code = import_name_composite(context,
+ cp, length,
+ &ad_context);
+ if (code != 0)
+ goto fail_name;
+ cp += length;
+ }
+ assert(cp == end);
+ } else {
+ status = GSS_S_BAD_NAMETYPE;
+ goto cleanup;
+ }
+
+ /* At this point, stringrep is set, or if not, code is. */
+ if (stringrep) {
+ code = krb5_parse_name(context, (char *)stringrep, &princ);
+ if (code)
+ goto cleanup;
+ } else {
+ fail_name:
+ status = GSS_S_BAD_NAME;
+ goto cleanup;
+ }
+ }
+
+ /* Create a name and save it in the validation database. */
+ code = kg_init_name(context, princ, service, host, ad_context,
+ KG_INIT_NAME_NO_COPY, &name);
+ if (code)
+ goto cleanup;
+ princ = NULL;
+ ad_context = NULL;
+ service = host = NULL;
+ *output_name = (gss_name_t)name;
+ status = GSS_S_COMPLETE;
+
+cleanup:
+ *minor_status = (OM_uint32)code;
+ if (*minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_principal(context, princ);
+ krb5_authdata_context_free(context, ad_context);
+ krb5_free_context(context);
+ free(tmp);
+ free(tmp2);
+ free(service);
+ free(host);
+ return status;
+}
diff --git a/src/lib/gssapi/krb5/import_sec_context.c b/src/lib/gssapi/krb5/import_sec_context.c
new file mode 100644
index 000000000000..4190adf35cab
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_sec_context.c
@@ -0,0 +1,118 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/import_sec_context.c - Internalize the security context */
+/*
+ * Copyright 1995,2004,2007,2008 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.
+ */
+
+#include "gssapiP_krb5.h"
+/* for serialization initialization functions */
+#include "k5-int.h"
+
+/*
+ * Fix up the OID of the mechanism so that uses the static version of
+ * the OID if possible.
+ */
+gss_OID krb5_gss_convert_static_mech_oid(oid)
+ gss_OID oid;
+{
+ const gss_OID_desc *p;
+ OM_uint32 minor_status;
+
+ for (p = krb5_gss_oid_array; p->length; p++) {
+ if ((oid->length == p->length) &&
+ (memcmp(oid->elements, p->elements, p->length) == 0)) {
+ generic_gss_release_oid(&minor_status, &oid);
+ return (gss_OID) p;
+ }
+ }
+ return oid;
+}
+
+krb5_error_code
+krb5_gss_ser_init (krb5_context context)
+{
+ krb5_error_code code;
+ static krb5_error_code (KRB5_CALLCONV *const fns[])(krb5_context) = {
+ krb5_ser_context_init, krb5_ser_auth_context_init,
+ krb5_ser_ccache_init, krb5_ser_rcache_init, krb5_ser_keytab_init,
+ };
+ unsigned int i;
+
+ for (i = 0; i < sizeof(fns)/sizeof(fns[0]); i++)
+ if ((code = (fns[i])(context)) != 0)
+ return code;
+ return 0;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_sec_context(minor_status, interprocess_token, context_handle)
+ OM_uint32 *minor_status;
+ gss_buffer_t interprocess_token;
+ gss_ctx_id_t *context_handle;
+{
+ krb5_context context;
+ krb5_error_code kret = 0;
+ size_t blen;
+ krb5_gss_ctx_id_t ctx;
+ krb5_octet *ibp;
+
+ /* This is a bit screwy. We create a krb5 context because we need
+ one when calling the serialization code. However, one of the
+ objects we're unpacking is a krb5 context, so when we finish,
+ we can throw this one away. */
+ kret = krb5_gss_init_context(&context);
+ if (kret) {
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ kret = krb5_gss_ser_init(context);
+ if (kret) {
+ *minor_status = kret;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+ /* Assume a tragic failure */
+ ctx = (krb5_gss_ctx_id_t) NULL;
+ *minor_status = 0;
+
+ /* Internalize the context */
+ ibp = (krb5_octet *) interprocess_token->value;
+ blen = (size_t) interprocess_token->length;
+ kret = kg_ctx_internalize(context, (krb5_pointer *) &ctx, &ibp, &blen);
+ if (kret) {
+ *minor_status = (OM_uint32) kret;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ krb5_free_context(context);
+
+ ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+
+ *context_handle = (gss_ctx_id_t) ctx;
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/indicate_mechs.c b/src/lib/gssapi/krb5/indicate_mechs.c
new file mode 100644
index 000000000000..45538cb779aa
--- /dev/null
+++ b/src/lib/gssapi/krb5/indicate_mechs.c
@@ -0,0 +1,37 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_indicate_mechs(minor_status, mech_set)
+ OM_uint32 *minor_status;
+ gss_OID_set *mech_set;
+{
+ return generic_gss_copy_oid_set(minor_status, kg_all_mechs, mech_set);
+}
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
new file mode 100644
index 000000000000..70f7955ae1ae
--- /dev/null
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -0,0 +1,1104 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2002, 2003, 2007, 2008 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 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+ * $Id$
+ */
+
+/* XXX This is for debugging only!!! Should become a real bitfield
+ at some point */
+int krb5_gss_dbg_client_expcreds = 0;
+
+/*
+ * Common code which fetches the correct krb5 credentials from the
+ * ccache.
+ */
+static krb5_error_code get_credentials(context, cred, server, now,
+ endtime, out_creds)
+ krb5_context context;
+ krb5_gss_cred_id_t cred;
+ krb5_gss_name_t server;
+ krb5_timestamp now;
+ krb5_timestamp endtime;
+ krb5_creds **out_creds;
+{
+ krb5_error_code code;
+ krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL;
+ krb5_flags flags = 0;
+
+ *out_creds = NULL;
+
+ k5_mutex_assert_locked(&cred->lock);
+ memset(&in_creds, 0, sizeof(krb5_creds));
+ memset(&evidence_creds, 0, sizeof(krb5_creds));
+ in_creds.client = in_creds.server = NULL;
+
+ assert(cred->name != NULL);
+
+ in_creds.client = cred->name->princ;
+ in_creds.server = server->princ;
+ in_creds.times.endtime = endtime;
+ in_creds.authdata = NULL;
+ in_creds.keyblock.enctype = 0;
+
+ /*
+ * cred->name is immutable, so there is no need to acquire
+ * cred->name->lock.
+ */
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(context,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /*
+ * For IAKERB or constrained delegation, only check the cache in this step.
+ * For IAKERB we will ask the server to make any necessary TGS requests;
+ * for constrained delegation we will adjust in_creds and make an S4U2Proxy
+ * request below if the cache lookup fails.
+ */
+ if (cred->impersonator != NULL || cred->iakerb_mech)
+ flags |= KRB5_GC_CACHED;
+
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, &result_creds);
+
+ /*
+ * Try constrained delegation if we have proxy credentials, unless
+ * we are trying to get a ticket to ourselves (in which case we could
+ * just use the evidence ticket directly from cache).
+ */
+ if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
+ !cred->iakerb_mech &&
+ !krb5_principal_compare(context, cred->impersonator, server->princ)) {
+
+ memset(&mcreds, 0, sizeof(mcreds));
+ mcreds.magic = KV5M_CREDS;
+ mcreds.server = cred->impersonator;
+ mcreds.client = cred->name->princ;
+ code = krb5_cc_retrieve_cred(context, cred->ccache,
+ KRB5_TC_MATCH_AUTHDATA, &mcreds,
+ &evidence_creds);
+ if (code)
+ goto cleanup;
+
+ assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+ in_creds.client = cred->impersonator;
+ in_creds.second_ticket = evidence_creds.ticket;
+ flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, &result_creds);
+ }
+
+ if (code)
+ goto cleanup;
+
+ if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
+ if (!krb5_principal_compare(context, cred->name->princ,
+ result_creds->client)) {
+ /* server did not support constrained delegation */
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Enforce a stricter limit (without timeskew forgiveness at the
+ * boundaries) because accept_sec_context code is also similarly
+ * non-forgiving.
+ */
+ if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) {
+ code = KRB5KRB_AP_ERR_TKT_EXPIRED;
+ goto cleanup;
+ }
+
+ *out_creds = result_creds;
+ result_creds = NULL;
+
+cleanup:
+ krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_cred_contents(context, &evidence_creds);
+ krb5_free_creds(context, result_creds);
+
+ return code;
+}
+struct gss_checksum_data {
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_cred_id_t cred;
+ krb5_checksum md5;
+ krb5_data checksum_data;
+ krb5_gss_ctx_ext_t exts;
+};
+
+#ifdef CFX_EXERCISE
+#include "../../krb5/krb/auth_con.h"
+#endif
+static krb5_error_code KRB5_CALLCONV
+make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
+ void *cksum_data, krb5_data **out)
+{
+ krb5_error_code code;
+ krb5_int32 con_flags;
+ unsigned char *ptr;
+ struct gss_checksum_data *data = cksum_data;
+ krb5_data credmsg;
+ unsigned int junk;
+ krb5_data *finished = NULL;
+ krb5_key send_subkey;
+
+ data->checksum_data.data = 0;
+ credmsg.data = 0;
+ /* build the checksum field */
+
+ if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
+ /* first get KRB_CRED message, so we know its length */
+
+ /* clear the time check flag that was set in krb5_auth_con_init() */
+ krb5_auth_con_getflags(context, auth_context, &con_flags);
+ krb5_auth_con_setflags(context, auth_context,
+ con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
+
+ assert(data->cred->name != NULL);
+
+ /*
+ * RFC 4121 4.1.1 specifies forwarded credentials must be encrypted in
+ * the session key, but krb5_fwd_tgt_creds will use the send subkey if
+ * it's set in the auth context. Suppress the send subkey
+ * temporarily.
+ */
+ krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
+ krb5_auth_con_setsendsubkey_k(context, auth_context, NULL);
+
+ code = krb5_fwd_tgt_creds(context, auth_context, 0,
+ data->cred->name->princ, data->ctx->there->princ,
+ data->cred->ccache, 1,
+ &credmsg);
+
+ /* Turn KRB5_AUTH_CONTEXT_DO_TIME back on and reset the send subkey. */
+ krb5_auth_con_setflags(context, auth_context, con_flags);
+ krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey);
+ krb5_k_free_key(context, send_subkey);
+
+ if (code) {
+ /* don't fail here; just don't accept/do the delegation
+ request */
+ data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG |
+ GSS_C_DELEG_POLICY_FLAG);
+
+ data->checksum_data.length = 24;
+ } else {
+ if (credmsg.length+28 > KRB5_INT16_MAX) {
+ code = KRB5KRB_ERR_FIELD_TOOLONG;
+ goto cleanup;
+ }
+
+ data->checksum_data.length = 28+credmsg.length;
+ }
+ } else {
+ data->checksum_data.length = 24;
+ }
+#ifdef CFX_EXERCISE
+ if (data->ctx->auth_context->keyblock != NULL
+ && data->ctx->auth_context->keyblock->enctype == 18) {
+ srand(time(0) ^ getpid());
+ /* Our ftp client code stupidly assumes a base64-encoded
+ version of the token will fit in 10K, so don't make this
+ too big. */
+ junk = rand() & 0xff;
+ } else
+ junk = 0;
+#else
+ junk = 0;
+#endif
+
+ assert(data->exts != NULL);
+
+ if (data->exts->iakerb.conv) {
+ krb5_key key;
+
+ code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
+ &finished);
+ if (code != 0) {
+ krb5_k_free_key(context, key);
+ goto cleanup;
+ }
+
+ krb5_k_free_key(context, key);
+ data->checksum_data.length += 8 + finished->length;
+ }
+
+ data->checksum_data.length += junk;
+
+ /* now allocate a buffer to hold the checksum data and
+ (maybe) KRB_CRED msg */
+
+ if ((data->checksum_data.data =
+ (char *) xmalloc(data->checksum_data.length)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ ptr = (unsigned char *)data->checksum_data.data;
+
+ TWRITE_INT(ptr, data->md5.length, 0);
+ TWRITE_STR(ptr, data->md5.contents, data->md5.length);
+ TWRITE_INT(ptr, data->ctx->gss_flags, 0);
+
+ /* done with this, free it */
+ xfree(data->md5.contents);
+
+ if (credmsg.data) {
+ TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
+ TWRITE_INT16(ptr, credmsg.length, 0);
+ TWRITE_STR(ptr, credmsg.data, credmsg.length);
+ }
+ if (data->exts->iakerb.conv) {
+ TWRITE_INT(ptr, KRB5_GSS_EXTS_IAKERB_FINISHED, 1);
+ TWRITE_INT(ptr, finished->length, 1);
+ TWRITE_STR(ptr, finished->data, finished->length);
+ }
+ if (junk)
+ memset(ptr, 'i', junk);
+ *out = &data->checksum_data;
+ code = 0;
+cleanup:
+ krb5_free_data_contents(context, &credmsg);
+ krb5_free_data(context, finished);
+ return code;
+}
+
+static krb5_error_code
+make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
+ chan_bindings, mech_type, token, exts)
+ krb5_context context;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_cred_id_t cred;
+ krb5_creds *k_cred;
+ krb5_authdata_context ad_context;
+ gss_channel_bindings_t chan_bindings;
+ gss_OID mech_type;
+ gss_buffer_t token;
+ krb5_gss_ctx_ext_t exts;
+{
+ krb5_flags mk_req_flags = 0;
+ krb5_error_code code;
+ struct gss_checksum_data cksum_struct;
+ krb5_checksum md5;
+ krb5_data ap_req;
+ unsigned char *ptr;
+ unsigned char *t;
+ unsigned int tlen;
+
+ k5_mutex_assert_locked(&cred->lock);
+ ap_req.data = 0;
+
+ /* compute the hash of the channel bindings */
+
+ if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5)))
+ return(code);
+
+ krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
+ CKSUMTYPE_KG_CB);
+ cksum_struct.md5 = md5;
+ cksum_struct.ctx = ctx;
+ cksum_struct.cred = cred;
+ cksum_struct.checksum_data.data = NULL;
+ cksum_struct.exts = exts;
+ krb5_auth_con_set_checksum_func(context, ctx->auth_context,
+ make_gss_checksum, &cksum_struct);
+
+ /* call mk_req. subkey and ap_req need to be used or destroyed */
+
+ mk_req_flags = AP_OPTS_USE_SUBKEY;
+
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
+ mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION;
+
+ krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context);
+ code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
+ NULL, k_cred, &ap_req);
+ krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL);
+ krb5_free_data_contents(context, &cksum_struct.checksum_data);
+ if (code)
+ goto cleanup;
+
+ /* store the interesting stuff from creds and authent */
+ ctx->krb_times = k_cred->times;
+ ctx->krb_flags = k_cred->ticket_flags;
+
+ /* build up the token */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /*
+ * For DCE RPC, do not encapsulate the AP-REQ in the
+ * typical GSS wrapping.
+ */
+ code = data_to_gss(&ap_req, token);
+ if (code)
+ goto cleanup;
+ } else {
+ /* allocate space for the token */
+ tlen = g_token_size((gss_OID) mech_type, ap_req.length);
+
+ if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the buffer */
+ ptr = t;
+
+ g_make_token_header(mech_type, ap_req.length,
+ &ptr, KG_TOK_CTX_AP_REQ);
+
+ TWRITE_STR(ptr, ap_req.data, ap_req.length);
+
+ /* pass it back */
+
+ token->length = tlen;
+ token->value = (void *) t;
+ }
+
+ code = 0;
+
+cleanup:
+ if (ap_req.data)
+ krb5_free_data_contents(context, &ap_req);
+
+ return (code);
+}
+
+/*
+ * new_connection
+ *
+ * Do the grunt work of setting up a new context.
+ */
+static OM_uint32
+kg_new_connection(
+ OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context,
+ krb5_gss_ctx_ext_t exts)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_creds *k_cred = NULL;
+ krb5_gss_ctx_id_rec *ctx, *ctx_free;
+ krb5_timestamp now;
+ gss_buffer_desc token;
+ krb5_keyblock *keyblock;
+
+ k5_mutex_assert_locked(&cred->lock);
+ major_status = GSS_S_FAILURE;
+ token.length = 0;
+ token.value = NULL;
+
+ /* make sure the cred is usable for init */
+
+ if ((cred->usage != GSS_C_INITIATE) &&
+ (cred->usage != GSS_C_BOTH)) {
+ *minor_status = 0;
+ return(GSS_S_NO_CRED);
+ }
+
+ /* complain if the input token is non-null */
+
+ if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ /* create the ctx */
+
+ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+ == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ /* fill in the ctx */
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
+ ctx_free = ctx;
+ if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
+ goto cleanup;
+ krb5_auth_con_setflags(context, ctx->auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+ /* limit the encryption types negotiated (if requested) */
+ if (cred->req_enctypes) {
+ if ((code = krb5_set_default_tgs_enctypes(context,
+ cred->req_enctypes))) {
+ goto cleanup;
+ }
+ }
+
+ ctx->initiate = 1;
+ ctx->seed_init = 0;
+ ctx->seqstate = 0;
+
+ ctx->gss_flags = req_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG |
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
+ GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
+ GSS_C_EXTENDED_ERROR_FLAG);
+ ctx->gss_flags |= GSS_C_TRANS_FLAG;
+ if (!cred->suppress_ci_flags)
+ ctx->gss_flags |= (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
+ if (req_flags & GSS_C_DCE_STYLE)
+ ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
+
+ if ((code = krb5_timeofday(context, &now)))
+ goto cleanup;
+
+ if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
+ ctx->krb_times.endtime = 0;
+ } else {
+ ctx->krb_times.endtime = now + time_req;
+ }
+
+ if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
+ goto cleanup;
+
+ if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name,
+ &ctx->there)))
+ goto cleanup;
+
+ code = get_credentials(context, cred, ctx->there, now,
+ ctx->krb_times.endtime, &k_cred);
+ if (code)
+ goto cleanup;
+
+ ctx->krb_times = k_cred->times;
+
+ /*
+ * GSS_C_DELEG_POLICY_FLAG means to delegate only if the
+ * ok-as-delegate ticket flag is set.
+ */
+ if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
+ && (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE))
+ ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
+
+ if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
+ != GSS_S_COMPLETE) {
+ code = *minor_status;
+ goto cleanup;
+ }
+ /*
+ * Now try to make it static if at all possible....
+ */
+ ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+
+ {
+ /* gsskrb5 v1 */
+ krb5_int32 seq_temp;
+ if ((code = make_ap_req_v1(context, ctx,
+ cred, k_cred, ctx->here->ad_context,
+ input_chan_bindings,
+ mech_type, &token, exts))) {
+ if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
+ (code == KG_EMPTY_CCACHE))
+ major_status = GSS_S_NO_CRED;
+ if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
+ major_status = GSS_S_CREDENTIALS_EXPIRED;
+ goto cleanup;
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
+ ctx->seq_send = seq_temp;
+ code = krb5_auth_con_getsendsubkey(context, ctx->auth_context,
+ &keyblock);
+ if (code != 0)
+ goto cleanup;
+ code = krb5_k_create_key(context, keyblock, &ctx->subkey);
+ krb5_free_keyblock(context, keyblock);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ ctx->enc = NULL;
+ ctx->seq = NULL;
+ ctx->have_acceptor_subkey = 0;
+ code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
+ if (code != 0)
+ goto cleanup;
+
+ if (!(ctx->gss_flags & GSS_C_MUTUAL_FLAG)) {
+ /* There will be no AP-REP, so set up sequence state now. */
+ ctx->seq_recv = ctx->seq_send;
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* compute time_rec */
+ if (time_rec) {
+ if ((code = krb5_timeofday(context, &now)))
+ goto cleanup;
+ *time_rec = ctx->krb_times.endtime - now;
+ }
+
+ /* set the other returns */
+ *output_token = token;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
+
+ /* return successfully */
+
+ *context_handle = (gss_ctx_id_t) ctx;
+ ctx_free = NULL;
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+ ctx->established = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ } else {
+ ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+ ctx->established = 1;
+ major_status = GSS_S_COMPLETE;
+ }
+
+cleanup:
+ krb5_free_creds(context, k_cred);
+ if (ctx_free) {
+ if (ctx_free->auth_context)
+ krb5_auth_con_free(context, ctx_free->auth_context);
+ if (ctx_free->here)
+ kg_release_name(context, &ctx_free->here);
+ if (ctx_free->there)
+ kg_release_name(context, &ctx_free->there);
+ if (ctx_free->subkey)
+ krb5_k_free_key(context, ctx_free->subkey);
+ xfree(ctx_free);
+ }
+
+ *minor_status = code;
+ return (major_status);
+}
+
+/*
+ * mutual_auth
+ *
+ * Handle the reply from the acceptor, if we're doing mutual auth.
+ */
+static OM_uint32
+mutual_auth(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ unsigned char *ptr;
+ char *sptr;
+ krb5_data ap_rep;
+ krb5_ap_rep_enc_part *ap_rep_data;
+ krb5_timestamp now;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error *krb_error;
+ krb5_error_code code;
+ krb5int_access kaccess;
+
+ major_status = GSS_S_FAILURE;
+
+ code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (code)
+ goto fail;
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+
+ /* make sure the context is non-established, and that certain
+ arguments are unchanged */
+
+ if ((ctx->established) ||
+ ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
+ code = KG_CONTEXT_ESTABLISHED;
+ goto fail;
+ }
+
+ if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) {
+ (void)krb5_gss_delete_sec_context(minor_status,
+ context_handle, NULL);
+ code = 0;
+ major_status = GSS_S_BAD_NAME;
+ goto fail;
+ }
+
+ /* verify the token and leave the AP_REP message in ap_rep */
+
+ if (input_token == GSS_C_NO_BUFFER) {
+ (void)krb5_gss_delete_sec_context(minor_status,
+ context_handle, NULL);
+ code = 0;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ ptr = (unsigned char *) input_token->value;
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /* Raw AP-REP */
+ ap_rep.length = input_token->length;
+ ap_rep.data = (char *)input_token->value;
+ } else if (g_verify_token_header(ctx->mech_used,
+ &(ap_rep.length),
+ &ptr, KG_TOK_CTX_AP_REP,
+ input_token->length, 1)) {
+ if (g_verify_token_header((gss_OID) ctx->mech_used,
+ &(ap_rep.length),
+ &ptr, KG_TOK_CTX_ERROR,
+ input_token->length, 1) == 0) {
+
+ /* Handle a KRB_ERROR message from the server */
+
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+
+ code = krb5_rd_error(context, &ap_rep, &krb_error);
+ if (code)
+ goto fail;
+ if (krb_error->error)
+ code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5;
+ else
+ code = 0;
+ krb5_free_error(context, krb_error);
+ goto fail;
+ } else {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+ }
+
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+
+ /* decode the ap_rep */
+ if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data))) {
+ /*
+ * XXX A hack for backwards compatiblity.
+ * To be removed in 1999 -- proven
+ */
+ krb5_auth_con_setuseruserkey(context, ctx->auth_context,
+ &ctx->subkey->keyblock);
+ if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data)))
+ goto fail;
+ }
+
+ /* store away the sequence number */
+ ctx->seq_recv = ap_rep_data->seq_number;
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+
+ if (ap_rep_data->subkey != NULL &&
+ (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
+ ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) {
+ /* Keep acceptor's subkey. */
+ ctx->have_acceptor_subkey = 1;
+ code = krb5_k_create_key(context, ap_rep_data->subkey,
+ &ctx->acceptor_subkey);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+ code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
+ &ctx->acceptor_subkey_cksumtype);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+ }
+ /* free the ap_rep_data */
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ krb5_data outbuf;
+
+ code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf);
+ if (code)
+ goto fail;
+
+ code = data_to_gss(&outbuf, output_token);
+ if (code)
+ goto fail;
+ }
+
+ /* set established */
+ ctx->established = 1;
+
+ /* set returns */
+
+ if (time_rec) {
+ if ((code = krb5_timeofday(context, &now)))
+ goto fail;
+ *time_rec = ctx->krb_times.endtime - now;
+ }
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
+
+ /* success */
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+fail:
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+
+ *minor_status = code;
+ return (major_status);
+}
+
+OM_uint32
+krb5_gss_init_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_context context;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code kerr;
+ OM_uint32 major_status;
+ OM_uint32 tmp_min_stat;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ kerr = krb5_gss_init_context(&context);
+ if (kerr) {
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+ if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+ } else {
+ context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
+ }
+
+ /* set up return values so they can be "freed" successfully */
+
+ major_status = GSS_S_FAILURE; /* Default major code */
+ output_token->length = 0;
+ output_token->value = NULL;
+ if (actual_mech_type)
+ *actual_mech_type = NULL;
+
+ /* verify the mech_type */
+
+ if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) {
+ mech_type = (gss_OID) gss_mech_krb5;
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
+ mech_type = (gss_OID) gss_mech_krb5_old;
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
+ mech_type = (gss_OID) gss_mech_krb5_wrong;
+ } else if (g_OID_equal(mech_type, gss_mech_iakerb)) {
+ mech_type = (gss_OID) gss_mech_iakerb;
+ } else {
+ *minor_status = 0;
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* is this a new connection or not? */
+
+ /*SUPPRESS 29*/
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ /* verify the credential, or use the default */
+ /*SUPPRESS 29*/
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = kg_get_defcred(minor_status, &defcred);
+ if (major_status && GSS_ERROR(major_status)) {
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(major_status);
+ }
+ claimant_cred_handle = defcred;
+ }
+
+ major_status = kg_cred_resolve(minor_status, context,
+ claimant_cred_handle, target_name);
+ if (GSS_ERROR(major_status)) {
+ save_error_info(*minor_status, context);
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(major_status);
+ }
+ cred = (krb5_gss_cred_id_t)claimant_cred_handle;
+
+ major_status = kg_new_connection(minor_status, cred, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context, exts);
+ k5_mutex_unlock(&cred->lock);
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ save_error_info (*minor_status, context);
+ krb5_free_context(context);
+ } else
+ ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
+ } else {
+ /* mutual_auth doesn't care about the credentials */
+ major_status = mutual_auth(minor_status, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context);
+ /* If context_handle is now NO_CONTEXT, mutual_auth called
+ delete_sec_context, which would've zapped the krb5 context
+ too. */
+ }
+
+ return(major_status);
+}
+
+#ifndef _WIN32
+k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static int kdc_flag = 0;
+#endif
+
+krb5_error_code
+krb5_gss_init_context (krb5_context *ctxp)
+{
+ krb5_error_code err;
+#ifndef _WIN32
+ int is_kdc;
+#endif
+
+ err = gss_krb5int_initialize_library();
+ if (err)
+ return err;
+#ifndef _WIN32
+ k5_mutex_lock(&kg_kdc_flag_mutex);
+ is_kdc = kdc_flag;
+ k5_mutex_unlock(&kg_kdc_flag_mutex);
+
+ if (is_kdc)
+ return krb5int_init_context_kdc(ctxp);
+#endif
+
+ return krb5_init_context(ctxp);
+}
+
+#ifndef _WIN32
+OM_uint32
+krb5int_gss_use_kdc_context(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ OM_uint32 err;
+
+ *minor_status = 0;
+
+ err = gss_krb5int_initialize_library();
+ if (err)
+ return err;
+ k5_mutex_lock(&kg_kdc_flag_mutex);
+ kdc_flag = 1;
+ k5_mutex_unlock(&kg_kdc_flag_mutex);
+ return GSS_S_COMPLETE;
+}
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
+ context_handle, target_name, mech_type,
+ req_flags, time_req, input_chan_bindings,
+ input_token, actual_mech_type, output_token,
+ ret_flags, time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t claimant_cred_handle;
+ gss_ctx_id_t *context_handle;
+ gss_name_t target_name;
+ gss_OID mech_type;
+ OM_uint32 req_flags;
+ OM_uint32 time_req;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_buffer_t input_token;
+ gss_OID *actual_mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_init_sec_context_ext(minor_status,
+ claimant_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+}
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
new file mode 100644
index 000000000000..9024b3c7ea9c
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -0,0 +1,312 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
+ acceptor_name, lifetime_rec, mech_type, ret_flags,
+ locally_initiated, opened)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_name_t *initiator_name;
+ gss_name_t *acceptor_name;
+ OM_uint32 *lifetime_rec;
+ gss_OID *mech_type;
+ OM_uint32 *ret_flags;
+ int *locally_initiated;
+ int *opened;
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_name_t initiator, acceptor;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+
+ if (initiator_name)
+ *initiator_name = (gss_name_t) NULL;
+ if (acceptor_name)
+ *acceptor_name = (gss_name_t) NULL;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ context = ctx->k5_context;
+
+ /* RFC 2743 states that a partially completed context must return
+ * flags, locally_initiated, and open, and *may* return mech_type. */
+ if (ctx->established) {
+ initiator = NULL;
+ acceptor = NULL;
+
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+
+ /* Add the maximum allowable clock skew as a grace period for context
+ * expiration, just as we do for the ticket during authentication. */
+ lifetime = ctx->krb_times.endtime - now;
+ if (!ctx->initiate)
+ lifetime += context->clockskew;
+ if (lifetime < 0)
+ lifetime = 0;
+
+ if (initiator_name) {
+ code = kg_duplicate_name(context,
+ ctx->initiate ? ctx->here : ctx->there,
+ &initiator);
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+ }
+
+ if (acceptor_name) {
+ code = kg_duplicate_name(context,
+ ctx->initiate ? ctx->there : ctx->here,
+ &acceptor);
+ if (code) {
+ if (initiator)
+ kg_release_name(context, &initiator);
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+ }
+
+ if (initiator_name)
+ *initiator_name = (gss_name_t) initiator;
+
+ if (acceptor_name)
+ *acceptor_name = (gss_name_t) acceptor;
+
+ if (lifetime_rec)
+ *lifetime_rec = lifetime;
+ } else {
+ lifetime = 0;
+ if (initiator_name)
+ *initiator_name = GSS_C_NO_NAME;
+
+ if (acceptor_name)
+ *acceptor_name = GSS_C_NO_NAME;
+
+ if (lifetime_rec)
+ *lifetime_rec = 0;
+ }
+
+ if (mech_type)
+ *mech_type = (gss_OID) ctx->mech_used;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (locally_initiated)
+ *locally_initiated = ctx->initiate;
+
+ if (opened)
+ *opened = ctx->established;
+
+ *minor_status = 0;
+ if (ctx->established)
+ return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+ else
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_krb5int_inq_session_key(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_key key;
+ gss_buffer_desc keyvalue, keyinfo;
+ OM_uint32 major_status, minor;
+ unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
+ gss_OID_desc oid;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
+
+ keyvalue.value = key->keyblock.contents;
+ keyvalue.length = key->keyblock.length;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status, &keyvalue, data_set);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ oid.elements = oid_buf;
+ oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
+ GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
+ key->keyblock.enctype,
+ &oid);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ keyinfo.value = oid.elements;
+ keyinfo.length = oid.length;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status, &keyinfo, data_set);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ return GSS_S_COMPLETE;
+
+cleanup:
+ if (*data_set != GSS_C_NO_BUFFER_SET) {
+ if ((*data_set)->count != 0)
+ memset((*data_set)->elements[0].value, 0, (*data_set)->elements[0].length);
+ gss_release_buffer_set(&minor, data_set);
+ }
+
+ return major_status;
+}
+
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major_status;
+ krb5_gss_ctx_id_rec *ctx;
+ int ad_type = 0;
+ size_t i;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ major_status = generic_gss_oid_decompose(minor_status,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ desired_object,
+ &ad_type);
+ if (major_status != GSS_S_COMPLETE || ad_type == 0) {
+ *minor_status = ENOENT;
+ return GSS_S_FAILURE;
+ }
+
+ if (ctx->authdata != NULL) {
+ for (i = 0; ctx->authdata[i] != NULL; i++) {
+ if (ctx->authdata[i]->ad_type == ad_type) {
+ gss_buffer_desc ad_data;
+
+ ad_data.length = ctx->authdata[i]->length;
+ ad_data.value = ctx->authdata[i]->contents;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status,
+ &ad_data, data_set);
+ if (GSS_ERROR(major_status))
+ break;
+ }
+ }
+ }
+
+ if (GSS_ERROR(major_status)) {
+ OM_uint32 tmp;
+
+ generic_gss_release_buffer_set(&tmp, data_set);
+ }
+
+ return major_status;
+}
+
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_oid,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_buffer_desc rep;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ rep.value = &ctx->krb_times.authtime;
+ rep.length = sizeof(ctx->krb_times.authtime);
+
+ return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+}
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
new file mode 100644
index 000000000000..4e35a056316f
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -0,0 +1,247 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2007 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 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
+ cred_usage, mechanisms)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+ gss_name_t *name;
+ OM_uint32 *lifetime_ret;
+ gss_cred_usage_t *cred_usage;
+ gss_OID_set *mechanisms;
+{
+ krb5_context context;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_error_code code;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+ krb5_gss_name_t ret_name;
+ krb5_principal princ;
+ gss_OID_set mechs;
+ OM_uint32 major, tmpmin, ret;
+
+ ret = GSS_S_FAILURE;
+ ret_name = NULL;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (name) *name = NULL;
+ if (mechanisms) *mechanisms = NULL;
+
+ /* check for default credential */
+ /*SUPPRESS 29*/
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ major = kg_get_defcred(minor_status, &defcred);
+ if (GSS_ERROR(major)) {
+ krb5_free_context(context);
+ return(major);
+ }
+ cred_handle = defcred;
+ }
+
+ major = kg_cred_resolve(minor_status, context, cred_handle, GSS_C_NO_NAME);
+ if (GSS_ERROR(major)) {
+ krb5_gss_release_cred(minor_status, &defcred);
+ krb5_free_context(context);
+ return(major);
+ }
+ cred = (krb5_gss_cred_id_t)cred_handle;
+
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ if (cred->expire > 0) {
+ if ((lifetime = cred->expire - now) < 0)
+ lifetime = 0;
+ }
+ else
+ lifetime = GSS_C_INDEFINITE;
+
+ if (name) {
+ if (cred->name) {
+ code = kg_duplicate_name(context, cred->name, &ret_name);
+ } else if ((cred->usage == GSS_C_ACCEPT || cred->usage == GSS_C_BOTH)
+ && cred->keytab != NULL) {
+ /* This is a default acceptor cred; use a name from the keytab if
+ * we can. */
+ code = k5_kt_get_principal(context, cred->keytab, &princ);
+ if (code == 0) {
+ code = kg_init_name(context, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ret_name);
+ if (code)
+ krb5_free_principal(context, princ);
+ } else if (code == KRB5_KT_NOTFOUND)
+ code = 0;
+ }
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (mechanisms) {
+ if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+ &mechs)) ||
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &mechs)) ||
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &mechs))) {
+ if (ret_name)
+ kg_release_name(context, &ret_name);
+ /* *minor_status set above */
+ goto fail;
+ }
+ }
+
+ if (name) {
+ if (ret_name != NULL)
+ *name = (gss_name_t) ret_name;
+ else
+ *name = GSS_C_NO_NAME;
+ }
+
+ if (lifetime_ret)
+ *lifetime_ret = lifetime;
+
+ if (cred_usage)
+ *cred_usage = cred->usage;
+ k5_mutex_unlock(&cred->lock);
+
+ if (mechanisms)
+ *mechanisms = mechs;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
+
+ krb5_free_context(context);
+ *minor_status = 0;
+ return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE);
+fail:
+ k5_mutex_unlock(&cred->lock);
+ krb5_gss_release_cred(&tmpmin, &defcred);
+ krb5_free_context(context);
+ return ret;
+}
+
+/* V2 interface */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
+ mech_type, name, initiator_lifetime,
+ acceptor_lifetime, cred_usage)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+ gss_OID mech_type;
+ gss_name_t *name;
+ OM_uint32 *initiator_lifetime;
+ OM_uint32 *acceptor_lifetime;
+ gss_cred_usage_t *cred_usage;
+{
+ krb5_gss_cred_id_t cred;
+ OM_uint32 lifetime;
+ OM_uint32 mstat;
+
+ cred = (krb5_gss_cred_id_t) cred_handle;
+ mstat = krb5_gss_inquire_cred(minor_status,
+ cred_handle,
+ name,
+ &lifetime,
+ cred_usage,
+ (gss_OID_set *) NULL);
+ if (mstat == GSS_S_COMPLETE) {
+ if (cred &&
+ ((cred->usage == GSS_C_INITIATE) ||
+ (cred->usage == GSS_C_BOTH)) &&
+ initiator_lifetime)
+ *initiator_lifetime = lifetime;
+ if (cred &&
+ ((cred->usage == GSS_C_ACCEPT) ||
+ (cred->usage == GSS_C_BOTH)) &&
+ acceptor_lifetime)
+ *acceptor_lifetime = lifetime;
+ }
+ return(mstat);
+}
diff --git a/src/lib/gssapi/krb5/inq_names.c b/src/lib/gssapi/krb5/inq_names.c
new file mode 100644
index 000000000000..b326adbb5f23
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_names.c
@@ -0,0 +1,100 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/inq_names.c - Return nametypes supported by krb5 mech */
+/*
+ * Copyright 1995 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+ OM_uint32 *minor_status;
+ gss_OID mechanism;
+ gss_OID_set *name_types;
+{
+ OM_uint32 major, minor;
+
+ /*
+ * We only know how to handle our own mechanism.
+ */
+ if ((mechanism != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mechanism) &&
+ !g_OID_equal(gss_mech_krb5_old, mechanism) &&
+ !g_OID_equal(gss_mech_krb5_wrong, mechanism) &&
+ !g_OID_equal(gss_mech_iakerb, mechanism)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* We're okay. Create an empty OID set */
+ major = generic_gss_create_empty_oid_set(minor_status, name_types);
+ if (major == GSS_S_COMPLETE) {
+ /* Now add our members. */
+ if (
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_user_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_machine_uid_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_string_uid_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_service_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_service_name_v2,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_exported_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_krb5_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ GSS_C_NT_COMPOSITE_EXPORT,
+ name_types)
+ ) == GSS_S_COMPLETE)
+ ) {
+ major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_krb5_principal,
+ name_types);
+ }
+
+ /*
+ * If we choked, then release the set, but don't overwrite the minor
+ * status with the release call.
+ */
+ if (major != GSS_S_COMPLETE)
+ (void) generic_gss_release_oid_set(&minor, name_types);
+ }
+ return(major);
+}
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
new file mode 100644
index 000000000000..4da531b58245
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -0,0 +1,413 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+#include <assert.h>
+
+static krb5_error_code
+make_seal_token_v1 (krb5_context context,
+ krb5_key enc,
+ krb5_key seq,
+ uint64_t *seqnum,
+ int direction,
+ gss_buffer_t text,
+ gss_buffer_t token,
+ int signalg,
+ size_t cksum_size,
+ int sealalg,
+ int do_encrypt,
+ int toktype,
+ gss_OID oid)
+{
+ krb5_error_code code;
+ size_t sumlen;
+ char *data_ptr;
+ krb5_data plaind;
+ krb5_checksum md5cksum;
+ krb5_checksum cksum;
+ /* msglen contains the message length
+ * we are signing/encrypting. tmsglen
+ * contains the length of the message
+ * we plan to write out to the token.
+ * tlen is the length of the token
+ * including header. */
+ unsigned int conflen=0, tmsglen, tlen, msglen;
+ unsigned char *t, *ptr;
+ unsigned char *plain;
+ unsigned char pad;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+
+ assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
+ /* create the token buffer */
+ /* Do we need confounder? */
+ if (do_encrypt || toktype == KG_TOK_SEAL_MSG)
+ conflen = kg_confounder_size(context, enc->keyblock.enctype);
+ else conflen = 0;
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ switch (sealalg) {
+ case SEAL_ALG_MICROSOFT_RC4:
+ msglen = conflen + text->length+1;
+ pad = 1;
+ break;
+ default:
+ /* XXX knows that des block size is 8 */
+ msglen = (conflen+text->length+8)&(~7);
+ pad = 8-(text->length%8);
+ }
+ tmsglen = msglen;
+ } else {
+ tmsglen = 0;
+ msglen = text->length;
+ pad = 0;
+ }
+ tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
+
+ if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL)
+ return(ENOMEM);
+
+ /*** fill in the token */
+
+ ptr = t;
+ g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);
+
+ /* 0..1 SIGN_ALG */
+ store_16_le(signalg, &ptr[0]);
+
+ /* 2..3 SEAL_ALG or Filler */
+ if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
+ store_16_le(sealalg, &ptr[2]);
+ } else {
+ /* No seal */
+ ptr[2] = 0xff;
+ ptr[3] = 0xff;
+ }
+
+ /* 4..5 Filler */
+ ptr[4] = 0xff;
+ ptr[5] = 0xff;
+
+ /* pad the plaintext, encrypt if needed, and stick it in the token */
+
+ /* initialize the the cksum */
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ if (toktype != KG_TOK_SEAL_MSG)
+ sign_usage = 15;
+ break;
+ default:
+ case SGN_ALG_DES_MAC:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code) {
+ gssalloc_free(t);
+ return(code);
+ }
+ md5cksum.length = sumlen;
+
+
+ if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
+ gssalloc_free(t);
+ return(ENOMEM);
+ }
+
+ if (conflen) {
+ if ((code = kg_make_confounder(context, enc->keyblock.enctype,
+ plain))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+
+ memcpy(plain+conflen, text->value, text->length);
+ if (pad) memset(plain+conflen+text->length, pad, pad);
+
+ /* compute the checksum */
+
+ /* 8 = head of token body as specified by mech spec */
+ if (! (data_ptr = xmalloc(8 + msglen))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(ENOMEM);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, plain, msglen);
+ plaind.length = 8 + msglen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type, seq,
+ sign_usage, &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ switch(signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case 3:
+
+ code = kg_encrypt_inplace(context, seq, KG_USAGE_SEAL,
+ (g_OID_equal(oid, gss_mech_krb5_old) ?
+ seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ xfree (plain);
+ gssalloc_free(t);
+ return code;
+ }
+
+ cksum.length = cksum_size;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ memcpy(ptr+14, cksum.contents, cksum.length);
+ break;
+
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ /*
+ * Using key derivation, the call to krb5_c_make_checksum
+ * already dealt with encrypting.
+ */
+ if (md5cksum.length != cksum_size)
+ abort ();
+ memcpy (ptr+14, md5cksum.contents, md5cksum.length);
+ break;
+ case SGN_ALG_HMAC_MD5:
+ memcpy (ptr+14, md5cksum.contents, cksum_size);
+ break;
+ }
+
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ /* create the seq_num */
+
+ if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
+ (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
+ xfree (plain);
+ gssalloc_free(t);
+ return(code);
+ }
+
+ if (do_encrypt) {
+ switch(sealalg) {
+ case SEAL_ALG_MICROSOFT_RC4:
+ {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ int i;
+ store_32_be(*seqnum, bigend_seqnum);
+ code = krb5_k_key_keyblock(context, enc, &enc_key);
+ if (code)
+ {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ assert (enc_key->length == 16);
+ for (i = 0; i <= 15; i++)
+ ((char *) enc_key->contents)[i] ^=0xf0;
+ code = kg_arcfour_docrypt (enc_key, 0,
+ bigend_seqnum, 4,
+ plain, tmsglen,
+ ptr+14+cksum_size);
+ krb5_free_keyblock (context, enc_key);
+ if (code)
+ {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+ break;
+ default:
+ if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
+ (krb5_pointer) plain,
+ (krb5_pointer) (ptr+cksum_size+14),
+ tmsglen))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+ }else {
+ if (tmsglen)
+ memcpy(ptr+14+cksum_size, plain, tmsglen);
+ }
+ xfree(plain);
+
+
+ /* that's it. return the token */
+
+ (*seqnum)++;
+ *seqnum &= 0xffffffffL;
+
+ token->length = tlen;
+ token->value = (void *) t;
+
+ return(0);
+}
+
+/* if signonly is true, ignore conf_req, conf_state,
+ and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
+
+OM_uint32
+kg_seal(minor_status, context_handle, conf_req_flag, qop_req,
+ input_message_buffer, conf_state, output_message_buffer, toktype)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ gss_buffer_t input_message_buffer;
+ int *conf_state;
+ gss_buffer_t output_message_buffer;
+ int toktype;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error_code code;
+ krb5_context context;
+
+ output_message_buffer->length = 0;
+ output_message_buffer->value = NULL;
+
+ /* Only default qop or matching established cryptosystem is allowed.
+
+ There are NO EXTENSIONS to this set for AES and friends! The
+ new spec says "just use 0". The old spec plus extensions would
+ actually allow for certain non-zero values. Fix this to handle
+ them later. */
+ if (qop_req != 0) {
+ *minor_status = (OM_uint32) G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ context = ctx->k5_context;
+ switch (ctx->proto)
+ {
+ case 0:
+ code = make_seal_token_v1(context, ctx->enc, ctx->seq,
+ &ctx->seq_send, ctx->initiate,
+ input_message_buffer, output_message_buffer,
+ ctx->signalg, ctx->cksum_size, ctx->sealalg,
+ conf_req_flag, toktype, ctx->mech_used);
+ break;
+ case 1:
+ code = gss_krb5int_make_seal_token_v3(context, ctx,
+ input_message_buffer,
+ output_message_buffer,
+ conf_req_flag, toktype);
+ break;
+ default:
+ code = G_UNKNOWN_QOP; /* XXX */
+ break;
+ }
+
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+
+ if (conf_state)
+ *conf_state = conf_req_flag;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap(minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ gss_buffer_t input_message_buffer;
+ int *conf_state;
+ gss_buffer_t output_message_buffer;
+{
+ return(kg_seal(minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, KG_TOK_WRAP_MSG));
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic(minor_status, context_handle, qop_req,
+ message_buffer, message_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_qop_t qop_req;
+ gss_buffer_t message_buffer;
+ gss_buffer_t message_token;
+{
+ return(kg_seal(minor_status, context_handle, 0,
+ qop_req, message_buffer, NULL,
+ message_token, KG_TOK_MIC_MSG));
+}
diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c
new file mode 100644
index 000000000000..88caa856f86a
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealiov.c
@@ -0,0 +1,557 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealiov.c */
+/*
+ * Copyright 2008, 2009 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static krb5_error_code
+make_seal_token_v1_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ krb5_checksum md5cksum;
+ krb5_checksum cksum;
+ size_t k5_headerlen = 0, k5_trailerlen = 0;
+ size_t data_length = 0, assoc_data_length = 0;
+ size_t tmsglen = 0, tlen;
+ unsigned char *ptr;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ md5cksum.length = cksum.length = 0;
+ md5cksum.contents = cksum.contents = NULL;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL)
+ return EINVAL;
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding == NULL && toktype == KG_TOK_WRAP_MSG &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+ return EINVAL;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL)
+ trailer->buffer.length = 0;
+
+ /* Determine confounder length */
+ if (toktype == KG_TOK_WRAP_MSG || conf_req_flag)
+ k5_headerlen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ /* Check padding length */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
+ size_t gss_padlen;
+ size_t conf_data_length;
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+ conf_data_length = k5_headerlen + data_length - assoc_data_length;
+
+ if (k5_padlen == 1)
+ gss_padlen = 1; /* one byte to indicate one byte of padding */
+ else
+ gss_padlen = k5_padlen - (conf_data_length % k5_padlen);
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /* DCE will pad the actual data itself; padding buffer optional and will be zeroed */
+ gss_padlen = 0;
+
+ if (conf_data_length % k5_padlen)
+ code = KRB5_BAD_MSIZE;
+ } else if (padding->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(padding, gss_padlen);
+ } else if (padding->buffer.length < gss_padlen) {
+ code = KRB5_BAD_MSIZE;
+ }
+ if (code != 0)
+ goto cleanup;
+
+ /* Initialize padding buffer to pad itself */
+ if (padding != NULL) {
+ padding->buffer.length = gss_padlen;
+ memset(padding->buffer.value, (int)gss_padlen, gss_padlen);
+ }
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ tmsglen = k5_headerlen; /* confounder length */
+ else
+ tmsglen = conf_data_length + padding->buffer.length;
+ }
+
+ /* Determine token size */
+ tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen);
+
+ k5_headerlen += tlen - tmsglen;
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(header, k5_headerlen);
+ else if (header->buffer.length < k5_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+
+ header->buffer.length = k5_headerlen;
+
+ ptr = (unsigned char *)header->buffer.value;
+ g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype);
+
+ /* 0..1 SIGN_ALG */
+ store_16_le(ctx->signalg, &ptr[0]);
+
+ /* 2..3 SEAL_ALG or Filler */
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ store_16_le(ctx->sealalg, &ptr[2]);
+ } else {
+ /* No seal */
+ ptr[2] = 0xFF;
+ ptr[3] = 0xFF;
+ }
+
+ /* 4..5 Filler */
+ ptr[4] = 0xFF;
+ ptr[5] = 0xFF;
+
+ /* pad the plaintext, encrypt if needed, and stick it in the token */
+
+ /* initialize the checksum */
+ switch (ctx->signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ if (toktype != KG_TOK_WRAP_MSG)
+ sign_usage = 15;
+ break;
+ default:
+ case SGN_ALG_DES_MAC:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+ md5cksum.length = k5_trailerlen;
+
+ if (k5_headerlen != 0 && toktype == KG_TOK_WRAP_MSG) {
+ code = kg_make_confounder(context, ctx->enc->keyblock.enctype,
+ ptr + 14 + ctx->cksum_size);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* compute the checksum */
+ code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
+ ctx->cksum_size, ctx->seq, ctx->enc,
+ sign_usage, iov, iov_count, toktype,
+ &md5cksum);
+ if (code != 0)
+ goto cleanup;
+
+ switch (ctx->signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code != 0)
+ goto cleanup;
+
+ cksum.length = ctx->cksum_size;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ memcpy(ptr + 14, cksum.contents, cksum.length);
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ assert(md5cksum.length == ctx->cksum_size);
+ memcpy(ptr + 14, md5cksum.contents, md5cksum.length);
+ break;
+ case SGN_ALG_HMAC_MD5:
+ memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size);
+ break;
+ }
+
+ /* create the seq_num */
+ code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
+ (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6);
+ if (code != 0)
+ goto cleanup;
+
+ if (conf_req_flag) {
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ size_t i;
+
+ store_32_be(ctx->seq_send, bigend_seqnum);
+
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code != 0)
+ goto cleanup;
+
+ assert(enc_key->length == 16);
+
+ for (i = 0; i < enc_key->length; i++)
+ ((char *)enc_key->contents)[i] ^= 0xF0;
+
+ code = kg_arcfour_docrypt_iov(context, enc_key, 0,
+ bigend_seqnum, 4,
+ iov, iov_count);
+ krb5_free_keyblock(context, enc_key);
+ } else {
+ code = kg_encrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ 0 /*EC*/, 0 /*RRC*/,
+ ctx->enc, KG_USAGE_SEAL, NULL,
+ iov, iov_count);
+ }
+ if (code != 0)
+ goto cleanup;
+ }
+
+ ctx->seq_send++;
+ ctx->seq_send &= 0xFFFFFFFFL;
+
+ code = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+cleanup:
+ if (code != 0)
+ kg_release_iov(iov, iov_count);
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ return code;
+}
+
+OM_uint32
+kg_seal_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error_code code;
+ krb5_context context;
+
+ if (qop_req != 0) {
+ *minor_status = (OM_uint32)G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (conf_req_flag && kg_integ_only_iov(iov, iov_count)) {
+ /* may be more sensible to return an error here */
+ conf_req_flag = FALSE;
+ }
+
+ context = ctx->k5_context;
+ switch (ctx->proto) {
+ case 0:
+ code = make_seal_token_v1_iov(context, ctx, conf_req_flag,
+ conf_state, iov, iov_count, toktype);
+ break;
+ case 1:
+ code = gss_krb5int_make_seal_token_v3_iov(context, ctx, conf_req_flag,
+ conf_state, iov, iov_count, toktype);
+ break;
+ default:
+ code = G_UNKNOWN_QOP;
+ break;
+ }
+
+ if (code != 0) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return GSS_S_FAILURE;
+ }
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+#define INIT_IOV_DATA(_iov) do { (_iov)->buffer.value = NULL; \
+ (_iov)->buffer.length = 0; } \
+ while (0)
+
+OM_uint32
+kg_seal_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_iov_buffer_t header, trailer, padding;
+ size_t data_length, assoc_data_length;
+ size_t gss_headerlen, gss_padlen, gss_trailerlen;
+ unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0;
+ krb5_error_code code;
+ krb5_context context;
+ int dce_or_mic;
+
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor_status = (OM_uint32)G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (!ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ INIT_IOV_DATA(header);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL) {
+ INIT_IOV_DATA(trailer);
+ }
+
+ /* MIC tokens and DCE-style wrap tokens have similar length considerations:
+ * no padding, and the framing surrounds the header only, not the data. */
+ dce_or_mic = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0 ||
+ toktype == KG_TOK_MIC_MSG);
+
+ /* For CFX, EC is used instead of padding, and is placed in header or trailer */
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding == NULL) {
+ if (conf_req_flag && ctx->proto == 0 && !dce_or_mic) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ } else {
+ INIT_IOV_DATA(padding);
+ }
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ if (conf_req_flag && kg_integ_only_iov(iov, iov_count))
+ conf_req_flag = FALSE;
+
+ context = ctx->k5_context;
+
+ gss_headerlen = gss_padlen = gss_trailerlen = 0;
+
+ if (ctx->proto == 1) {
+ krb5_key key;
+ krb5_enctype enctype;
+ size_t ec;
+
+ key = (ctx->have_acceptor_subkey) ? ctx->acceptor_subkey : ctx->subkey;
+ enctype = key->keyblock.enctype;
+
+ code = krb5_c_crypto_length(context, enctype,
+ conf_req_flag ?
+ KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ gss_headerlen = 16; /* Header */
+ if (conf_req_flag) {
+ gss_headerlen += k5_headerlen; /* Kerb-Header */
+ gss_trailerlen = 16 /* E(Header) */ + k5_trailerlen; /* Kerb-Trailer */
+
+ code = krb5_c_padding_length(context, enctype,
+ data_length - assoc_data_length + 16 /* E(Header) */, &k5_padlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (k5_padlen == 0 && dce_or_mic) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(context, enctype, &ec);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ } else
+ ec = k5_padlen;
+
+ gss_trailerlen += ec;
+ } else {
+ gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */
+ }
+ } else if (!dce_or_mic) {
+ k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
+
+ if (k5_padlen == 1)
+ gss_padlen = 1;
+ else
+ gss_padlen = k5_padlen - ((data_length - assoc_data_length) % k5_padlen);
+ }
+
+ data_length += gss_padlen;
+
+ if (ctx->proto == 0) {
+ /* Header | Checksum | Confounder | Data | Pad */
+ size_t data_size;
+
+ k5_headerlen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen;
+
+ if (!dce_or_mic)
+ data_size += data_length;
+
+ gss_headerlen = g_token_size(ctx->mech_used, data_size);
+
+ /* g_token_size() will include data_size as well as the overhead, so
+ * subtract data_length just to get the overhead (ie. token size) */
+ if (!dce_or_mic)
+ gss_headerlen -= data_length;
+ }
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (trailer == NULL)
+ gss_headerlen += gss_trailerlen;
+ else
+ trailer->buffer.length = gss_trailerlen;
+
+ assert(gss_padlen == 0 || padding != NULL);
+
+ if (padding != NULL)
+ padding->buffer.length = gss_padlen;
+
+ header->buffer.length = gss_headerlen;
+
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov(minor_status, context_handle, conf_req_flag,
+ qop_req, conf_state,
+ iov, iov_count, KG_TOK_WRAP_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov_length(minor_status, context_handle,
+ conf_req_flag, qop_req, conf_state, iov,
+ iov_count, KG_TOK_WRAP_MSG);
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov(minor_status, context_handle, FALSE,
+ qop_req, NULL,
+ iov, iov_count, KG_TOK_MIC_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov_length(minor_status, context_handle, FALSE,
+ qop_req, NULL, iov, iov_count,
+ KG_TOK_MIC_MSG);
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
new file mode 100644
index 000000000000..1a5c14c2713b
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealv3.c
@@ -0,0 +1,512 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealv3.c */
+/*
+ * Copyright 2003,2004,2007 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.
+ */
+
+/* draft-ietf-krb-wg-gssapi-cfx-05 */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+int
+gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc)
+{
+ /* Optimize for receiving. After some debugging is done, the MIT
+ implementation won't do any rotates on sending, and while
+ debugging, they'll be randomly chosen.
+
+ Return 1 for success, 0 for failure (ENOMEM). */
+ void *tbuf;
+
+ if (bufsiz == 0)
+ return 1;
+ rc = rc % bufsiz;
+ if (rc == 0)
+ return 1;
+
+ tbuf = malloc(rc);
+ if (tbuf == 0)
+ return 0;
+ memcpy(tbuf, ptr, rc);
+ memmove(ptr, (char *)ptr + rc, bufsiz - rc);
+ memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
+ free(tbuf);
+ return 1;
+}
+
+static const gss_buffer_desc empty_message = { 0, 0 };
+
+krb5_error_code
+gss_krb5int_make_seal_token_v3 (krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ const gss_buffer_desc * message,
+ gss_buffer_t token,
+ int conf_req_flag, int toktype)
+{
+ size_t bufsize = 16;
+ unsigned char *outbuf = 0;
+ krb5_error_code err;
+ int key_usage;
+ unsigned char acceptor_flag;
+ const gss_buffer_desc *message2 = message;
+#ifdef CFX_EXERCISE
+ size_t rrc;
+#endif
+ size_t ec;
+ unsigned short tok_id;
+ krb5_checksum sum;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+
+ acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+#ifdef CFX_EXERCISE
+ {
+ static int initialized = 0;
+ if (!initialized) {
+ srand(time(0));
+ initialized = 1;
+ }
+ }
+#endif
+
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ krb5_data plain;
+ krb5_enc_data cipher;
+ size_t ec_max;
+
+ /* 300: Adds some slop. */
+ if (SIZE_MAX - 300 < message->length)
+ return ENOMEM;
+ ec_max = SIZE_MAX - message->length - 300;
+ if (ec_max > 0xffff)
+ ec_max = 0xffff;
+#ifdef CFX_EXERCISE
+ /* For testing only. For performance, always set ec = 0. */
+ ec = ec_max & rand();
+#else
+ ec = 0;
+#endif
+ err = alloc_data(&plain, message->length + 16 + ec);
+ if (err)
+ return err;
+
+ /* Get size of ciphertext. */
+ bufsize = 16 + krb5_encrypt_size (plain.length, key->keyblock.enctype);
+ /* Allocate space for header plus encrypted data. */
+ outbuf = gssalloc_malloc(bufsize);
+ if (outbuf == NULL) {
+ free(plain.data);
+ return ENOMEM;
+ }
+
+ /* TOK_ID */
+ store_16_be(KG2_TOK_WRAP_MSG, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xff;
+ /* EC */
+ store_16_be(ec, outbuf+4);
+ /* RRC */
+ store_16_be(0, outbuf+6);
+ store_64_be(ctx->seq_send, outbuf+8);
+
+ memcpy(plain.data, message->value, message->length);
+ if (ec != 0)
+ memset(plain.data + message->length, 'x', ec);
+ memcpy(plain.data + message->length + ec, outbuf, 16);
+
+ cipher.ciphertext.data = (char *)outbuf + 16;
+ cipher.ciphertext.length = bufsize - 16;
+ cipher.enctype = key->keyblock.enctype;
+ err = krb5_k_encrypt(context, key, key_usage, 0, &plain, &cipher);
+ zap(plain.data, plain.length);
+ free(plain.data);
+ plain.data = 0;
+ if (err)
+ goto error;
+
+ /* Now that we know we're returning a valid token.... */
+ ctx->seq_send++;
+
+#ifdef CFX_EXERCISE
+ rrc = rand() & 0xffff;
+ if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
+ (bufsize-16) - (rrc % (bufsize - 16))))
+ store_16_be(rrc, outbuf+6);
+ /* If the rotate fails, don't worry about it. */
+#endif
+ } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
+ krb5_data plain;
+ size_t cksumsize;
+
+ /* Here, message is the application-supplied data; message2 is
+ what goes into the output token. They may be the same, or
+ message2 may be empty (for MIC). */
+
+ tok_id = KG2_TOK_WRAP_MSG;
+
+ wrap_with_checksum:
+ err = alloc_data(&plain, message->length + 16);
+ if (err)
+ return err;
+
+ err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
+ if (err)
+ goto error;
+
+ assert(cksumsize <= 0xffff);
+
+ bufsize = 16 + message2->length + cksumsize;
+ outbuf = gssalloc_malloc(bufsize);
+ if (outbuf == NULL) {
+ free(plain.data);
+ plain.data = 0;
+ err = ENOMEM;
+ goto error;
+ }
+
+ /* TOK_ID */
+ store_16_be(tok_id, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xff;
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Use 0 for checksum calculation, substitute
+ checksum length later. */
+ /* EC */
+ store_16_be(0, outbuf+4);
+ /* RRC */
+ store_16_be(0, outbuf+6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC. */
+ store_16_be(0xffff, outbuf+4);
+ store_16_be(0xffff, outbuf+6);
+ }
+ store_64_be(ctx->seq_send, outbuf+8);
+
+ memcpy(plain.data, message->value, message->length);
+ memcpy(plain.data + message->length, outbuf, 16);
+
+ /* Fill in the output token -- data contents, if any, and
+ space for the checksum. */
+ if (message2->length)
+ memcpy(outbuf + 16, message2->value, message2->length);
+
+ sum.contents = outbuf + 16 + message2->length;
+ sum.length = cksumsize;
+
+ err = krb5_k_make_checksum(context, cksumtype, key,
+ key_usage, &plain, &sum);
+ zap(plain.data, plain.length);
+ free(plain.data);
+ plain.data = 0;
+ if (err) {
+ zap(outbuf,bufsize);
+ goto error;
+ }
+ if (sum.length != cksumsize)
+ abort();
+ memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
+ krb5_free_checksum_contents(context, &sum);
+ sum.contents = 0;
+ /* Now that we know we're actually generating the token... */
+ ctx->seq_send++;
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+#ifdef CFX_EXERCISE
+ rrc = rand() & 0xffff;
+ /* If the rotate fails, don't worry about it. */
+ if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
+ (bufsize-16) - (rrc % (bufsize - 16))))
+ store_16_be(rrc, outbuf+6);
+#endif
+ /* Fix up EC field. */
+ store_16_be(cksumsize, outbuf+4);
+ } else {
+ store_16_be(0xffff, outbuf+6);
+ }
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ tok_id = KG2_TOK_MIC_MSG;
+ message2 = &empty_message;
+ goto wrap_with_checksum;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ tok_id = KG2_TOK_DEL_CTX;
+ message = message2 = &empty_message;
+ goto wrap_with_checksum;
+ } else
+ abort();
+
+ token->value = outbuf;
+ token->length = bufsize;
+ return 0;
+
+error:
+ gssalloc_free(outbuf);
+ token->value = NULL;
+ token->length = 0;
+ return err;
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ unsigned char *ptr, unsigned int bodysize,
+ gss_buffer_t message_buffer,
+ int *conf_state, gss_qop_t *qop_state, int toktype)
+{
+ krb5_context context = *contextptr;
+ krb5_data plain;
+ uint64_t seqnum;
+ size_t ec, rrc;
+ int key_usage;
+ unsigned char acceptor_flag;
+ krb5_checksum sum;
+ krb5_error_code err;
+ krb5_boolean valid;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+
+ /* Oops. I wrote this code assuming ptr would be at the start of
+ the token header. */
+ ptr -= 2;
+ bodysize += 2;
+
+ if (bodysize < 16) {
+ defective:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Two things to note here.
+
+ First, we can't really enforce the use of the acceptor's subkey,
+ if we're the acceptor; the initiator may have sent messages
+ before getting the subkey. We could probably enforce it if
+ we're the initiator.
+
+ Second, if someone tweaks the code to not set the flag telling
+ the krb5 library to generate a new subkey in the AP-REP
+ message, the MIT library may include a subkey anyways --
+ namely, a copy of the AP-REQ subkey, if it was provided. So
+ the initiator may think we wanted a subkey, and set the flag,
+ even though we weren't trying to set the subkey. The "other"
+ key, the one not asserted by the acceptor, will have the same
+ value in that case, though, so we can just ignore the flag. */
+ if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
+ goto defective;
+ if (ptr[3] != 0xff)
+ goto defective;
+ ec = load_16_be(ptr+4);
+ rrc = load_16_be(ptr+6);
+ seqnum = load_64_be(ptr+8);
+ if (!gss_krb5int_rotate_left(ptr+16, bodysize-16, rrc)) {
+ no_mem:
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
+ /* confidentiality */
+ krb5_enc_data cipher;
+ unsigned char *althdr;
+
+ if (conf_state)
+ *conf_state = 1;
+ /* Do we have no decrypt_size function?
+
+ For all current cryptosystems, the ciphertext size will
+ be larger than the plaintext size. */
+ cipher.enctype = key->keyblock.enctype;
+ cipher.ciphertext.length = bodysize - 16;
+ cipher.ciphertext.data = (char *)ptr + 16;
+ plain.length = bodysize - 16;
+ plain.data = gssalloc_malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ err = krb5_k_decrypt(context, key, key_usage, 0,
+ &cipher, &plain);
+ if (err) {
+ gssalloc_free(plain.data);
+ goto error;
+ }
+ /* Don't use bodysize here! Use the fact that
+ cipher.ciphertext.length has been adjusted to the
+ correct length. */
+ althdr = (unsigned char *)plain.data + plain.length - 16;
+ if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr+8, ptr+8, 8)) {
+ free(plain.data);
+ goto defective;
+ }
+ message_buffer->value = plain.data;
+ message_buffer->length = plain.length - ec - 16;
+ if(message_buffer->length == 0) {
+ gssalloc_free(message_buffer->value);
+ message_buffer->value = NULL;
+ }
+ } else {
+ size_t cksumsize;
+
+ err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
+ if (err)
+ goto error;
+
+ /* no confidentiality */
+ if (conf_state)
+ *conf_state = 0;
+ if (ec + 16 < ec)
+ /* overflow check */
+ goto defective;
+ if (ec + 16 > bodysize)
+ goto defective;
+ /* We have: header | msg | cksum.
+ We need cksum(msg | header).
+ Rotate the first two. */
+ store_16_be(0, ptr+4);
+ store_16_be(0, ptr+6);
+ plain = make_data(ptr, bodysize - ec);
+ if (!gss_krb5int_rotate_left(ptr, bodysize-ec, 16))
+ goto no_mem;
+ sum.length = ec;
+ if (sum.length != cksumsize) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ sum.contents = ptr+bodysize-ec;
+ sum.checksum_type = cksumtype;
+ err = krb5_k_verify_checksum(context, key, key_usage,
+ &plain, &sum, &valid);
+ if (err)
+ goto error;
+ if (!valid) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ message_buffer->length = plain.length - 16;
+ message_buffer->value = gssalloc_malloc(message_buffer->length);
+ if (message_buffer->value == NULL)
+ goto no_mem;
+ memcpy(message_buffer->value, plain.data, message_buffer->length);
+ }
+ err = g_seqstate_check(ctx->seqstate, seqnum);
+ *minor_status = 0;
+ return err;
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ /* wrap token, no confidentiality */
+ if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
+ goto defective;
+ verify_mic_1:
+ if (ptr[3] != 0xff)
+ goto defective;
+ if (load_32_be(ptr+4) != 0xffffffffL)
+ goto defective;
+ seqnum = load_64_be(ptr+8);
+ plain.length = message_buffer->length + 16;
+ plain.data = malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ if (message_buffer->length)
+ memcpy(plain.data, message_buffer->value, message_buffer->length);
+ memcpy(plain.data + message_buffer->length, ptr, 16);
+ sum.length = bodysize - 16;
+ sum.contents = ptr + 16;
+ sum.checksum_type = cksumtype;
+ err = krb5_k_verify_checksum(context, key, key_usage,
+ &plain, &sum, &valid);
+ free(plain.data);
+ plain.data = NULL;
+ if (err) {
+ error:
+ *minor_status = err;
+ save_error_info(*minor_status, context);
+ return GSS_S_BAD_SIG; /* XXX */
+ }
+ if (!valid) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ err = g_seqstate_check(ctx->seqstate, seqnum);
+ *minor_status = 0;
+ return err;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
+ goto defective;
+ message_buffer = (gss_buffer_t)&empty_message;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+}
diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c
new file mode 100644
index 000000000000..a73edb6a4ffd
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealv3iov.c
@@ -0,0 +1,468 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealv3iov.c */
+/*
+ * Copyright 2008 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+krb5_error_code
+gss_krb5int_make_seal_token_v3_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned short tok_id;
+ unsigned char *outbuf = NULL;
+ unsigned char *tbuf = NULL;
+ int key_usage;
+ size_t rrc = 0;
+ unsigned int gss_headerlen, gss_trailerlen;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+ size_t data_length, assoc_data_length;
+
+ assert(ctx->proto == 1);
+
+ acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+ assert(cksumtype != 0);
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL)
+ return EINVAL;
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL)
+ padding->buffer.length = 0;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ unsigned int k5_headerlen, k5_trailerlen, k5_padlen;
+ size_t ec = 0;
+ size_t conf_data_length = data_length - assoc_data_length;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_padding_length(context, key->keyblock.enctype,
+ conf_data_length + 16 /* E(Header) */, &k5_padlen);
+ if (code != 0)
+ goto cleanup;
+
+ if (k5_padlen == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(context, key->keyblock.enctype, &ec);
+ if (code != 0)
+ goto cleanup;
+ } else
+ ec = k5_padlen;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ gss_headerlen = 16 /* Header */ + k5_headerlen;
+ gss_trailerlen = ec + 16 /* E(Header) */ + k5_trailerlen;
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ /* Workaround for Windows bug where it rotates by EC + RRC */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ rrc -= ec;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(header, (size_t) gss_headerlen);
+ } else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be(KG2_TOK_WRAP_MSG, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ /* EC */
+ store_16_be(ec, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ store_64_be(ctx->seq_send, outbuf + 8);
+
+ /* EC | copy of header to be encrypted, located in (possibly rotated) trailer */
+ if (trailer == NULL)
+ tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
+ else
+ tbuf = (unsigned char *)trailer->buffer.value;
+
+ memset(tbuf, 0xFF, ec);
+ memcpy(tbuf + ec, header->buffer.value, 16);
+
+ code = kg_encrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, key, key_usage, 0, iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ /* RRC */
+ store_16_be(rrc, outbuf + 6);
+
+ ctx->seq_send++;
+ } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
+ tok_id = KG2_TOK_WRAP_MSG;
+
+ wrap_with_checksum:
+
+ gss_headerlen = 16;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &gss_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ assert(gss_trailerlen <= 0xFFFF);
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(header, (size_t) gss_headerlen);
+ else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be(tok_id, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Use 0 for checksum calculation, substitute
+ * checksum length later.
+ */
+ /* EC */
+ store_16_be(0, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC */
+ store_16_be(0xFFFF, outbuf + 4);
+ store_16_be(0xFFFF, outbuf + 6);
+ }
+ store_64_be(ctx->seq_send, outbuf + 8);
+
+ code = kg_make_checksum_iov_v3(context, cksumtype,
+ rrc, key, key_usage,
+ iov, iov_count, toktype);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->seq_send++;
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Fix up EC field */
+ store_16_be(gss_trailerlen, outbuf + 4);
+ /* Fix up RRC field */
+ store_16_be(rrc, outbuf + 6);
+ }
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ tok_id = KG2_TOK_MIC_MSG;
+ trailer = NULL;
+ goto wrap_with_checksum;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ tok_id = KG2_TOK_DEL_CTX;
+ goto wrap_with_checksum;
+ } else {
+ abort();
+ }
+
+ code = 0;
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+cleanup:
+ if (code != 0)
+ kg_release_iov(iov, iov_count);
+
+ return code;
+}
+
+OM_uint32
+gss_krb5int_unseal_v3_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned char *ptr = NULL;
+ int key_usage;
+ size_t rrc, ec;
+ size_t data_length, assoc_data_length;
+ krb5_key key;
+ uint64_t seqnum;
+ krb5_boolean valid;
+ krb5_cksumtype cksumtype;
+ int conf_flag = 0;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL && padding->buffer.length != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ ptr = (unsigned char *)header->buffer.value;
+
+ if (header->buffer.length < 16) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+
+ if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ unsigned int k5_trailerlen;
+
+ if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
+ goto defective;
+ conf_flag = ((ptr[2] & FLAG_WRAP_CONFIDENTIAL) != 0);
+ if (ptr[3] != 0xFF)
+ goto defective;
+ ec = load_16_be(ptr + 4);
+ rrc = load_16_be(ptr + 6);
+ seqnum = load_64_be(ptr + 8);
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* Deal with RRC */
+ if (trailer == NULL) {
+ size_t desired_rrc = k5_trailerlen;
+
+ if (conf_flag) {
+ desired_rrc += 16; /* E(Header) */
+
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+ desired_rrc += ec;
+ }
+
+ /* According to MS, we only need to deal with a fixed RRC for DCE */
+ if (rrc != desired_rrc)
+ goto defective;
+ } else if (rrc != 0) {
+ /* Should have been rotated by kg_unseal_stream_iov() */
+ goto defective;
+ }
+
+ if (conf_flag) {
+ unsigned char *althdr;
+
+ /* Decrypt */
+ code = kg_decrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc,
+ key, key_usage, 0, iov, iov_count);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Validate header integrity */
+ if (trailer == NULL)
+ althdr = (unsigned char *)header->buffer.value + 16 + ec;
+ else
+ althdr = (unsigned char *)trailer->buffer.value + ec;
+
+ if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr + 8, ptr + 8, 8) != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ } else {
+ /* Verify checksum: note EC is checksum size here, not padding */
+ if (ec != k5_trailerlen)
+ goto defective;
+
+ /* Zero EC, RRC before computing checksum */
+ store_16_be(0, ptr + 4);
+ store_16_be(0, ptr + 6);
+
+ code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
+ key, key_usage,
+ iov, iov_count, toktype, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ }
+
+ code = g_seqstate_check(ctx->seqstate, seqnum);
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
+ goto defective;
+
+ verify_mic_1:
+ if (ptr[3] != 0xFF)
+ goto defective;
+ seqnum = load_64_be(ptr + 8);
+
+ /* For MIC tokens, the GSS header and checksum are in the same buffer.
+ * Fake up an RRC so that the checksum is expected in the header. */
+ rrc = (trailer != NULL) ? 0 : header->buffer.length - 16;
+ code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
+ key, key_usage,
+ iov, iov_count, toktype, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ code = g_seqstate_check(ctx->seqstate, seqnum);
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
+ goto defective;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+
+ *minor_status = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_flag;
+
+ return code;
+
+defective:
+ *minor_status = 0;
+
+ return GSS_S_DEFECTIVE_TOKEN;
+}
diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c
new file mode 100644
index 000000000000..26a2d33e7a2c
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5unseal.c
@@ -0,0 +1,588 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2007 by the Massachusetts Institute of Technology.
+ * Copyright 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+static OM_uint32
+kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ gss_buffer_t message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+ int toktype;
+{
+ krb5_error_code code;
+ int conflen = 0;
+ int signalg;
+ int sealalg;
+ int bad_pad = 0;
+ gss_buffer_desc token;
+ krb5_checksum cksum;
+ krb5_checksum md5cksum;
+ krb5_data plaind;
+ char *data_ptr;
+ unsigned char *plain;
+ unsigned int cksum_len = 0;
+ size_t plainlen;
+ int direction;
+ krb5_ui_4 seqnum;
+ OM_uint32 retval;
+ size_t sumlen;
+ size_t padlen;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ message_buffer->length = 0;
+ message_buffer->value = NULL;
+ }
+
+ /* Sanity checks */
+
+ if (ctx->seq == NULL) {
+ /* ctx was established using a newer enctype, and cannot process RFC
+ * 1964 tokens. */
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((bodysize < 22) || (ptr[4] != 0xff) || (ptr[5] != 0xff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ signalg = ptr[0] + (ptr[1]<<8);
+ sealalg = ptr[2] + (ptr[3]<<8);
+
+ if ((toktype != KG_TOK_SEAL_MSG) &&
+ (sealalg != 0xffff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* in the current spec, there is only one valid seal algorithm per
+ key type, so a simple comparison is ok */
+
+ if ((toktype == KG_TOK_SEAL_MSG) &&
+ !((sealalg == 0xffff) ||
+ (sealalg == ctx->sealalg))) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* there are several mappings of seal algorithms to sign algorithms,
+ but few enough that we can try them all. */
+
+ if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+ (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+ (ctx->sealalg == SEAL_ALG_DES3KD &&
+ signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
+ (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
+ signalg != SGN_ALG_HMAC_MD5)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_HMAC_MD5:
+ cksum_len = 8;
+ if (toktype != KG_TOK_SEAL_MSG)
+ sign_usage = 15;
+ break;
+ case SGN_ALG_3:
+ cksum_len = 16;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ cksum_len = 20;
+ break;
+ default:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((size_t)bodysize < 14 + cksum_len) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* get the token parameters */
+
+ if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
+ &seqnum))) {
+ *minor_status = code;
+ return(GSS_S_BAD_SIG);
+ }
+
+ /* decode the message, if SEAL */
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ size_t tmsglen = bodysize-(14+cksum_len);
+ if (sealalg != 0xffff) {
+ if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ int i;
+ store_32_be(seqnum, bigend_seqnum);
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code)
+ {
+ xfree(plain);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ assert (enc_key->length == 16);
+ for (i = 0; i <= 15; i++)
+ ((char *) enc_key->contents)[i] ^=0xf0;
+ code = kg_arcfour_docrypt (enc_key, 0,
+ &bigend_seqnum[0], 4,
+ ptr+14+cksum_len, tmsglen,
+ plain);
+ krb5_free_keyblock (context, enc_key);
+ } else {
+ code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
+ ptr+14+cksum_len, plain, tmsglen);
+ }
+ if (code) {
+ xfree(plain);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ plain = ptr+14+cksum_len;
+ }
+
+ plainlen = tmsglen;
+
+ conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+ if (tmsglen < conflen) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+ padlen = plain[tmsglen - 1];
+ if (tmsglen - conflen < padlen) {
+ /* Don't error out yet, to avoid padding oracle attacks. We will
+ * treat this as a checksum failure later on. */
+ padlen = 0;
+ bad_pad = 1;
+ }
+ token.length = tmsglen - conflen - padlen;
+
+ if (token.length) {
+ if ((token.value = (void *) gssalloc_malloc(token.length)) == NULL) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ memcpy(token.value, plain+conflen, token.length);
+ } else {
+ token.value = NULL;
+ }
+ } else if (toktype == KG_TOK_SIGN_MSG) {
+ token = *message_buffer;
+ plain = token.value;
+ plainlen = token.length;
+ } else {
+ token.length = 0;
+ token.value = NULL;
+ plain = token.value;
+ plainlen = token.length;
+ }
+
+ /* compute the checksum of the message */
+
+ /* initialize the the cksum */
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_DES_MAC:
+ case SGN_ALG_3:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ default:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code)
+ return(code);
+ md5cksum.length = sumlen;
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ /* compute the checksum of the message */
+
+ /* 8 = bytes of token body to be checksummed according to spec */
+
+ if (! (data_ptr = xmalloc(8 + plainlen))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ (void) memcpy(data_ptr, ptr-2, 8);
+
+ (void) memcpy(data_ptr+8, plain, plainlen);
+
+ plaind.length = 8 + plainlen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (signalg == 0)
+ cksum.length = 8;
+ else
+ cksum.length = 16;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
+ break;
+
+ case SGN_ALG_MD2_5:
+ if (!ctx->seed_init &&
+ (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (! (data_ptr = xmalloc(sizeof(ctx->seed) + 8 + plainlen))) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed), plain, plainlen);
+ plaind.length = 8 + sizeof(ctx->seed) + plainlen;
+ plaind.data = data_ptr;
+ krb5_free_checksum_contents(context, &md5cksum);
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = k5_bcmp(md5cksum.contents, ptr + 14, 8);
+ /* Falls through to defective-token?? */
+
+ default:
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ case SGN_ALG_HMAC_MD5:
+ /* compute the checksum of the message */
+
+ /* 8 = bytes of token body to be checksummed according to spec */
+
+ if (! (data_ptr = xmalloc(8 + plainlen))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ (void) memcpy(data_ptr, ptr-2, 8);
+
+ (void) memcpy(data_ptr+8, plain, plainlen);
+
+ plaind.length = 8 + plainlen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
+ break;
+ }
+
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg != 0xffff)
+ xfree(plain);
+
+ /* compare the computed checksum against the transmitted checksum */
+
+ if (code || bad_pad) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = 0;
+ return(GSS_S_BAD_SIG);
+ }
+
+
+ /* It got through unscathed. Make sure the context is unexpired. */
+
+ if (toktype == KG_TOK_SEAL_MSG)
+ *message_buffer = token;
+
+ if (conf_state)
+ *conf_state = (sealalg != 0xffff);
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ /* do sequencing checks */
+
+ if ((ctx->initiate && direction != 0xff) ||
+ (!ctx->initiate && direction != 0)) {
+ if (toktype == KG_TOK_SEAL_MSG) {
+ gssalloc_free(token.value);
+ message_buffer->value = NULL;
+ message_buffer->length = 0;
+ }
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
+ }
+
+ retval = g_seqstate_check(ctx->seqstate, (uint64_t)seqnum);
+
+ /* success or ordering violation */
+
+ *minor_status = 0;
+ return(retval);
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+kg_unseal(minor_status, context_handle, input_token_buffer,
+ message_buffer, conf_state, qop_state, toktype)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t input_token_buffer;
+ gss_buffer_t message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+ int toktype;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ unsigned int bodysize;
+ int err;
+ int toktype2;
+ int vfyflags = 0;
+ OM_uint32 ret;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ /* parse the token, leave the data in message_buffer, setting conf_state */
+
+ /* verify the header */
+
+ ptr = (unsigned char *) input_token_buffer->value;
+
+
+ err = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ input_token_buffer->length,
+ vfyflags);
+ if (err) {
+ *minor_status = err;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX:
+ ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
+ ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype);
+ break;
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
+ message_buffer, conf_state, qop_state,
+ toktype);
+ break;
+ default:
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ break;
+ }
+
+ if (ret != 0)
+ save_error_info (*minor_status, ctx->k5_context);
+
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_unwrap(minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t input_message_buffer;
+ gss_buffer_t output_message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+{
+ OM_uint32 rstat;
+
+ rstat = kg_unseal(minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, KG_TOK_WRAP_MSG);
+ return(rstat);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_verify_mic(minor_status, context_handle,
+ message_buffer, token_buffer,
+ qop_state)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t message_buffer;
+ gss_buffer_t token_buffer;
+ gss_qop_t *qop_state;
+{
+ OM_uint32 rstat;
+
+ rstat = kg_unseal(minor_status, context_handle,
+ token_buffer, message_buffer,
+ NULL, qop_state, KG_TOK_MIC_MSG);
+ return(rstat);
+}
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
new file mode 100644
index 000000000000..8b6704274db8
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
@@ -0,0 +1,675 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5unsealiov.c */
+/*
+ * Copyright 2008, 2009 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static OM_uint32
+kg_unseal_v1_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t token_wrapper_len,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t trailer;
+ unsigned char *ptr;
+ int sealalg;
+ int signalg;
+ krb5_checksum cksum;
+ krb5_checksum md5cksum;
+ size_t cksum_len = 0;
+ size_t conflen = 0;
+ int direction;
+ krb5_ui_4 seqnum;
+ OM_uint32 retval;
+ size_t sumlen;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ md5cksum.length = cksum.length = 0;
+ md5cksum.contents = cksum.contents = NULL;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL && trailer->buffer.length != 0) {
+ *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (ctx->seq == NULL) {
+ /* ctx was established using a newer enctype, and cannot process RFC
+ * 1964 tokens. */
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (header->buffer.length < token_wrapper_len + 22) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ ptr = (unsigned char *)header->buffer.value + token_wrapper_len;
+
+ signalg = ptr[0];
+ signalg |= ptr[1] << 8;
+
+ sealalg = ptr[2];
+ sealalg |= ptr[3] << 8;
+
+ if (ptr[4] != 0xFF || ptr[5] != 0xFF) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (toktype != KG_TOK_WRAP_MSG && sealalg != 0xFFFF) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (toktype == KG_TOK_WRAP_MSG &&
+ !(sealalg == 0xFFFF || sealalg == ctx->sealalg)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+ (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+ (ctx->sealalg == SEAL_ALG_DES3KD &&
+ signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
+ (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
+ signalg != SGN_ALG_HMAC_MD5)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_HMAC_MD5:
+ cksum_len = 8;
+ if (toktype != KG_TOK_WRAP_MSG)
+ sign_usage = 15;
+ break;
+ case SGN_ALG_3:
+ cksum_len = 16;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ cksum_len = 20;
+ break;
+ default:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* get the token parameters */
+ code = kg_get_seq_num(context, ctx->seq, ptr + 14, ptr + 6, &direction,
+ &seqnum);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* decode the message, if SEAL */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (sealalg != 0xFFFF) {
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ size_t i;
+
+ store_32_be(seqnum, bigend_seqnum);
+
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ assert(enc_key->length == 16);
+
+ for (i = 0; i < enc_key->length; i++)
+ ((char *)enc_key->contents)[i] ^= 0xF0;
+
+ code = kg_arcfour_docrypt_iov(context, enc_key, 0,
+ &bigend_seqnum[0], 4,
+ iov, iov_count);
+ krb5_free_keyblock(context, enc_key);
+ } else {
+ code = kg_decrypt_iov(context, 0,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ 0 /*EC*/, 0 /*RRC*/,
+ ctx->enc, KG_USAGE_SEAL, NULL,
+ iov, iov_count);
+ }
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+ conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+ }
+
+ if (header->buffer.length != token_wrapper_len + 14 + cksum_len + conflen) {
+ retval = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ /* compute the checksum of the message */
+
+ /* initialize the checksum */
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_DES_MAC:
+ case SGN_ALG_3:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ default:
+ abort();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ md5cksum.length = sumlen;
+
+ /* compute the checksum of the message */
+ code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
+ cksum_len, ctx->seq, ctx->enc,
+ sign_usage, iov, iov_count, toktype,
+ &md5cksum);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ cksum.length = cksum_len;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ case SGN_ALG_HMAC_MD5:
+ code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
+ break;
+ default:
+ code = 0;
+ retval = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ break;
+ }
+
+ if (code != 0) {
+ code = 0;
+ retval = GSS_S_BAD_SIG;
+ goto cleanup;
+ }
+
+ /*
+ * For GSS_C_DCE_STYLE, the caller manages the padding, because the
+ * pad length is in the RPC PDU. The value of the padding may be
+ * uninitialized. For normal GSS, the last bytes of the decrypted
+ * data contain the pad length. kg_fixup_padding_iov() will find
+ * this and fixup the last data IOV appropriately.
+ */
+ if (toktype == KG_TOK_WRAP_MSG &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+ retval = kg_fixup_padding_iov(&code, iov, iov_count);
+ if (retval != GSS_S_COMPLETE)
+ goto cleanup;
+ }
+
+ if (conf_state != NULL)
+ *conf_state = (sealalg != 0xFFFF);
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ if ((ctx->initiate && direction != 0xff) ||
+ (!ctx->initiate && direction != 0)) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ retval = GSS_S_BAD_SIG;
+ }
+
+ code = 0;
+ retval = g_seqstate_check(ctx->seqstate, (uint64_t)seqnum);
+
+cleanup:
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ *minor_status = code;
+
+ return retval;
+}
+
+/*
+ * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
+ * for DCE in which case it can just provide TOKEN | DATA (must
+ * guarantee that DATA is padded)
+ */
+static OM_uint32
+kg_unseal_iov_token(OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code;
+ krb5_context context = ctx->k5_context;
+ unsigned char *ptr;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ size_t input_length;
+ unsigned int bodysize;
+ int toktype2;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ ptr = (unsigned char *)header->buffer.value;
+ input_length = header->buffer.length;
+
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+ toktype == KG_TOK_WRAP_MSG) {
+ size_t data_length, assoc_data_length;
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ input_length += data_length - assoc_data_length;
+
+ if (padding != NULL)
+ input_length += padding->buffer.length;
+
+ if (trailer != NULL)
+ input_length += trailer->buffer.length;
+ }
+
+ code = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ input_length, 0);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX:
+ code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count,
+ conf_state, qop_state, toktype);
+ break;
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ code = kg_unseal_v1_iov(context, minor_status, ctx, iov, iov_count,
+ (size_t)(ptr - (unsigned char *)header->buffer.value),
+ conf_state, qop_state, toktype);
+ break;
+ default:
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ code = GSS_S_DEFECTIVE_TOKEN;
+ break;
+ }
+
+ if (code != 0)
+ save_error_info(*minor_status, context);
+
+ return code;
+}
+
+/*
+ * Split a STREAM | SIGN_DATA | DATA into
+ * HEADER | SIGN_DATA | DATA | PADDING | TRAILER
+ */
+static OM_uint32
+kg_unseal_stream_iov(OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ unsigned char *ptr;
+ unsigned int bodysize;
+ OM_uint32 code = 0, major_status = GSS_S_FAILURE;
+ krb5_context context = ctx->k5_context;
+ int conf_req_flag, toktype2;
+ int i = 0, j;
+ gss_iov_buffer_desc *tiov = NULL;
+ gss_iov_buffer_t stream, data = NULL;
+ gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+
+ assert(toktype == KG_TOK_WRAP_MSG);
+
+ if (toktype != KG_TOK_WRAP_MSG || (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ stream = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
+ assert(stream != NULL);
+
+ ptr = (unsigned char *)stream->buffer.value;
+
+ code = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ stream->buffer.length, 0);
+ if (code != 0) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ tiov = (gss_iov_buffer_desc *)calloc((size_t)iov_count + 2, sizeof(gss_iov_buffer_desc));
+ if (tiov == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /* HEADER */
+ theader = &tiov[i++];
+ theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
+ theader->buffer.value = stream->buffer.value;
+ theader->buffer.length = ptr - (unsigned char *)stream->buffer.value;
+ if (bodysize < 14 ||
+ stream->buffer.length != theader->buffer.length + bodysize) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ theader->buffer.length += 14;
+
+ /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
+ for (j = 0; j < iov_count; j++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA) {
+ if (data != NULL) {
+ /* only a single DATA buffer can appear */
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ data = &iov[j];
+ tdata = &tiov[i];
+ }
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ tiov[i++] = iov[j];
+ }
+
+ if (data == NULL) {
+ /* a single DATA buffer must be present */
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ /* PADDING | TRAILER */
+ tpadding = &tiov[i++];
+ tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
+ tpadding->buffer.length = 0;
+ tpadding->buffer.value = NULL;
+
+ ttrailer = &tiov[i++];
+ ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX: {
+ size_t ec, rrc;
+ krb5_enctype enctype;
+ unsigned int k5_headerlen = 0;
+ unsigned int k5_trailerlen = 0;
+
+ if (ctx->have_acceptor_subkey)
+ enctype = ctx->acceptor_subkey->keyblock.enctype;
+ else
+ enctype = ctx->subkey->keyblock.enctype;
+ conf_req_flag = ((ptr[0] & FLAG_WRAP_CONFIDENTIAL) != 0);
+ ec = conf_req_flag ? load_16_be(ptr + 2) : 0;
+ rrc = load_16_be(ptr + 4);
+
+ if (rrc != 0) {
+ if (!gss_krb5int_rotate_left((unsigned char *)stream->buffer.value + 16,
+ stream->buffer.length - 16, rrc)) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ store_16_be(0, ptr + 4); /* set RRC to zero */
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0)
+ goto cleanup;
+ theader->buffer.length += k5_headerlen; /* length validated later */
+ }
+
+ /* no PADDING for CFX, EC is used instead */
+ code = krb5_c_crypto_length(context, enctype,
+ conf_req_flag ? KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + k5_trailerlen;
+ ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
+ stream->buffer.length - ttrailer->buffer.length;
+ break;
+ }
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ theader->buffer.length += ctx->cksum_size +
+ kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ /*
+ * we can't set the padding accurately until decryption;
+ * kg_fixup_padding_iov() will take care of this
+ */
+ tpadding->buffer.length = 1;
+ tpadding->buffer.value = (unsigned char *)stream->buffer.value + stream->buffer.length - 1;
+
+ /* no TRAILER for pre-CFX */
+ ttrailer->buffer.length = 0;
+ ttrailer->buffer.value = NULL;
+
+ break;
+ default:
+ code = (OM_uint32)G_BAD_TOK_HEADER;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ break;
+ }
+
+ /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
+ /* Old: GSS-Header | Conf | Data | Pad | */
+ /* CFX: GSS-Header | Kerb-Header | Data | | EC | E(Header) | Kerb-Trailer */
+ /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
+
+ /* validate lengths */
+ if (stream->buffer.length < theader->buffer.length +
+ tpadding->buffer.length +
+ ttrailer->buffer.length)
+ {
+ code = (OM_uint32)KRB5_BAD_MSIZE;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ /* setup data */
+ tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
+ tpadding->buffer.length - theader->buffer.length;
+
+ assert(data != NULL);
+
+ if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(tdata, tdata->buffer.length);
+ if (code != 0)
+ goto cleanup;
+ memcpy(tdata->buffer.value,
+ (unsigned char *)stream->buffer.value + theader->buffer.length, tdata->buffer.length);
+ } else
+ tdata->buffer.value = (unsigned char *)stream->buffer.value + theader->buffer.length;
+
+ assert(i <= iov_count + 2);
+
+ major_status = kg_unseal_iov_token(&code, ctx, conf_state, qop_state,
+ tiov, i, toktype);
+ if (major_status == GSS_S_COMPLETE)
+ *data = *tdata;
+ else
+ kg_release_iov(tdata, 1);
+
+cleanup:
+ if (tiov != NULL)
+ free(tiov);
+
+ *minor_status = code;
+
+ return major_status;
+}
+
+OM_uint32
+kg_unseal_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 code;
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
+ code = kg_unseal_stream_iov(minor_status, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ } else {
+ code = kg_unseal_iov_token(minor_status, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ }
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_unwrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_unseal_iov(minor_status, context_handle,
+ conf_state, qop_state,
+ iov, iov_count, KG_TOK_WRAP_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_verify_mic_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_unseal_iov(minor_status, context_handle,
+ NULL, qop_state,
+ iov, iov_count, KG_TOK_MIC_MSG);
+
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
new file mode 100644
index 000000000000..b35a2152344e
--- /dev/null
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -0,0 +1,445 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH,
+ GSS_KRB5_GET_TKT_FLAGS_OID };
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ticket_flags == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(*ticket_flags)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *ticket_flags = *((krb5_flags *)data_set->elements[0].value);
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_COPY_CCACHE_OID_LENGTH,
+ GSS_KRB5_COPY_CCACHE_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ if (out_ccache == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ req_buffer.value = out_ccache;
+ req_buffer.length = sizeof(out_ccache);
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred_handle,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_import_cred(OM_uint32 *minor_status,
+ krb5_ccache id,
+ krb5_principal keytab_principal,
+ krb5_keytab keytab,
+ gss_cred_id_t *cred)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_IMPORT_CRED_OID_LENGTH,
+ GSS_KRB5_IMPORT_CRED_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_import_cred_req req;
+ gss_buffer_desc req_buffer;
+
+ if (cred == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *cred = GSS_C_NO_CREDENTIAL;
+
+ req.id = id;
+ req.keytab_principal = keytab_principal;
+ req.keytab = keytab;
+
+ req_buffer.value = &req;
+ req_buffer.length = sizeof(req);
+
+ major_status = gss_set_cred_option(minor_status,
+ cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx)
+{
+ unsigned char oid_buf[GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH + 6];
+ gss_OID_desc req_oid;
+ OM_uint32 major_status, minor;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (kctx == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *kctx = NULL;
+
+ req_oid.elements = oid_buf;
+ req_oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
+ (int)version,
+ &req_oid);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ *context_handle,
+ &req_oid,
+ &data_set);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(void *)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *kctx = *((void **)data_set->elements[0].value);
+
+ /* Clean up the context state (it is an error for
+ * someone to attempt to use this context again)
+ */
+ (void)gss_delete_sec_context(minor_status, context_handle, NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ generic_gss_release_buffer_set(&minor, &data_set);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH,
+ GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_set_allowable_enctypes_req req;
+ gss_buffer_desc req_buffer;
+
+ req.num_ktypes = num_ktypes;
+ req.ktypes = ktypes;
+
+ req_buffer.length = sizeof(req);
+ req_buffer.value = &req;
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_ccache_name(OM_uint32 *minor_status,
+ const char *name,
+ const char **out_name)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_CCACHE_NAME_OID_LENGTH,
+ GSS_KRB5_CCACHE_NAME_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_ccache_name_req req;
+ gss_buffer_desc req_buffer;
+
+ req.name = name;
+ req.out_name = out_name;
+
+ req_buffer.length = sizeof(req);
+ req_buffer.value = &req;
+
+ major_status = gssspi_mech_invoke(minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *kctx)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = sizeof(kctx);
+ req_buffer.value = kctx;
+
+ major_status = gssspi_mech_invoke(minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_register_acceptor_identity(const char *keytab)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH,
+ GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID };
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = (keytab == NULL) ? 0 : strlen(keytab);
+ req_buffer.value = (char *)keytab;
+
+ major_status = gssspi_mech_invoke(&minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+#ifndef _WIN32
+krb5_error_code
+krb5_gss_use_kdc_context(void)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_USE_KDC_CONTEXT_OID };
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ gss_buffer_desc req_buffer;
+ krb5_error_code ret;
+
+ req_buffer.length = 0;
+ req_buffer.value = NULL;
+
+ major_status = gssspi_mech_invoke(&minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ if (major_status != GSS_S_COMPLETE) {
+ if (minor_status != 0)
+ ret = (krb5_error_code)minor_status;
+ else
+ ret = KRB5KRB_ERR_GENERIC;
+ } else
+ ret = 0;
+
+ return ret;
+}
+#endif
+
+/*
+ * This API should go away and be replaced with an accessor
+ * into a gss_name_t.
+ */
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int ad_type,
+ gss_buffer_t ad_data)
+{
+ gss_OID_desc req_oid;
+ unsigned char oid_buf[GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH + 6];
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ad_data == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ req_oid.elements = oid_buf;
+ req_oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ ad_type,
+ &req_oid);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE) {
+ return major_status;
+ }
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1) {
+ return GSS_S_FAILURE;
+ }
+
+ ad_data->length = data_set->elements[0].length;
+ ad_data->value = data_set->elements[0].value;
+
+ data_set->elements[0].length = 0;
+ data_set->elements[0].value = NULL;
+
+ data_set->count = 0;
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ krb5_rcache rcache)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH,
+ GSS_KRB5_SET_CRED_RCACHE_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = sizeof(rcache);
+ req_buffer.value = rcache;
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_timestamp *authtime)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID };
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (authtime == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(*authtime)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *authtime = *((krb5_timestamp *)data_set->elements[0].value);
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/lucid_context.c b/src/lib/gssapi/krb5/lucid_context.c
new file mode 100644
index 000000000000..a894f0e7355c
--- /dev/null
+++ b/src/lib/gssapi/krb5/lucid_context.c
@@ -0,0 +1,292 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/lucid_context.c */
+/*
+ * Copyright 2004, 2008 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.
+ */
+
+/* Externalize a "lucid" security context from a krb5_gss_ctx_id_rec
+ * structure. */
+#include "gssapiP_krb5.h"
+#include "gssapi_krb5.h"
+
+/*
+ * Local routine prototypes
+ */
+static void
+free_external_lucid_ctx_v1(
+ gss_krb5_lucid_context_v1_t *ctx);
+
+static void
+free_lucid_key_data(
+ gss_krb5_lucid_key_t *key);
+
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+ krb5_keyblock *k5key,
+ gss_krb5_lucid_key_t *lkey);
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+ krb5_gss_ctx_id_rec * gctx,
+ int version,
+ void **out_ptr);
+
+
+/*
+ * Exported routines
+ */
+
+OM_uint32
+gss_krb5int_export_lucid_sec_context(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_error_code kret = 0;
+ OM_uint32 retval;
+ krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
+ void *lctx = NULL;
+ int version = 0;
+ gss_buffer_desc rep;
+
+ /* Assume failure */
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ retval = generic_gss_oid_decompose(minor_status,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
+ desired_object,
+ &version);
+ if (GSS_ERROR(retval))
+ return retval;
+
+ /* Externalize a structure of the right version */
+ switch (version) {
+ case 1:
+ kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
+ version, &lctx);
+ break;
+ default:
+ kret = (OM_uint32) KG_LUCID_VERSION;
+ break;
+ }
+
+ if (kret)
+ goto error_out;
+
+ rep.value = &lctx;
+ rep.length = sizeof(lctx);
+
+ retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+ if (GSS_ERROR(retval))
+ goto error_out;
+
+error_out:
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+
+/*
+ * Frees the storage associated with an
+ * exported lucid context structure.
+ */
+OM_uint32
+gss_krb5int_free_lucid_sec_context(
+ OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ OM_uint32 retval;
+ krb5_error_code kret = 0;
+ int version;
+ void *kctx;
+
+ /* Assume failure */
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+
+ kctx = value->value;
+ if (!kctx) {
+ kret = EINVAL;
+ goto error_out;
+ }
+
+ /* Determine version and call correct free routine */
+ version = ((gss_krb5_lucid_context_version_t *)kctx)->version;
+ switch (version) {
+ case 1:
+ free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
+ break;
+ default:
+ kret = EINVAL;
+ break;
+ }
+
+ if (kret)
+ goto error_out;
+
+ /* Success! */
+ *minor_status = 0;
+ retval = GSS_S_COMPLETE;
+
+ return (retval);
+
+error_out:
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+
+/*
+ * Local routines
+ */
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+ krb5_gss_ctx_id_rec * gctx,
+ int version,
+ void **out_ptr)
+{
+ gss_krb5_lucid_context_v1_t *lctx = NULL;
+ unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t);
+ krb5_error_code retval;
+
+ /* Allocate the structure */
+ if ((lctx = xmalloc(bufsize)) == NULL) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+
+ memset(lctx, 0, bufsize);
+
+ lctx->version = 1;
+ lctx->initiate = gctx->initiate ? 1 : 0;
+ lctx->endtime = gctx->krb_times.endtime;
+ lctx->send_seq = gctx->seq_send;
+ lctx->recv_seq = gctx->seq_recv;
+ lctx->protocol = gctx->proto;
+ /* gctx->proto == 0 ==> rfc1964-style key information
+ gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */
+ if (gctx->proto == 0) {
+ lctx->rfc1964_kd.sign_alg = gctx->signalg;
+ lctx->rfc1964_kd.seal_alg = gctx->sealalg;
+ /* Copy key */
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->seq->keyblock,
+ &lctx->rfc1964_kd.ctx_key)))
+ goto error_out;
+ }
+ else if (gctx->proto == 1) {
+ /* Copy keys */
+ /* (subkey is always present, either a copy of the kerberos
+ session key or a subkey) */
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->subkey->keyblock,
+ &lctx->cfx_kd.ctx_key)))
+ goto error_out;
+ if (gctx->have_acceptor_subkey) {
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->acceptor_subkey->keyblock,
+ &lctx->cfx_kd.acceptor_subkey)))
+ goto error_out;
+ lctx->cfx_kd.have_acceptor_subkey = 1;
+ }
+ }
+ else {
+ xfree(lctx);
+ return EINVAL; /* XXX better error code? */
+ }
+
+ /* Success! */
+ *out_ptr = lctx;
+ return 0;
+
+error_out:
+ if (lctx) {
+ free_external_lucid_ctx_v1(lctx);
+ }
+ return retval;
+
+}
+
+/* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+ krb5_keyblock *k5key,
+ gss_krb5_lucid_key_t *lkey)
+{
+ if (!k5key || !k5key->contents || k5key->length == 0)
+ return EINVAL;
+
+ memset(lkey, 0, sizeof(gss_krb5_lucid_key_t));
+
+ /* Allocate storage for the key data */
+ if ((lkey->data = xmalloc(k5key->length)) == NULL) {
+ return ENOMEM;
+ }
+ memcpy(lkey->data, k5key->contents, k5key->length);
+ lkey->length = k5key->length;
+ lkey->type = k5key->enctype;
+
+ return 0;
+}
+
+
+/* Free any storage associated with a gss_krb5_lucid_key_t structure */
+static void
+free_lucid_key_data(
+ gss_krb5_lucid_key_t *key)
+{
+ if (key) {
+ if (key->data && key->length) {
+ zap(key->data, key->length);
+ xfree(key->data);
+ zap(key, sizeof(gss_krb5_lucid_key_t));
+ }
+ }
+}
+/* Free any storage associated with a gss_krb5_lucid_context_v1 structure */
+static void
+free_external_lucid_ctx_v1(
+ gss_krb5_lucid_context_v1_t *ctx)
+{
+ if (ctx) {
+ if (ctx->protocol == 0) {
+ free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
+ }
+ if (ctx->protocol == 1) {
+ free_lucid_key_data(&ctx->cfx_kd.ctx_key);
+ if (ctx->cfx_kd.have_acceptor_subkey)
+ free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
+ }
+ xfree(ctx);
+ ctx = NULL;
+ }
+}
diff --git a/src/lib/gssapi/krb5/naming_exts.c b/src/lib/gssapi/krb5/naming_exts.c
new file mode 100644
index 000000000000..6062a6dd8052
--- /dev/null
+++ b/src/lib/gssapi/krb5/naming_exts.c
@@ -0,0 +1,684 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/naming_exts.c */
+/*
+ * Copyright 2009 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+krb5_error_code
+kg_init_name(krb5_context context, krb5_principal principal,
+ char *service, char *host, krb5_authdata_context ad_context,
+ krb5_flags flags, krb5_gss_name_t *ret_name)
+{
+ krb5_error_code code;
+ krb5_gss_name_t name;
+
+ *ret_name = NULL;
+
+ assert(principal != NULL);
+
+ if (principal == NULL)
+ return EINVAL;
+
+ name = xmalloc(sizeof(krb5_gss_name_rec));
+ if (name == NULL)
+ return ENOMEM;
+
+ memset(name, 0, sizeof(krb5_gss_name_rec));
+
+ code = k5_mutex_init(&name->lock);
+ if (code != 0)
+ goto cleanup;
+
+ if ((flags & KG_INIT_NAME_NO_COPY) == 0) {
+ code = krb5_copy_principal(context, principal, &name->princ);
+ if (code != 0)
+ goto cleanup;
+
+ if (ad_context != NULL) {
+ code = krb5_authdata_context_copy(context,
+ ad_context,
+ &name->ad_context);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = ENOMEM;
+ if (service != NULL) {
+ name->service = strdup(service);
+ if (name->service == NULL)
+ goto cleanup;
+ }
+ if (host != NULL) {
+ name->host = strdup(host);
+ if (name->host == NULL)
+ goto cleanup;
+ }
+ code = 0;
+ } else {
+ name->princ = principal;
+ name->service = service;
+ name->host = host;
+ name->ad_context = ad_context;
+ }
+
+ *ret_name = name;
+
+cleanup:
+ if (code != 0)
+ kg_release_name(context, &name);
+
+ return code;
+}
+
+krb5_error_code
+kg_release_name(krb5_context context,
+ krb5_gss_name_t *name)
+{
+ if (*name != NULL) {
+ krb5_free_principal(context, (*name)->princ);
+ free((*name)->service);
+ free((*name)->host);
+ krb5_authdata_context_free(context, (*name)->ad_context);
+ k5_mutex_destroy(&(*name)->lock);
+ free(*name);
+ *name = NULL;
+ }
+
+ return 0;
+}
+
+krb5_error_code
+kg_duplicate_name(krb5_context context,
+ const krb5_gss_name_t src,
+ krb5_gss_name_t *dst)
+{
+ krb5_error_code code;
+
+ k5_mutex_lock(&src->lock);
+ code = kg_init_name(context, src->princ, src->service, src->host,
+ src->ad_context, 0, dst);
+ k5_mutex_unlock(&src->lock);
+ return code;
+}
+
+
+krb5_boolean
+kg_compare_name(krb5_context context,
+ krb5_gss_name_t name1,
+ krb5_gss_name_t name2)
+{
+ return krb5_principal_compare(context, name1->princ, name2->princ);
+}
+
+/* Determine the principal to use for an acceptor name, which is different from
+ * name->princ for host-based names. */
+krb5_boolean
+kg_acceptor_princ(krb5_context context, krb5_gss_name_t name,
+ krb5_principal *princ_out)
+{
+ krb5_error_code code;
+ const char *host;
+ char *tmp = NULL;
+
+ *princ_out = NULL;
+ if (name == NULL)
+ return 0;
+
+ /* If it's not a host-based name, just copy name->princ. */
+ if (name->service == NULL)
+ return krb5_copy_principal(context, name->princ, princ_out);
+
+ if (name->host != NULL && name->princ->length == 2) {
+ /* If a host was given, we have to use the canonicalized form of it (as
+ * given by krb5_sname_to_principal) for backward compatibility. */
+ const krb5_data *d = &name->princ->data[1];
+ tmp = k5memdup0(d->data, d->length, &code);
+ if (tmp == NULL)
+ return ENOMEM;
+ host = tmp;
+ } else /* No host was given; use an empty string. */
+ host = "";
+
+ code = krb5_build_principal(context, princ_out, 0, "", name->service, host,
+ (char *)NULL);
+ if (*princ_out != NULL)
+ (*princ_out)->type = KRB5_NT_SRV_HST;
+ free(tmp);
+ return code;
+}
+
+static OM_uint32
+kg_map_name_error(OM_uint32 *minor_status, krb5_error_code code)
+{
+ OM_uint32 major_status;
+
+ switch (code) {
+ case 0:
+ major_status = GSS_S_COMPLETE;
+ break;
+ case ENOENT:
+ case EPERM:
+ major_status = GSS_S_UNAVAILABLE;
+ break;
+ default:
+ major_status = GSS_S_FAILURE;
+ break;
+ }
+
+ *minor_status = code;
+
+ return major_status;
+}
+
+/* Owns data on success */
+static krb5_error_code
+data_list_to_buffer_set(krb5_context context,
+ krb5_data *data,
+ gss_buffer_set_t *buffer_set)
+{
+ gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
+ OM_uint32 minor_status;
+ int i;
+ krb5_error_code code = 0;
+
+ if (data == NULL)
+ goto cleanup;
+
+ if (buffer_set == NULL)
+ goto cleanup;
+
+ if (GSS_ERROR(gss_create_empty_buffer_set(&minor_status,
+ &set))) {
+ assert(minor_status != 0);
+ code = minor_status;
+ goto cleanup;
+ }
+
+ for (i = 0; data[i].data != NULL; i++)
+ ;
+
+ set->count = i;
+ set->elements = gssalloc_calloc(i, sizeof(gss_buffer_desc));
+ if (set->elements == NULL) {
+ gss_release_buffer_set(&minor_status, &set);
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /*
+ * Copy last element first so data remains properly
+ * NULL-terminated in case of allocation failure
+ * in data_to_gss() on windows.
+ */
+ for (i = set->count-1; i >= 0; i--) {
+ if (data_to_gss(&data[i], &set->elements[i])) {
+ gss_release_buffer_set(&minor_status, &set);
+ code = ENOMEM;
+ goto cleanup;
+ }
+ }
+cleanup:
+ krb5int_free_data_list(context, data);
+
+ if (buffer_set != NULL)
+ *buffer_set = set;
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data *kattrs = NULL;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (attrs != NULL)
+ *attrs = GSS_C_NO_BUFFER_SET;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_authdata_get_attribute_types(context,
+ kname->ad_context,
+ &kattrs);
+ if (code != 0)
+ goto cleanup;
+
+ code = data_list_to_buffer_set(context, kattrs, attrs);
+ kattrs = NULL;
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ k5_mutex_unlock(&kname->lock);
+ krb5int_free_data_list(context, kattrs);
+
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+ krb5_boolean kauthenticated;
+ krb5_boolean kcomplete;
+ krb5_data kvalue;
+ krb5_data kdisplay_value;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ kauthenticated = FALSE;
+ kcomplete = FALSE;
+
+ code = krb5_authdata_get_attribute(context,
+ kname->ad_context,
+ &kattr,
+ &kauthenticated,
+ &kcomplete,
+ value ? &kvalue : NULL,
+ display_value ? &kdisplay_value : NULL,
+ more);
+ if (code == 0) {
+ if (value != NULL)
+ code = data_to_gss(&kvalue, value);
+
+ if (authenticated != NULL)
+ *authenticated = kauthenticated;
+ if (complete != NULL)
+ *complete = kcomplete;
+
+ if (display_value != NULL) {
+ if (code == 0)
+ code = data_to_gss(&kdisplay_value, display_value);
+ else
+ free(kdisplay_value.data);
+ }
+ }
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+ krb5_data kvalue;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ kvalue.data = (char *)value->value;
+ kvalue.length = value->length;
+
+ code = krb5_authdata_set_attribute(context,
+ kname->ad_context,
+ complete,
+ &kattr,
+ &kvalue);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ code = krb5_authdata_delete_attribute(context,
+ kname->ad_context,
+ &kattr);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *kmodule;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kmodule = (char *)type_id->value;
+ if (kmodule[type_id->length] != '\0') {
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+
+ code = krb5_authdata_export_internal(context,
+ kname->ad_context,
+ authenticated,
+ kmodule,
+ (void **)output);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *kmodule;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kmodule = (char *)type_id->value;
+ if (kmodule[type_id->length] != '\0') {
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+
+ code = krb5_authdata_free_internal(context,
+ kname->ad_context,
+ kmodule,
+ *input);
+ if (code == 0)
+ *input = NULL;
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data *attrs = NULL;
+ char *princstr = NULL;
+ unsigned char *cp;
+ size_t princlen;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ code = krb5_unparse_name(context, kname->princ, &princstr);
+ if (code != 0)
+ goto cleanup;
+
+ princlen = strlen(princstr);
+
+ if (kname->ad_context != NULL) {
+ code = krb5_authdata_export_attributes(context,
+ kname->ad_context,
+ AD_USAGE_MASK,
+ &attrs);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* 04 02 OID Name AuthData */
+
+ exp_composite_name->length = 10 + gss_mech_krb5->length + princlen;
+ exp_composite_name->length += 4; /* length of encoded attributes */
+ if (attrs != NULL)
+ exp_composite_name->length += attrs->length;
+ exp_composite_name->value = malloc(exp_composite_name->length);
+ if (exp_composite_name->value == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ cp = exp_composite_name->value;
+
+ /* Note: we assume the OID will be less than 128 bytes... */
+ *cp++ = 0x04;
+ *cp++ = 0x02;
+
+ store_16_be(gss_mech_krb5->length + 2, cp);
+ cp += 2;
+ *cp++ = 0x06;
+ *cp++ = (gss_mech_krb5->length) & 0xFF;
+ memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
+ cp += gss_mech_krb5->length;
+
+ store_32_be(princlen, cp);
+ cp += 4;
+ memcpy(cp, princstr, princlen);
+ cp += princlen;
+
+ store_32_be(attrs != NULL ? attrs->length : 0, cp);
+ cp += 4;
+
+ if (attrs != NULL) {
+ memcpy(cp, attrs->data, attrs->length);
+ cp += attrs->length;
+ }
+
+cleanup:
+ krb5_free_unparsed_name(context, princstr);
+ krb5_free_data(context, attrs);
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+#if 0
+OM_uint32
+krb5_gss_display_name_ext(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name)
+{
+}
+#endif
diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c
new file mode 100644
index 000000000000..e897074fc193
--- /dev/null
+++ b/src/lib/gssapi/krb5/prf.c
@@ -0,0 +1,139 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/prf.c */
+/*
+ * Copyright 2009 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+#ifndef MIN /* Usually found in <sys/param.h>. */
+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out)
+{
+ krb5_error_code code;
+ krb5_key key = NULL;
+ krb5_gss_ctx_id_t ctx;
+ int i;
+ OM_uint32 minor;
+ size_t prflen;
+ krb5_data t, ns;
+ unsigned char *p;
+
+ prf_out->length = 0;
+ prf_out->value = NULL;
+
+ t.length = 0;
+ t.data = NULL;
+
+ ns.length = 0;
+ ns.data = NULL;
+
+ ctx = (krb5_gss_ctx_id_t)context;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ switch (prf_key) {
+ case GSS_C_PRF_KEY_FULL:
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ break;
+ }
+ /* fallthrough */
+ case GSS_C_PRF_KEY_PARTIAL:
+ key = ctx->subkey;
+ break;
+ default:
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if (key == NULL) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if (desired_output_len == 0)
+ return GSS_S_COMPLETE;
+
+ prf_out->value = k5alloc(desired_output_len, &code);
+ if (prf_out->value == NULL) {
+ code = KG_INPUT_TOO_LONG;
+ goto cleanup;
+ }
+ prf_out->length = desired_output_len;
+
+ code = krb5_c_prf_length(ctx->k5_context,
+ krb5_k_key_enctype(ctx->k5_context, key),
+ &prflen);
+ if (code != 0)
+ goto cleanup;
+
+ ns.length = 4 + prf_in->length;
+ ns.data = k5alloc(ns.length, &code);
+ if (ns.data == NULL) {
+ code = KG_INPUT_TOO_LONG;
+ goto cleanup;
+ }
+
+ t.length = prflen;
+ t.data = k5alloc(t.length, &code);
+ if (t.data == NULL)
+ goto cleanup;
+
+ memcpy(ns.data + 4, prf_in->value, prf_in->length);
+ i = 0;
+ p = (unsigned char *)prf_out->value;
+ while (desired_output_len > 0) {
+ store_32_be(i, ns.data);
+
+ code = krb5_k_prf(ctx->k5_context, key, &ns, &t);
+ if (code != 0)
+ goto cleanup;
+
+ memcpy(p, t.data, MIN(t.length, desired_output_len));
+
+ p += t.length;
+ desired_output_len -= t.length;
+ i++;
+ }
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&minor, prf_out);
+ krb5_free_data_contents(ctx->k5_context, &ns);
+ krb5_free_data_contents(ctx->k5_context, &t);
+
+ *minor_status = (OM_uint32)code;
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c
new file mode 100644
index 000000000000..a672f48c859b
--- /dev/null
+++ b/src/lib/gssapi/krb5/process_context_token.c
@@ -0,0 +1,66 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_process_context_token(minor_status, context_handle,
+ token_buffer)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t token_buffer;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 majerr;
+
+ ctx = (krb5_gss_ctx_id_t) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ /* We only support context deletion tokens for now, and RFC 4121 does not
+ * define a context deletion token. */
+ if (ctx->proto) {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ /* "unseal" the token */
+
+ if (GSS_ERROR(majerr = kg_unseal(minor_status, context_handle,
+ token_buffer,
+ GSS_C_NO_BUFFER, NULL, NULL,
+ KG_TOK_DEL_CTX)))
+ return(majerr);
+
+ /* Mark the context as terminated, but do not delete it (as that would
+ * leave the caller with a dangling context handle). */
+ ctx->terminated = 1;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
new file mode 100644
index 000000000000..8db745086009
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_cred.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t *cred_handle;
+{
+ krb5_context context;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code1, code2, code3;
+
+ code1 = krb5_gss_init_context(&context);
+ if (code1) {
+ *minor_status = code1;
+ return GSS_S_FAILURE;
+ }
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = 0;
+ krb5_free_context(context);
+ return(GSS_S_COMPLETE);
+ }
+
+ cred = (krb5_gss_cred_id_t)*cred_handle;
+
+ k5_mutex_destroy(&cred->lock);
+ /* ignore error destroying mutex */
+
+ if (cred->ccache) {
+ if (cred->destroy_ccache)
+ code1 = krb5_cc_destroy(context, cred->ccache);
+ else
+ code1 = krb5_cc_close(context, cred->ccache);
+ } else
+ code1 = 0;
+
+ if (cred->client_keytab)
+ krb5_kt_close(context, cred->client_keytab);
+
+#ifndef LEAN_CLIENT
+ if (cred->keytab)
+ code2 = krb5_kt_close(context, cred->keytab);
+ else
+#endif /* LEAN_CLIENT */
+ code2 = 0;
+
+ if (cred->rcache)
+ code3 = krb5_rc_close(context, cred->rcache);
+ else
+ code3 = 0;
+ if (cred->name)
+ kg_release_name(context, &cred->name);
+
+ krb5_free_principal(context, cred->impersonator);
+
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+
+ if (cred->password != NULL)
+ zapfree(cred->password, strlen(cred->password));
+
+ xfree(cred);
+
+ *cred_handle = NULL;
+
+ *minor_status = 0;
+ if (code1)
+ *minor_status = code1;
+ if (code2)
+ *minor_status = code2;
+ if (code3)
+ *minor_status = code3;
+
+ if (*minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(*minor_status?GSS_S_FAILURE:GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_name.c b/src/lib/gssapi/krb5/rel_name.c
new file mode 100644
index 000000000000..3dabe32f3342
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_name.c
@@ -0,0 +1,47 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_name(minor_status, input_name)
+ OM_uint32 *minor_status;
+ gss_name_t *input_name;
+{
+ krb5_context context;
+ krb5_error_code code;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kg_release_name(context, (krb5_gss_name_t *)input_name);
+ krb5_free_context(context);
+
+ *input_name = (gss_name_t) NULL;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c
new file mode 100644
index 000000000000..739efe4680b7
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_oid.c
@@ -0,0 +1,78 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/rel_oid.c - Release an OID */
+/*
+ * Copyright 1995, 2007 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_release_oid(minor_status, oid)
+ OM_uint32 *minor_status;
+ gss_OID *oid;
+{
+ /*
+ * The V2 API says the following!
+ *
+ * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+ * and will silently ignore attempts to free these OIDs; for other OIDs
+ * it will call the C free() routine for both the OID data and the
+ * descriptor. This allows applications to freely mix their own heap-
+ * allocated OID values with OIDs returned by GSS-API.
+ */
+ if (krb5_gss_internal_release_oid(minor_status, oid) != GSS_S_COMPLETE) {
+ /* Pawn it off on the generic routine */
+ return(generic_gss_release_oid(minor_status, oid));
+ }
+ else {
+ *oid = GSS_C_NO_OID;
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_internal_release_oid(minor_status, oid)
+ OM_uint32 *minor_status;
+ gss_OID *oid;
+{
+ /*
+ * This function only knows how to release internal OIDs. It will
+ * return GSS_S_CONTINUE_NEEDED for any OIDs it does not recognize.
+ */
+
+ *minor_status = 0;
+ if ((*oid != gss_mech_krb5) &&
+ (*oid != gss_mech_krb5_old) &&
+ (*oid != gss_mech_krb5_wrong) &&
+ (*oid != gss_mech_iakerb) &&
+ (*oid != gss_nt_krb5_name) &&
+ (*oid != gss_nt_krb5_principal)) {
+ /* We don't know about this OID */
+ return(GSS_S_CONTINUE_NEEDED);
+ }
+ else {
+ *oid = GSS_C_NO_OID;
+ return(GSS_S_COMPLETE);
+ }
+}
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
new file mode 100644
index 000000000000..ff1c310bce5e
--- /dev/null
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -0,0 +1,308 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+static int
+kg_is_initiator_cred(krb5_gss_cred_id_t cred)
+{
+ return (cred->usage == GSS_C_INITIATE || cred->usage == GSS_C_BOTH) &&
+ (cred->ccache != NULL);
+}
+
+static OM_uint32
+kg_impersonate_name(OM_uint32 *minor_status,
+ const krb5_gss_cred_id_t impersonator_cred,
+ const krb5_gss_name_t user,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_creds in_creds, *out_creds = NULL;
+
+ *output_cred = NULL;
+ memset(&in_creds, 0, sizeof(in_creds));
+
+ in_creds.client = user->princ;
+ in_creds.server = impersonator_cred->name->princ;
+
+ if (impersonator_cred->req_enctypes != NULL)
+ in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0];
+
+ k5_mutex_lock(&user->lock);
+
+ if (user->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(context,
+ user->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0) {
+ k5_mutex_unlock(&user->lock);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ k5_mutex_unlock(&user->lock);
+
+ code = krb5_get_credentials_for_user(context,
+ KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
+ impersonator_cred->ccache,
+ &in_creds,
+ NULL, &out_creds);
+ if (code != 0) {
+ krb5_free_authdata(context, in_creds.authdata);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ impersonator_cred,
+ out_creds,
+ time_req,
+ output_cred,
+ time_rec,
+ context);
+
+ krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_creds(context, out_creds);
+
+ return major_status;
+}
+
+/* The mechglue always passes null desired_mechs and actual_mechs. */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t imp_cred = (krb5_gss_cred_id_t)impersonator_cred_handle;
+ krb5_gss_cred_id_t cred;
+ krb5_context context;
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_usage != GSS_C_INITIATE) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ if (imp_cred->usage != GSS_C_INITIATE && imp_cred->usage != GSS_C_BOTH) {
+ *minor_status = 0;
+ return GSS_S_NO_CRED;
+ }
+
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_cred_resolve(minor_status, context,
+ impersonator_cred_handle, NULL);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_context(context);
+ return major_status;
+ }
+
+ major_status = kg_impersonate_name(minor_status,
+ imp_cred,
+ (krb5_gss_name_t)desired_name,
+ time_req,
+ &cred,
+ time_rec,
+ context);
+
+ if (!GSS_ERROR(major_status))
+ *output_cred_handle = (gss_cred_id_t)cred;
+
+ k5_mutex_unlock(&imp_cred->lock);
+ krb5_free_context(context);
+
+ return major_status;
+
+}
+
+/*
+ * Set up cred to be an S4U2Proxy credential by copying in the impersonator's
+ * creds, setting a cache config variable with the impersonator principal name,
+ * and saving the impersonator principal name in the cred structure.
+ */
+static krb5_error_code
+make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred,
+ krb5_gss_cred_id_t impersonator_cred)
+{
+ krb5_error_code code;
+ krb5_data data;
+ char *str;
+
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+ cred->ccache);
+ if (code)
+ return code;
+
+ code = krb5_unparse_name(context, impersonator_cred->name->princ, &str);
+ if (code)
+ return code;
+
+ data = string2data(str);
+ code = krb5_cc_set_config(context, cred->ccache, NULL,
+ KRB5_CC_CONF_PROXY_IMPERSONATOR, &data);
+ krb5_free_unparsed_name(context, str);
+ if (code)
+ return code;
+
+ return krb5_copy_principal(context, impersonator_cred->name->princ,
+ &cred->impersonator);
+}
+
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = NULL;
+
+ *output_cred = NULL;
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->name == NULL ||
+ impersonator_cred->impersonator != NULL) {
+ code = G_BAD_USAGE;
+ goto cleanup;
+ }
+
+ assert(impersonator_cred->name->princ != NULL);
+
+ assert(subject_creds != NULL);
+ assert(subject_creds->client != NULL);
+
+ cred = xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
+
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0)
+ goto cleanup;
+
+ cred->usage = GSS_C_INITIATE;
+
+ cred->expire = subject_creds->times.endtime;
+
+ code = kg_init_name(context, subject_creds->client, NULL, NULL, NULL, 0,
+ &cred->name);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code != 0)
+ goto cleanup;
+ cred->destroy_ccache = 1;
+
+ code = krb5_cc_initialize(context, cred->ccache, subject_creds->client);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Only return a "proxy" credential for use with constrained
+ * delegation if the subject credentials are forwardable.
+ * Submitting non-forwardable credentials to the KDC for use
+ * with constrained delegation will only return an error.
+ */
+ if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
+ code = make_proxy_cred(context, cred, impersonator_cred);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto cleanup;
+
+ *time_rec = cred->expire - now;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *minor_status = 0;
+ *output_cred = cred;
+
+cleanup:
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ }
+
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ krb5_cc_destroy(context, cred->ccache);
+ kg_release_name(context, &cred->name);
+ xfree(cred);
+ }
+
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c
new file mode 100644
index 000000000000..79c4c710e6d4
--- /dev/null
+++ b/src/lib/gssapi/krb5/ser_sctx.c
@@ -0,0 +1,798 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/ser_sctx.c - [De]serialization of security context */
+/*
+ * Copyright 1995, 2004, 2008 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/*
+ * This module contains routines to [de]serialize
+ * krb5_gss_enc_desc and krb5_gss_ctx_id_t.
+ * XXX This whole serialization abstraction is unnecessary in a
+ * non-messaging environment, which krb5 is. Someday, this should
+ * all get redone without the extra level of indirection. I've done
+ * some of this work here, since adding new serializers is an internal
+ * krb5 interface, and I won't use those. There is some more
+ * deobfuscation (no longer anonymizing pointers, mostly) which could
+ * still be done. --marc
+ */
+
+static krb5_error_code
+kg_oid_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ gss_OID oid = (gss_OID) arg;
+ krb5_error_code err;
+
+ err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_int32((krb5_int32) oid->length,
+ buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
+ oid->length, buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+ return err;
+}
+
+static krb5_error_code
+kg_oid_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ gss_OID oid;
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+
+ bp = *buffer;
+ remain = *lenremain;
+
+ /* Read in and check our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ return (EINVAL);
+
+ if (ibuf != KV5M_GSS_OID)
+ return (EINVAL);
+
+ oid = (gss_OID) malloc(sizeof(gss_OID_desc));
+ if (oid == NULL)
+ return ENOMEM;
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ free(oid);
+ return EINVAL;
+ }
+ oid->length = ibuf;
+ oid->elements = malloc((size_t)ibuf);
+ if (oid->elements == 0) {
+ free(oid);
+ return ENOMEM;
+ }
+ if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
+ oid->length, &bp, &remain)) {
+ free(oid->elements);
+ free(oid);
+ return EINVAL;
+ }
+
+ /* Read in and check our trailing magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ free(oid->elements);
+ free(oid);
+ return (EINVAL);
+ }
+
+ if (ibuf != KV5M_GSS_OID) {
+ free(oid->elements);
+ free(oid);
+ return (EINVAL);
+ }
+
+ *buffer = bp;
+ *lenremain = remain;
+ *argp = (krb5_pointer) oid;
+ return 0;
+}
+
+static krb5_error_code
+kg_oid_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ gss_OID oid;
+ size_t required;
+
+ kret = EINVAL;
+ if ((oid = (gss_OID) arg)) {
+ required = 2*sizeof(krb5_int32); /* For the header and trailer */
+ required += sizeof(krb5_int32);
+ required += oid->length;
+
+ kret = 0;
+
+ *sizep += required;
+ }
+
+ return(kret);
+}
+
+static krb5_error_code
+kg_seqstate_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ g_seqnum_state arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code err;
+ err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+ if (err == 0)
+ err = g_seqstate_externalize(arg, buffer, lenremain);
+ if (err == 0)
+ err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+ return err;
+}
+
+static krb5_error_code
+kg_seqstate_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ g_seqnum_state *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+ krb5_error_code err;
+
+ bp = *buffer;
+ remain = *lenremain;
+
+ /* Read in and check our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ return (EINVAL);
+
+ if (ibuf != KV5M_GSS_QUEUE)
+ return (EINVAL);
+
+ err = g_seqstate_internalize(argp, &bp, &remain);
+ if (err)
+ return err;
+
+ /* Read in and check our trailing magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ g_seqstate_free(*argp);
+ return (EINVAL);
+ }
+
+ if (ibuf != KV5M_GSS_QUEUE) {
+ g_seqstate_free(*argp);
+ return (EINVAL);
+ }
+
+ *buffer = bp;
+ *lenremain = remain;
+ return 0;
+}
+
+static krb5_error_code
+kg_seqstate_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ g_seqnum_state arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ size_t required;
+
+ kret = EINVAL;
+ if (arg) {
+ required = 2*sizeof(krb5_int32); /* For the header and trailer */
+ g_seqstate_size(arg, &required);
+
+ kret = 0;
+ *sizep += required;
+ }
+ return(kret);
+}
+
+/*
+ * Determine the size required for this krb5_gss_ctx_id_rec.
+ */
+krb5_error_code
+kg_ctx_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ size_t required;
+
+ /*
+ * krb5_gss_ctx_id_rec requires:
+ * krb5_int32 for KG_CONTEXT
+ * krb5_int32 for initiate.
+ * krb5_int32 for established.
+ * krb5_int32 for have_acceptor_subkey.
+ * krb5_int32 for seed_init.
+ * krb5_int32 for gss_flags.
+ * sizeof(seed) for seed
+ * ... for here
+ * ... for there
+ * ... for subkey
+ * krb5_int32 for signalg.
+ * krb5_int32 for cksum_size.
+ * krb5_int32 for sealalg.
+ * ... for enc
+ * ... for seq
+ * krb5_int32 for authtime.
+ * krb5_int32 for starttime.
+ * krb5_int32 for endtime.
+ * krb5_int32 for renew_till.
+ * krb5_int32 for flags.
+ * int64_t for seq_send.
+ * int64_t for seq_recv.
+ * ... for seqstate
+ * ... for auth_context
+ * ... for mech_used
+ * krb5_int32 for proto
+ * krb5_int32 for cksumtype
+ * ... for acceptor_subkey
+ * krb5_int32 for acceptor_key_cksumtype
+ * krb5_int32 for cred_rcache
+ * krb5_int32 for number of elements in authdata array
+ * ... for authdata array
+ * krb5_int32 for trailer.
+ */
+ kret = EINVAL;
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+ required = 21*sizeof(krb5_int32);
+ required += 2*sizeof(int64_t);
+ required += sizeof(ctx->seed);
+
+ kret = 0;
+ if (!kret && ctx->here)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->here->princ,
+ &required);
+
+ if (!kret && ctx->there)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->there->princ,
+ &required);
+
+ if (!kret && ctx->subkey)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->subkey->keyblock,
+ &required);
+
+ if (!kret && ctx->enc)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->enc->keyblock,
+ &required);
+
+ if (!kret && ctx->seq)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->seq->keyblock,
+ &required);
+
+ if (!kret)
+ kret = kg_oid_size(kcontext,
+ (krb5_pointer) ctx->mech_used,
+ &required);
+
+ if (!kret && ctx->seqstate)
+ kret = kg_seqstate_size(kcontext, ctx->seqstate, &required);
+
+ if (!kret)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer) ctx->k5_context,
+ &required);
+ if (!kret)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer) ctx->auth_context,
+ &required);
+ if (!kret && ctx->acceptor_subkey)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->acceptor_subkey->keyblock,
+ &required);
+ if (!kret && ctx->authdata) {
+ krb5_int32 i;
+
+ for (i = 0; !kret && ctx->authdata[i]; i++) {
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTHDATA,
+ (krb5_pointer)ctx->authdata[i],
+ &required);
+ }
+ }
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+
+ if (initiator_name && initiator_name->ad_context) {
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ initiator_name->ad_context,
+ &required);
+ }
+ }
+ *sizep += required;
+ }
+ return(kret);
+}
+
+/*
+ * Externalize this krb5_gss_ctx_id_ret.
+ */
+krb5_error_code
+kg_ctx_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ size_t required;
+ krb5_octet *bp;
+ size_t remain;
+ krb5int_access kaccess;
+
+ kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (kret)
+ return(kret);
+
+ required = 0;
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+ kret = ENOMEM;
+ if (!kg_ctx_size(kcontext, arg, &required) &&
+ (required <= remain)) {
+ /* Our identifier */
+ (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+
+ /* Now static data */
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
+ &bp, &remain);
+ (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
+ sizeof(ctx->seed),
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.authtime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.starttime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.endtime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.renew_till,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
+ &bp, &remain);
+ (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_send,
+ &bp, &remain);
+ (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_recv,
+ &bp, &remain);
+
+ /* Now dynamic data */
+ kret = 0;
+
+ if (!kret && ctx->mech_used)
+ kret = kg_oid_externalize(kcontext, ctx->mech_used,
+ &bp, &remain);
+
+ if (!kret && ctx->here)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->here->princ,
+ &bp, &remain);
+
+ if (!kret && ctx->there)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->there->princ,
+ &bp, &remain);
+
+ if (!kret && ctx->subkey)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->subkey->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->enc)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->enc->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->seq)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->seq->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->seqstate)
+ kret = kg_seqstate_externalize(kcontext,
+ ctx->seqstate, &bp, &remain);
+
+ if (!kret)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer) ctx->k5_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer) ctx->auth_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
+ &bp, &remain);
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
+ &bp, &remain);
+ if (!kret && ctx->acceptor_subkey)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->acceptor_subkey->keyblock,
+ &bp, &remain);
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
+ &bp, &remain);
+ if (!kret) {
+ krb5_int32 i = 0;
+
+ if (ctx->authdata) {
+ for (; ctx->authdata[i]; i++)
+ ;
+ }
+ /* authdata count */
+ kret = krb5_ser_pack_int32(i, &bp, &remain);
+ if (!kret && ctx->authdata) {
+ /* authdata */
+ for (i = 0; !kret && ctx->authdata[i]; i++)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTHDATA,
+ ctx->authdata[i],
+ &bp,
+ &remain);
+ }
+ }
+ /* authdata context */
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+
+ if (initiator_name && initiator_name->ad_context) {
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ initiator_name->ad_context,
+ &bp,
+ &remain);
+ }
+ }
+ /* trailer */
+ if (!kret)
+ kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+ if (!kret) {
+ *buffer = bp;
+ *lenremain = remain;
+ }
+ }
+ }
+ return(kret);
+}
+
+/* Internalize a keyblock and convert it to a key. */
+static krb5_error_code
+intern_key(krb5_context ctx, krb5_key *key, krb5_octet **bp, size_t *sp)
+{
+ krb5_keyblock *keyblock;
+ krb5_error_code ret;
+
+ ret = krb5_internalize_opaque(ctx, KV5M_KEYBLOCK,
+ (krb5_pointer *) &keyblock, bp, sp);
+ if (ret != 0)
+ return ret;
+ ret = krb5_k_create_key(ctx, keyblock, key);
+ krb5_free_keyblock(ctx, keyblock);
+ return ret;
+}
+
+/*
+ * Internalize this krb5_gss_ctx_id_t.
+ */
+krb5_error_code
+kg_ctx_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+ krb5int_access kaccess;
+ krb5_principal princ;
+
+ kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (kret)
+ return(kret);
+
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ princ = NULL;
+ /* Read our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ ibuf = 0;
+ if (ibuf == KG_CONTEXT) {
+ kret = ENOMEM;
+
+ /* Get a context */
+ if ((remain >= (17*sizeof(krb5_int32)
+ + 2*sizeof(int64_t)
+ + sizeof(ctx->seed))) &&
+ (ctx = (krb5_gss_ctx_id_rec *)
+ xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+
+ ctx->magic = ibuf;
+ ctx->k5_context = kcontext;
+
+ /* Get static data */
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->initiate = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->established = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->have_acceptor_subkey = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->seed_init = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->gss_flags = (int) ibuf;
+ (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
+ sizeof(ctx->seed),
+ &bp, &remain);
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->signalg = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cksum_size = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->sealalg = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.authtime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.starttime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.endtime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.renew_till = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_flags = (krb5_flags) ibuf;
+ (void) (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_send,
+ &bp, &remain);
+ kret = (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_recv,
+ &bp, &remain);
+ if (kret) {
+ free(ctx);
+ return kret;
+ }
+
+ {
+ krb5_pointer tmp;
+ kret = kg_oid_internalize(kcontext, &tmp, &bp,
+ &remain);
+ if (kret == 0)
+ ctx->mech_used = tmp;
+ else if (kret == EINVAL)
+ kret = 0;
+ }
+ /* Now get substructure data */
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer *) &princ,
+ &bp, &remain);
+ if (kret == 0) {
+ kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ctx->here);
+ if (kret)
+ krb5_free_principal(kcontext, princ);
+ } else if (kret == EINVAL)
+ kret = 0;
+ if (!kret) {
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer *) &princ,
+ &bp, &remain);
+ if (kret == 0) {
+ kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ctx->there);
+ if (kret)
+ krb5_free_principal(kcontext, princ);
+ } else if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->subkey, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->enc, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->seq, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+
+ if (!kret) {
+ kret = kg_seqstate_internalize(kcontext, &ctx->seqstate,
+ &bp, &remain);
+ if (kret == EINVAL)
+ kret = 0;
+ }
+
+ if (!kret)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer *) &ctx->k5_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer *) &ctx->auth_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->proto = ibuf;
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cksumtype = ibuf;
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->acceptor_subkey,
+ &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->acceptor_subkey_cksumtype = ibuf;
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cred_rcache = ibuf;
+ /* authdata */
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ if (!kret) {
+ krb5_int32 nadata = ibuf, i;
+
+ if (nadata > 0) {
+ ctx->authdata = (krb5_authdata **)calloc((size_t)nadata + 1,
+ sizeof(krb5_authdata *));
+ if (ctx->authdata == NULL) {
+ kret = ENOMEM;
+ } else {
+ for (i = 0; !kret && i < nadata; i++)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTHDATA,
+ (krb5_pointer *)&ctx->authdata[i],
+ &bp,
+ &remain);
+ }
+ }
+ }
+ /* authdata context */
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+ if (initiator_name == NULL) {
+ kret = EINVAL;
+ } else {
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ (krb5_pointer *)&initiator_name->ad_context,
+ &bp,
+ &remain);
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ }
+ /* Get trailer */
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ if (!kret && ibuf != KG_CONTEXT)
+ kret = EINVAL;
+
+ if (!kret) {
+ *buffer = bp;
+ *lenremain = remain;
+ *argp = (krb5_pointer) ctx;
+ } else {
+ if (ctx->seq)
+ krb5_k_free_key(kcontext, ctx->seq);
+ if (ctx->enc)
+ krb5_k_free_key(kcontext, ctx->enc);
+ if (ctx->subkey)
+ krb5_k_free_key(kcontext, ctx->subkey);
+ if (ctx->there)
+ kg_release_name(kcontext, &ctx->there);
+ if (ctx->here)
+ kg_release_name(kcontext, &ctx->here);
+ xfree(ctx);
+ }
+ }
+ }
+ return(kret);
+}
diff --git a/src/lib/gssapi/krb5/set_allowable_enctypes.c b/src/lib/gssapi/krb5/set_allowable_enctypes.c
new file mode 100644
index 000000000000..d9fd279ed234
--- /dev/null
+++ b/src/lib/gssapi/krb5/set_allowable_enctypes.c
@@ -0,0 +1,123 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/set_allowable_enctypes.c */
+/*
+ * Copyright 2004 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.
+ */
+
+/*
+ * krb5_gss_set_allowable_enctypes()
+ */
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred_handle' must be a valid credential handle obtained via
+ * gss_acquire_cred(). It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may be called with GSS_C_NO_CREDENTIAL
+ * to get a handle to the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "gssapi_krb5.h"
+
+OM_uint32
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ unsigned int i;
+ krb5_enctype * new_ktypes;
+ OM_uint32 major_status;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code kerr = 0;
+ struct krb5_gss_set_allowable_enctypes_req *req;
+
+ /* Assume a failure */
+ *minor_status = 0;
+ major_status = GSS_S_FAILURE;
+
+ assert(value->length == sizeof(*req));
+ req = (struct krb5_gss_set_allowable_enctypes_req *)value->value;
+
+ /* verify and valildate cred handle */
+ cred = (krb5_gss_cred_id_t) *cred_handle;
+
+ if (req->ktypes) {
+ for (i = 0; i < req->num_ktypes && req->ktypes[i]; i++) {
+ if (!krb5_c_valid_enctype(req->ktypes[i])) {
+ kerr = KRB5_PROG_ETYPE_NOSUPP;
+ goto error_out;
+ }
+ }
+ } else {
+ k5_mutex_lock(&cred->lock);
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+ cred->req_enctypes = NULL;
+ k5_mutex_unlock(&cred->lock);
+ return GSS_S_COMPLETE;
+ }
+
+ /* Copy the requested ktypes into the cred structure */
+ if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * (i + 1)))) {
+ memcpy(new_ktypes, req->ktypes, sizeof(krb5_enctype) * i);
+ new_ktypes[i] = 0; /* "null-terminate" the list */
+ }
+ else {
+ kerr = ENOMEM;
+ goto error_out;
+ }
+ k5_mutex_lock(&cred->lock);
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+ cred->req_enctypes = new_ktypes;
+ k5_mutex_unlock(&cred->lock);
+
+ /* Success! */
+ return GSS_S_COMPLETE;
+
+error_out:
+ *minor_status = kerr;
+ return(major_status);
+}
diff --git a/src/lib/gssapi/krb5/set_ccache.c b/src/lib/gssapi/krb5/set_ccache.c
new file mode 100644
index 000000000000..8acf3ec90cde
--- /dev/null
+++ b/src/lib/gssapi/krb5/set_ccache.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/set_ccache.c */
+/*
+ * Copyright 1999, 2003 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.
+ */
+
+/*
+ * Set ccache name used by gssapi, and optionally obtain old ccache
+ * name. Caller should not free returned name.
+ */
+
+#include <string.h>
+#include "gssapiP_krb5.h"
+
+OM_uint32
+gss_krb5int_ccache_name(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ char *old_name = NULL;
+ OM_uint32 err = 0;
+ OM_uint32 minor = 0;
+ char *gss_out_name;
+ struct krb5_gss_ccache_name_req *req;
+
+ err = gss_krb5int_initialize_library();
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+
+ assert(value->length == sizeof(*req));
+
+ if (value->length != sizeof(*req))
+ return GSS_S_FAILURE;
+
+ req = (struct krb5_gss_ccache_name_req *)value->value;
+
+ gss_out_name = k5_getspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+
+ if (req->out_name) {
+ const char *tmp_name = NULL;
+
+ if (!err) {
+ kg_get_ccache_name (&err, &tmp_name);
+ }
+ if (!err) {
+ old_name = gss_out_name;
+ gss_out_name = (char *)tmp_name;
+ }
+ }
+ /* If out_name was NULL, we keep the same gss_out_name value, and
+ don't free up any storage (leave old_name NULL). */
+
+ if (!err)
+ kg_set_ccache_name (&err, req->name);
+
+ minor = k5_setspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, gss_out_name);
+ if (minor) {
+ /* Um. Now what? */
+ if (err == 0) {
+ err = minor;
+ }
+ free(gss_out_name);
+ gss_out_name = NULL;
+ }
+
+ if (!err) {
+ if (req->out_name) {
+ *(req->out_name) = gss_out_name;
+ }
+ }
+
+ if (old_name != NULL) {
+ free (old_name);
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c
new file mode 100644
index 000000000000..654d96541726
--- /dev/null
+++ b/src/lib/gssapi/krb5/store_cred.c
@@ -0,0 +1,234 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/store_cred.c */
+/*
+ * Copyright 2009 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.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static int
+has_unexpired_creds(krb5_gss_cred_id_t kcred,
+ const gss_OID desired_mech,
+ int default_cred,
+ gss_const_key_value_set_t cred_store)
+{
+ OM_uint32 major_status, minor;
+ gss_name_t cred_name;
+ gss_OID_set_desc desired_mechs;
+ gss_cred_id_t tmp_cred = GSS_C_NO_CREDENTIAL;
+ OM_uint32 time_rec;
+
+ desired_mechs.count = 1;
+ desired_mechs.elements = (gss_OID)desired_mech;
+
+ if (default_cred)
+ cred_name = GSS_C_NO_NAME;
+ else
+ cred_name = (gss_name_t)kcred->name;
+
+ major_status = krb5_gss_acquire_cred_from(&minor, cred_name, 0,
+ &desired_mechs, GSS_C_INITIATE,
+ cred_store, &tmp_cred, NULL,
+ &time_rec);
+
+ krb5_gss_release_cred(&minor, &tmp_cred);
+
+ return (GSS_ERROR(major_status) || time_rec);
+}
+
+static OM_uint32
+copy_initiator_creds(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t kcred = NULL;
+ krb5_context context = NULL;
+ krb5_ccache ccache = NULL;
+ const char *ccache_name;
+
+ *minor_status = 0;
+
+ if (!default_cred && cred_store == GSS_C_NO_CRED_STORE) {
+ *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ input_cred_handle,
+ context);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ kcred = (krb5_gss_cred_id_t)input_cred_handle;
+
+ if (kcred->ccache == NULL) {
+ *minor_status = KG_CCACHE_NOMATCH;
+ major_status = GSS_S_DEFECTIVE_CREDENTIAL;
+ goto cleanup;
+ }
+
+ if (!overwrite_cred &&
+ has_unexpired_creds(kcred, desired_mech, default_cred, cred_store)) {
+ major_status = GSS_S_DUPLICATE_ELEMENT;
+ goto cleanup;
+ }
+
+ major_status = kg_value_from_cred_store(cred_store,
+ KRB5_CS_CCACHE_URN, &ccache_name);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ if (ccache_name != NULL) {
+ code = krb5_cc_resolve(context, ccache_name, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ code = krb5_cc_initialize(context, ccache,
+ kcred->name->princ);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ }
+
+ if (ccache == NULL) {
+ if (!default_cred) {
+ *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ code = krb5int_cc_default(context, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ code = krb5_cc_copy_creds(context, kcred->ccache, ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ *minor_status = 0;
+ major_status = GSS_S_COMPLETE;
+
+cleanup:
+ if (kcred != NULL)
+ k5_mutex_unlock(&kcred->lock);
+ if (ccache != NULL)
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ return krb5_gss_store_cred_into(minor_status, input_cred_handle,
+ cred_usage, desired_mech,
+ overwrite_cred, default_cred,
+ GSS_C_NO_CRED_STORE,
+ elements_stored, cred_usage_stored);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ OM_uint32 major_status;
+ gss_cred_usage_t actual_usage;
+ OM_uint32 lifetime;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_NO_CRED;
+
+ major_status = GSS_S_FAILURE;
+
+ if (cred_usage == GSS_C_ACCEPT) {
+ *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
+ return GSS_S_FAILURE;
+ } else if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
+ *minor_status = G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = krb5_gss_inquire_cred(minor_status, input_cred_handle,
+ NULL, &lifetime,
+ &actual_usage, elements_stored);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (lifetime == 0)
+ return GSS_S_CREDENTIALS_EXPIRED;
+
+ if (actual_usage != GSS_C_INITIATE && actual_usage != GSS_C_BOTH) {
+ *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = copy_initiator_creds(minor_status, input_cred_handle,
+ desired_mech, overwrite_cred,
+ default_cred, cred_store);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (cred_usage_stored != NULL)
+ *cred_usage_stored = GSS_C_INITIATE;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/util_cksum.c b/src/lib/gssapi/krb5/util_cksum.c
new file mode 100644
index 000000000000..cfd585ec7219
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_cksum.c
@@ -0,0 +1,295 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* Checksumming the channel bindings always uses plain MD5. */
+krb5_error_code
+kg_checksum_channel_bindings(context, cb, cksum)
+ krb5_context context;
+ gss_channel_bindings_t cb;
+ krb5_checksum *cksum;
+{
+ size_t len;
+ char *buf = 0;
+ char *ptr;
+ size_t sumlen;
+ krb5_data plaind;
+ krb5_error_code code;
+ void *temp;
+
+ /* initialize the the cksum */
+ code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
+ if (code)
+ return(code);
+
+ cksum->checksum_type = CKSUMTYPE_RSA_MD5;
+ cksum->length = sumlen;
+
+ /* generate a buffer full of zeros if no cb specified */
+
+ if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
+ if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
+ return(ENOMEM);
+ }
+ memset(cksum->contents, '\0', cksum->length);
+ return(0);
+ }
+
+ /* create the buffer to checksum into */
+
+ len = (sizeof(krb5_int32)*5+
+ cb->initiator_address.length+
+ cb->acceptor_address.length+
+ cb->application_data.length);
+
+ if ((buf = (char *) xmalloc(len)) == NULL)
+ return(ENOMEM);
+
+ /* helper macros. This code currently depends on a long being 32
+ bits, and htonl dtrt. */
+
+ ptr = buf;
+
+ TWRITE_INT(ptr, cb->initiator_addrtype, 0);
+ TWRITE_BUF(ptr, cb->initiator_address, 0);
+ TWRITE_INT(ptr, cb->acceptor_addrtype, 0);
+ TWRITE_BUF(ptr, cb->acceptor_address, 0);
+ TWRITE_BUF(ptr, cb->application_data, 0);
+
+ /* checksum the data */
+
+ plaind.length = len;
+ plaind.data = buf;
+
+ code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
+ &plaind, cksum);
+ if (code)
+ goto cleanup;
+
+ if ((temp = xmalloc(cksum->length)) == NULL) {
+ krb5_free_checksum_contents(context, cksum);
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(temp, cksum->contents, cksum->length);
+ krb5_free_checksum_contents(context, cksum);
+ cksum->contents = (krb5_octet *)temp;
+
+ /* success */
+cleanup:
+ if (buf)
+ xfree(buf);
+ return code;
+}
+
+krb5_error_code
+kg_make_checksum_iov_v1(krb5_context context,
+ krb5_cksumtype type,
+ size_t cksum_len,
+ krb5_key seq,
+ krb5_key enc,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_checksum *checksum)
+{
+ krb5_error_code code;
+ gss_iov_buffer_desc *header;
+ krb5_crypto_iov *kiov;
+ int i = 0, j;
+ size_t conf_len = 0, token_header_len;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* Checksum over ( Header | Confounder | Data | Pad ) */
+ if (toktype == KG_TOK_WRAP_MSG)
+ conf_len = kg_confounder_size(context, enc->keyblock.enctype);
+
+ /* Checksum output */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ kiov[i].data.length = checksum->length;
+ kiov[i].data.data = xmalloc(checksum->length);
+ if (kiov[i].data.data == NULL) {
+ xfree(kiov);
+ return ENOMEM;
+ }
+ i++;
+
+ /* Header | SND_SEQ | SGN_CKSUM | Confounder */
+ token_header_len = 16 + cksum_len + conf_len;
+
+ /* Header (calculate from end because of variable length ASN.1 header) */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 8;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len;
+ i++;
+
+ /* Confounder */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = conf_len;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
+ i++;
+ }
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
+ if (code == 0) {
+ checksum->length = kiov[0].data.length;
+ checksum->contents = (unsigned char *)kiov[0].data.data;
+ } else
+ free(kiov[0].data.data);
+
+ xfree(kiov);
+
+ return code;
+}
+
+static krb5_error_code
+checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean verify,
+ krb5_boolean *valid)
+{
+ krb5_error_code code;
+ gss_iov_buffer_desc *header;
+ gss_iov_buffer_desc *trailer;
+ krb5_crypto_iov *kiov;
+ size_t kiov_count;
+ int i = 0, j;
+ unsigned int k5_checksumlen;
+
+ if (verify)
+ *valid = FALSE;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
+ if (code != 0)
+ return code;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(rrc != 0 || trailer != NULL);
+
+ if (trailer == NULL) {
+ if (rrc != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ if (header->buffer.length != 16 + k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ } else if (trailer->buffer.length != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 2 + iov_count;
+ kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* Checksum over ( Data | Header ) */
+
+ /* Data */
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /* Header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 16;
+ kiov[i].data.data = (char *)header->buffer.value;
+ i++;
+
+ /* Checksum */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ if (trailer == NULL) {
+ kiov[i].data.length = header->buffer.length - 16;
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ } else {
+ kiov[i].data.length = trailer->buffer.length;
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ }
+ i++;
+
+ if (verify)
+ code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid);
+ else
+ code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count);
+
+ xfree(kiov);
+
+ return code;
+}
+
+krb5_error_code
+kg_make_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ return checksum_iov_v3(context, type, rrc, key,
+ sign_usage, iov, iov_count, toktype, 0, NULL);
+}
+
+krb5_error_code
+kg_verify_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean *valid)
+{
+ return checksum_iov_v3(context, type, rrc, key,
+ sign_usage, iov, iov_count, toktype, 1, valid);
+}
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
new file mode 100644
index 000000000000..0cebde12a85c
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -0,0 +1,782 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
+ * Copyright 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+static krb5_error_code
+kg_copy_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey)
+{
+ krb5_error_code code;
+
+ krb5_k_free_key(context, ctx->enc);
+ ctx->enc = NULL;
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->enc);
+ if (code != 0)
+ return code;
+
+ krb5_k_free_key(context, ctx->seq);
+ ctx->seq = NULL;
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
+ if (code != 0)
+ return code;
+
+ return 0;
+}
+
+static krb5_error_code
+kg_derive_des_enc_key(krb5_context context, krb5_key subkey, krb5_key *out)
+{
+ krb5_error_code code;
+ krb5_keyblock *keyblock;
+ unsigned int i;
+
+ *out = NULL;
+
+ code = krb5_k_key_keyblock(context, subkey, &keyblock);
+ if (code != 0)
+ return code;
+
+ for (i = 0; i < keyblock->length; i++)
+ keyblock->contents[i] ^= 0xF0;
+
+ code = krb5_k_create_key(context, keyblock, out);
+ krb5_free_keyblock(context, keyblock);
+ return code;
+}
+
+krb5_error_code
+kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
+ krb5_cksumtype *cksumtype)
+{
+ krb5_error_code code;
+
+ assert(ctx != NULL);
+ assert(subkey != NULL);
+
+ *cksumtype = 0;
+ ctx->proto = 0;
+
+ if (ctx->enc == NULL) {
+ ctx->signalg = -1;
+ ctx->sealalg = -1;
+ }
+
+ code = krb5int_c_mandatory_cksumtype(context, subkey->keyblock.enctype,
+ cksumtype);
+ if (code != 0)
+ return code;
+
+ switch (subkey->keyblock.enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_CRC:
+ krb5_k_free_key(context, ctx->seq);
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
+ if (code != 0)
+ return code;
+
+ krb5_k_free_key(context, ctx->enc);
+ code = kg_derive_des_enc_key(context, subkey, &ctx->enc);
+ if (code != 0)
+ return code;
+
+ ctx->enc->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->seq->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = SGN_ALG_DES_MAC_MD5;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_DES;
+
+ break;
+ case ENCTYPE_DES3_CBC_SHA1:
+ code = kg_copy_keys(context, ctx, subkey);
+ if (code != 0)
+ return code;
+
+ ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
+ ctx->cksum_size = 20;
+ ctx->sealalg = SEAL_ALG_DES3KD;
+ break;
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer" enctype,
+ * even though RFC 4757 treats it as one. */
+ code = kg_copy_keys(context, ctx, subkey);
+ if (code != 0)
+ return code;
+
+ ctx->signalg = SGN_ALG_HMAC_MD5;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
+ break;
+ default:
+ ctx->proto = 1;
+ break;
+ }
+
+ return 0;
+}
+
+int
+kg_confounder_size(krb5_context context, krb5_enctype enctype)
+{
+ krb5_error_code code;
+ size_t blocksize;
+ /* We special case rc4*/
+ if (enctype == ENCTYPE_ARCFOUR_HMAC || enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+ return 8;
+ code = krb5_c_block_size(context, enctype, &blocksize);
+ if (code)
+ return(-1); /* XXX */
+
+ return(blocksize);
+}
+
+krb5_error_code
+kg_make_confounder(krb5_context context, krb5_enctype enctype,
+ unsigned char *buf)
+{
+ int confsize;
+ krb5_data lrandom;
+
+ confsize = kg_confounder_size(context, enctype);
+ if (confsize < 0)
+ return KRB5_BAD_MSIZE;
+
+ lrandom.length = confsize;
+ lrandom.data = (char *)buf;
+
+ return(krb5_c_random_make_octets(context, &lrandom));
+}
+
+/* Set *data_out to a krb5_data structure containing iv, or to NULL if iv is
+ * NULL. */
+static krb5_error_code
+iv_to_state(krb5_context context, krb5_key key, krb5_pointer iv,
+ krb5_data **data_out)
+{
+ krb5_error_code code;
+ krb5_data *data;
+ size_t blocksize;
+
+ *data_out = NULL;
+ if (iv == NULL)
+ return 0;
+
+ code = krb5_c_block_size(context, key->keyblock.enctype, &blocksize);
+ if (code)
+ return code;
+
+ data = k5alloc(sizeof(*data), &code);
+ if (data == NULL)
+ return code;
+ code = alloc_data(data, blocksize);
+ if (code) {
+ free(data);
+ return code;
+ }
+ memcpy(data->data, iv, blocksize);
+ *data_out = data;
+ return 0;
+}
+
+krb5_error_code
+kg_encrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
+ krb5_const_pointer in, krb5_pointer out, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_data *state, inputd;
+ krb5_enc_data outputd;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ inputd.length = length;
+ inputd.data = (char *)in;
+
+ outputd.ciphertext.length = length;
+ outputd.ciphertext.data = out;
+
+ code = krb5_k_encrypt(context, key, usage, state, &inputd, &outputd);
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_encrypt_inplace(krb5_context context, krb5_key key, int usage,
+ krb5_pointer iv, krb5_pointer ptr, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_crypto_iov iov;
+ krb5_data *state;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ iov.flags = KRB5_CRYPTO_TYPE_DATA;
+ iov.data = make_data((void *)ptr, length);
+ code = krb5_k_encrypt_iov(context, key, usage, state, &iov, 1);
+ krb5_free_data(context, state);
+ return code;
+}
+
+/* length is the length of the cleartext. */
+
+krb5_error_code
+kg_decrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
+ krb5_const_pointer in, krb5_pointer out, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_data *state, outputd;
+ krb5_enc_data inputd;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ inputd.enctype = ENCTYPE_UNKNOWN;
+ inputd.ciphertext.length = length;
+ inputd.ciphertext.data = (char *)in;
+
+ outputd.length = length;
+ outputd.data = out;
+
+ code = krb5_k_decrypt(context, key, usage, state, &inputd, &outputd);
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_arcfour_docrypt(const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ const unsigned char *input_buf, size_t input_len,
+ unsigned char *output_buf)
+{
+ krb5_data kd = make_data((char *) kd_data, kd_data_len);
+ krb5_crypto_iov kiov;
+
+ memcpy(output_buf, input_buf, input_len);
+ kiov.flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov.data = make_data(output_buf, input_len);
+ return krb5int_arcfour_gsscrypt(keyblock, usage, &kd, &kiov, 1);
+}
+
+/* AEAD */
+static krb5_error_code
+kg_translate_iov_v1(krb5_context context, krb5_enctype enctype,
+ gss_iov_buffer_desc *iov, int iov_count,
+ krb5_crypto_iov **pkiov, size_t *pkiov_count)
+{
+ gss_iov_buffer_desc *header;
+ gss_iov_buffer_desc *trailer;
+ int i = 0, j;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+ size_t conf_len;
+
+ *pkiov = NULL;
+ *pkiov_count = 0;
+
+ conf_len = kg_confounder_size(context, enctype);
+
+ header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ if (header->buffer.length < conf_len)
+ return KRB5_BAD_MSIZE;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(trailer == NULL || trailer->buffer.length == 0);
+
+ kiov_count = 3 + iov_count;
+ kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* For pre-CFX (raw enctypes) there is no krb5 header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
+ kiov[i].data.length = 0;
+ kiov[i].data.data = NULL;
+ i++;
+
+ /* For pre-CFX, the confounder is at the end of the GSS header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = conf_len;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
+ i++;
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
+ continue;
+
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+ kiov[i].data.length = 0;
+ kiov[i].data.data = NULL;
+ i++;
+
+ *pkiov = kiov;
+ *pkiov_count = i;
+
+ return 0;
+}
+
+/*
+ * DCE_STYLE indicates actual RRC is EC + RRC
+ * EC is extra rotate count for DCE_STYLE, pad length otherwise
+ * RRC is rotate count.
+ */
+static krb5_error_code
+kg_translate_iov_v3(krb5_context context, int dce_style, size_t ec, size_t rrc,
+ krb5_enctype enctype, gss_iov_buffer_desc *iov,
+ int iov_count, krb5_crypto_iov **pkiov,
+ size_t *pkiov_count)
+{
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t trailer;
+ int i = 0, j;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+ unsigned int k5_headerlen = 0, k5_trailerlen = 0;
+ size_t gss_headerlen, gss_trailerlen;
+ krb5_error_code code;
+
+ *pkiov = NULL;
+ *pkiov_count = 0;
+
+ header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(trailer == NULL || rrc == 0);
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
+ &k5_headerlen);
+ if (code != 0)
+ return code;
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
+ &k5_trailerlen);
+ if (code != 0)
+ return code;
+
+ /* Check header and trailer sizes */
+ gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
+ gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
+
+ /* If we're caller without a trailer, we must rotate by trailer length */
+ if (trailer == NULL) {
+ size_t actual_rrc = rrc;
+
+ if (dce_style)
+ actual_rrc += ec; /* compensate for Windows bug */
+
+ if (actual_rrc != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+
+ gss_headerlen += gss_trailerlen;
+ gss_trailerlen = 0;
+ } else {
+ if (trailer->buffer.length != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+ }
+
+ if (header->buffer.length != gss_headerlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 3 + iov_count;
+ kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /*
+ * The krb5 header is located at the end of the GSS header.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
+ kiov[i].data.length = k5_headerlen;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
+ i++;
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
+ continue;
+
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /*
+ * The EC and encrypted GSS header are placed in the trailer, which may
+ * be rotated directly after the plaintext header if no trailer buffer
+ * is provided.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = ec + 16; /* E(Header) */
+ if (trailer == NULL)
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ else
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ i++;
+
+ /*
+ * The krb5 trailer is placed after the encrypted copy of the
+ * krb5 header (which may be in the GSS header or trailer).
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+ kiov[i].data.length = k5_trailerlen;
+ kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
+ i++;
+
+ *pkiov = kiov;
+ *pkiov_count = i;
+
+ return 0;
+}
+
+/* PROTO is 1 if CFX, 0 if pre-CFX */
+static krb5_error_code
+kg_translate_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_enctype enctype, gss_iov_buffer_desc *iov,
+ int iov_count, krb5_crypto_iov **pkiov, size_t *pkiov_count)
+{
+ return proto ?
+ kg_translate_iov_v3(context, dce_style, ec, rrc, enctype,
+ iov, iov_count, pkiov, pkiov_count) :
+ kg_translate_iov_v1(context, enctype, iov, iov_count,
+ pkiov, pkiov_count);
+}
+
+krb5_error_code
+kg_encrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_key key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ krb5_data *state;
+ size_t kiov_len;
+ krb5_crypto_iov *kiov;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ code = kg_translate_iov(context, proto, dce_style, ec, rrc,
+ key->keyblock.enctype, iov, iov_count,
+ &kiov, &kiov_len);
+ if (code == 0) {
+ code = krb5_k_encrypt_iov(context, key, usage, state, kiov, kiov_len);
+ free(kiov);
+ }
+
+ krb5_free_data(context, state);
+ return code;
+}
+
+/* length is the length of the cleartext. */
+
+krb5_error_code
+kg_decrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_key key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ krb5_data *state;
+ size_t kiov_len;
+ krb5_crypto_iov *kiov;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ code = kg_translate_iov(context, proto, dce_style, ec, rrc,
+ key->keyblock.enctype, iov, iov_count,
+ &kiov, &kiov_len);
+ if (code == 0) {
+ code = krb5_k_decrypt_iov(context, key, usage, state, kiov, kiov_len);
+ free(kiov);
+ }
+
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_arcfour_docrypt_iov(krb5_context context, const krb5_keyblock *keyblock,
+ int usage, const unsigned char *kd_data,
+ size_t kd_data_len, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ krb5_error_code code;
+ krb5_data kd = make_data((char *) kd_data, kd_data_len);
+ krb5_crypto_iov *kiov = NULL;
+ size_t kiov_len = 0;
+
+ code = kg_translate_iov(context, 0 /* proto */, 0 /* dce_style */,
+ 0 /* ec */, 0 /* rrc */, keyblock->enctype,
+ iov, iov_count, &kiov, &kiov_len);
+ if (code)
+ return code;
+ code = krb5int_arcfour_gsscrypt(keyblock, usage, &kd, kiov, kiov_len);
+ free(kiov);
+ return code;
+}
+
+krb5_cryptotype
+kg_translate_flag_iov(OM_uint32 type)
+{
+ krb5_cryptotype ktype;
+
+ switch (GSS_IOV_BUFFER_TYPE(type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ case GSS_IOV_BUFFER_TYPE_PADDING:
+ ktype = KRB5_CRYPTO_TYPE_DATA;
+ break;
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ break;
+ default:
+ ktype = KRB5_CRYPTO_TYPE_EMPTY;
+ break;
+ }
+
+ return ktype;
+}
+
+gss_iov_buffer_t
+kg_locate_iov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
+{
+ int i;
+ gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return GSS_C_NO_IOV_BUFFER;
+
+ for (i = iov_count - 1; i >= 0; i--) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
+ if (p == GSS_C_NO_IOV_BUFFER)
+ p = &iov[i];
+ else
+ return GSS_C_NO_IOV_BUFFER;
+ }
+ }
+
+ return p;
+}
+
+/* Return the IOV where the GSSAPI token header should be placed (and possibly
+ * the checksum as well, depending on the token type). */
+gss_iov_buffer_t
+kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
+{
+ if (toktype == KG_TOK_MIC_MSG)
+ return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
+ else
+ return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+}
+
+void
+kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
+ size_t *assoc_data_length_p)
+{
+ int i;
+ size_t data_length = 0, assoc_data_length = 0;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ *data_length_p = *assoc_data_length_p = 0;
+
+ for (i = 0; i < iov_count; i++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ assoc_data_length += iov[i].buffer.length;
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ data_length += iov[i].buffer.length;
+ }
+
+ *data_length_p = data_length;
+ *assoc_data_length_p = assoc_data_length;
+}
+
+void
+kg_release_iov(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ gssalloc_free(iov[i].buffer.value);
+ iov[i].buffer.length = 0;
+ iov[i].buffer.value = NULL;
+ iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+ }
+}
+
+OM_uint32
+kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ gss_iov_buffer_t padding = NULL;
+ gss_iov_buffer_t data = NULL;
+ size_t padlength, relative_padlength;
+ unsigned char *p;
+
+ data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+
+ if (data == NULL) {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ if (padding == NULL || padding->buffer.length == 0) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)padding->buffer.value;
+ padlength = p[padding->buffer.length - 1];
+
+ if (data->buffer.length + padding->buffer.length < padlength ||
+ padlength == 0) {
+ *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /*
+ * kg_unseal_stream_iov() will place one byte of padding in the
+ * padding buffer; its true value is unknown until after decryption.
+ *
+ * relative_padlength contains the number of bytes to compensate the
+ * padding and data buffers by; it will be zero if the caller manages
+ * the padding length.
+ *
+ * If the caller manages the padding length, then relative_padlength
+ * wil be zero.
+ *
+ * eg. if the buffers are structured as follows:
+ *
+ * +---DATA---+-PAD-+
+ * | ABCDE444 | 4 |
+ * +----------+-----+
+ *
+ * after compensation they would look like:
+ *
+ * +-DATA--+-PAD--+
+ * | ABCDE | NULL |
+ * +-------+------+
+ */
+ relative_padlength = padlength - padding->buffer.length;
+
+ assert(data->buffer.length >= relative_padlength);
+
+ data->buffer.length -= relative_padlength;
+
+ kg_release_iov(padding, 1);
+ padding->buffer.length = 0;
+ padding->buffer.value = NULL;
+
+ return GSS_S_COMPLETE;
+}
+
+krb5_boolean
+kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+ krb5_boolean has_conf_data = FALSE;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
+ has_conf_data = TRUE;
+ break;
+ }
+ }
+
+ return (has_conf_data == FALSE);
+}
+
+krb5_error_code
+kg_allocate_iov(gss_iov_buffer_t iov, size_t size)
+{
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+ assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
+
+ iov->buffer.length = size;
+ iov->buffer.value = gssalloc_malloc(size);
+ if (iov->buffer.value == NULL) {
+ iov->buffer.length = 0;
+ return ENOMEM;
+ }
+
+ iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
+
+ return 0;
+}
diff --git a/src/lib/gssapi/krb5/util_seed.c b/src/lib/gssapi/krb5/util_seed.c
new file mode 100644
index 000000000000..6e1c9ac8aecb
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_seed.c
@@ -0,0 +1,61 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+static const unsigned char zeros[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+
+krb5_error_code
+kg_make_seed(context, key, seed)
+ krb5_context context;
+ krb5_key key;
+ unsigned char *seed;
+{
+ krb5_error_code code;
+ krb5_key rkey = NULL;
+ krb5_keyblock *tmpkey, *kb;
+ unsigned int i;
+
+ code = krb5_k_key_keyblock(context, key, &tmpkey);
+ if (code)
+ return(code);
+
+ /* reverse the key bytes, as per spec */
+ kb = &key->keyblock;
+ for (i=0; i<tmpkey->length; i++)
+ tmpkey->contents[i] = kb->contents[kb->length - 1 - i];
+
+ code = krb5_k_create_key(context, tmpkey, &rkey);
+ if (code)
+ goto cleanup;
+
+ code = kg_encrypt(context, rkey, KG_USAGE_SEAL, NULL, zeros, seed, 16);
+
+cleanup:
+ krb5_free_keyblock(context, tmpkey);
+ krb5_k_free_key(context, rkey);
+ return(code);
+}
diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c
new file mode 100644
index 000000000000..bef631da9d1a
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_seqnum.c
@@ -0,0 +1,102 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2009 by the Massachusetts Institute of Technology.
+ * Copyright 1993 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.
+ */
+
+#include "gssapiP_krb5.h"
+#include "k5-int.h"
+
+/*
+ * $Id$
+ */
+
+krb5_error_code
+kg_make_seq_num(context, key, direction, seqnum, cksum, buf)
+ krb5_context context;
+ krb5_key key;
+ int direction;
+ krb5_ui_4 seqnum;
+ unsigned char *cksum;
+ unsigned char *buf;
+{
+ unsigned char plain[8];
+
+ plain[4] = direction;
+ plain[5] = direction;
+ plain[6] = direction;
+ plain[7] = direction;
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ /* Yes, Microsoft used big-endian sequence number.*/
+ store_32_be(seqnum, plain);
+ return kg_arcfour_docrypt (&key->keyblock, 0,
+ cksum, 8,
+ &plain[0], 8,
+ buf);
+
+ }
+
+ store_32_le(seqnum, plain);
+ return(kg_encrypt(context, key, KG_USAGE_SEQ, cksum, plain, buf, 8));
+}
+
+krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum)
+ krb5_context context;
+ krb5_key key;
+ unsigned char *cksum;
+ unsigned char *buf;
+ int *direction;
+ krb5_ui_4 *seqnum;
+{
+ krb5_error_code code;
+ unsigned char plain[8];
+
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ code = kg_arcfour_docrypt (&key->keyblock, 0,
+ cksum, 8,
+ buf, 8,
+ plain);
+ } else {
+ code = kg_decrypt(context, key, KG_USAGE_SEQ, cksum, buf, plain, 8);
+ }
+ if (code)
+ return(code);
+
+ if ((plain[4] != plain[5]) ||
+ (plain[4] != plain[6]) ||
+ (plain[4] != plain[7]))
+ return((krb5_error_code) KG_BAD_SEQ);
+
+ *direction = plain[4];
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ *seqnum = (plain[3]|(plain[2]<<8) | (plain[1]<<16)| (plain[0]<<24));
+ } else {
+ *seqnum = ((plain[0]) |
+ (plain[1]<<8) |
+ (plain[2]<<16) |
+ (plain[3]<<24));
+ }
+
+ return(0);
+}
diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c
new file mode 100644
index 000000000000..cb1cb9393acf
--- /dev/null
+++ b/src/lib/gssapi/krb5/val_cred.c
@@ -0,0 +1,83 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1997, 2007 by 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.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* Check to see whether or not a GSSAPI krb5 credential is valid. If
+ * it is not, return an error. */
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ krb5_context context)
+{
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+ krb5_principal princ;
+
+ cred = (krb5_gss_cred_id_t) cred_handle;
+ k5_mutex_lock(&cred->lock);
+
+ if (cred->ccache && cred->expire != 0) {
+ if ((code = krb5_cc_get_principal(context, cred->ccache, &princ))) {
+ k5_mutex_unlock(&cred->lock);
+ *minor_status = code;
+ return(GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+ if (!krb5_principal_compare(context, princ, cred->name->princ)) {
+ k5_mutex_unlock(&cred->lock);
+ *minor_status = KG_CCACHE_NOMATCH;
+ return(GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+ (void)krb5_free_principal(context, princ);
+ }
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+krb5_gss_validate_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+{
+ krb5_context context;
+ krb5_error_code code;
+ OM_uint32 maj;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj == 0) {
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t) cred_handle;
+ k5_mutex_assert_locked(&cred->lock);
+ k5_mutex_unlock(&cred->lock);
+ }
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return maj;
+}
diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c
new file mode 100644
index 000000000000..7959f424ec96
--- /dev/null
+++ b/src/lib/gssapi/krb5/wrap_size_limit.c
@@ -0,0 +1,178 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000 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 1993 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.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* V2 interface */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
+ qop_req, req_output_size, max_input_size)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ OM_uint32 req_output_size;
+ OM_uint32 *max_input_size;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 data_size, conflen;
+ OM_uint32 ohlen;
+ int overhead;
+
+ /* only default qop is allowed */
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor_status = (OM_uint32) G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ if (ctx->proto == 1) {
+ /* No pseudo-ASN.1 wrapper overhead, so no sequence length and
+ OID. */
+ OM_uint32 sz = req_output_size;
+
+ /* Token header: 16 octets. */
+ if (conf_req_flag) {
+ krb5_key key;
+ krb5_enctype enctype;
+
+ key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey
+ : ctx->subkey;
+ enctype = key->keyblock.enctype;
+
+ while (sz > 0 && krb5_encrypt_size(sz, enctype) + 16 > req_output_size)
+ sz--;
+ /* Allow for encrypted copy of header. */
+ if (sz > 16)
+ sz -= 16;
+ else
+ sz = 0;
+#ifdef CFX_EXERCISE
+ /* Allow for EC padding. In the MIT implementation, only
+ added while testing. */
+ if (sz > 65535)
+ sz -= 65535;
+ else
+ sz = 0;
+#endif
+ } else {
+ krb5_cksumtype cksumtype;
+ krb5_error_code err;
+ size_t cksumsize;
+
+ cksumtype = ctx->have_acceptor_subkey ? ctx->acceptor_subkey_cksumtype
+ : ctx->cksumtype;
+
+ err = krb5_c_checksum_length(ctx->k5_context, cksumtype, &cksumsize);
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+
+ /* Allow for token header and checksum. */
+ if (sz < 16 + cksumsize)
+ sz = 0;
+ else
+ sz -= (16 + cksumsize);
+ }
+
+ *max_input_size = sz;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ /* Calculate the token size and subtract that from the output size */
+ overhead = 7 + ctx->mech_used->length;
+ data_size = req_output_size;
+ conflen = kg_confounder_size(ctx->k5_context, ctx->enc->keyblock.enctype);
+ data_size = (conflen + data_size + 8) & (~(OM_uint32)7);
+ ohlen = g_token_size(ctx->mech_used,
+ (unsigned int) (data_size + ctx->cksum_size + 14))
+ - req_output_size;
+
+ if (ohlen+overhead < req_output_size)
+ /*
+ * Cannot have trailer length that will cause us to pad over our
+ * length.
+ */
+ *max_input_size = (req_output_size - ohlen - overhead) & (~(OM_uint32)7);
+ else
+ *max_input_size = 0;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
new file mode 100644
index 000000000000..9facb3f42671
--- /dev/null
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -0,0 +1,162 @@
+GSS_C_ATTR_LOCAL_LOGIN_USER
+GSS_C_INQ_SSPI_SESSION_KEY
+GSS_C_NT_ANONYMOUS
+GSS_C_NT_COMPOSITE_EXPORT
+GSS_C_NT_EXPORT_NAME
+GSS_C_NT_HOSTBASED_SERVICE
+GSS_C_NT_HOSTBASED_SERVICE_X
+GSS_C_NT_MACHINE_UID_NAME
+GSS_C_NT_STRING_UID_NAME
+GSS_C_NT_USER_NAME
+GSS_KRB5_NT_PRINCIPAL_NAME
+GSS_KRB5_CRED_NO_CI_FLAGS_X
+GSS_C_MA_MECH_CONCRETE
+GSS_C_MA_MECH_PSEUDO
+GSS_C_MA_MECH_COMPOSITE
+GSS_C_MA_MECH_NEGO
+GSS_C_MA_MECH_GLUE
+GSS_C_MA_NOT_MECH
+GSS_C_MA_DEPRECATED
+GSS_C_MA_NOT_DFLT_MECH
+GSS_C_MA_ITOK_FRAMED
+GSS_C_MA_AUTH_INIT
+GSS_C_MA_AUTH_TARG
+GSS_C_MA_AUTH_INIT_INIT
+GSS_C_MA_AUTH_TARG_INIT
+GSS_C_MA_AUTH_INIT_ANON
+GSS_C_MA_AUTH_TARG_ANON
+GSS_C_MA_DELEG_CRED
+GSS_C_MA_INTEG_PROT
+GSS_C_MA_CONF_PROT
+GSS_C_MA_MIC
+GSS_C_MA_WRAP
+GSS_C_MA_PROT_READY
+GSS_C_MA_REPLAY_DET
+GSS_C_MA_OOS_DET
+GSS_C_MA_CBINDINGS
+GSS_C_MA_PFS
+GSS_C_MA_COMPRESS
+GSS_C_MA_CTX_TRANS
+gss_accept_sec_context
+gss_acquire_cred
+gss_acquire_cred_with_password
+gss_acquire_cred_impersonate_name
+gss_add_buffer_set_member
+gss_add_cred
+gss_add_cred_impersonate_name
+gss_add_cred_with_password
+gss_add_oid_set_member
+gss_authorize_localname
+gss_canonicalize_name
+gss_compare_name
+gss_complete_auth_token
+gss_context_time
+gss_create_empty_buffer_set
+gss_create_empty_oid_set
+gss_decapsulate_token
+gss_delete_name_attribute
+gss_delete_sec_context
+gss_display_mech_attr
+gss_display_name
+gss_display_name_ext
+gss_display_status
+gss_duplicate_name
+gss_encapsulate_token
+gss_export_cred
+gss_export_name
+gss_export_name_composite
+gss_export_sec_context
+gss_get_mic
+gss_get_mic_iov
+gss_get_mic_iov_length
+gss_get_name_attribute
+gss_import_cred
+gss_import_name
+gss_import_sec_context
+gss_indicate_mechs
+gss_init_sec_context
+gss_indicate_mechs_by_attrs
+gss_inquire_attrs_for_mech
+gss_inquire_context
+gss_inquire_cred
+gss_inquire_cred_by_mech
+gss_inquire_cred_by_oid
+gss_inquire_mech_for_saslname
+gss_inquire_mechs_for_name
+gss_inquire_names_for_mech
+gss_inquire_saslname_for_mech
+gss_inquire_sec_context_by_oid
+gss_krb5_ccache_name
+gss_krb5_copy_ccache
+gss_krb5_export_lucid_sec_context
+gss_krb5_free_lucid_sec_context
+gss_krb5_get_tkt_flags
+gss_krb5_import_cred
+gss_krb5_set_allowable_enctypes
+gss_krb5_set_cred_rcache
+gss_krb5int_make_seal_token_v3
+gss_krb5int_unseal_token_v3
+gsskrb5_extract_authtime_from_sec_context
+gsskrb5_extract_authz_data_from_sec_context
+gss_localname
+gss_map_name_to_any
+gss_mech_iakerb
+gss_mech_krb5
+gss_mech_krb5_old
+gss_mech_krb5_wrong
+gss_mech_set_krb5
+gss_mech_set_krb5_both
+gss_mech_set_krb5_old
+gss_nt_exported_name
+gss_nt_krb5_name
+gss_nt_krb5_principal
+gss_nt_machine_uid_name
+gss_nt_service_name
+gss_nt_service_name_v2
+gss_nt_string_uid_name
+gss_nt_user_name
+gss_oid_equal
+gss_oid_to_str
+gss_pname_to_uid
+gss_pseudo_random
+gss_process_context_token
+gss_release_any_name_mapping
+gss_release_buffer_set
+gss_release_buffer
+gss_release_cred
+gss_release_iov_buffer
+gss_release_name
+gss_release_oid
+gss_release_oid_set
+gss_seal
+gss_set_name_attribute
+gss_set_neg_mechs
+gss_set_sec_context_option
+gss_sign
+gss_store_cred
+gss_str_to_oid
+gss_test_oid_set_member
+gss_unseal
+gss_unwrap
+gss_unwrap_aead
+gss_unwrap_iov
+gss_userok
+gss_verify
+gss_verify_mic
+gss_verify_mic_iov
+gss_wrap
+gss_wrap_aead
+gss_wrap_iov
+gss_wrap_iov_length
+gss_wrap_size_limit
+gss_set_cred_option
+gssspi_set_cred_option
+gssspi_mech_invoke
+krb5_gss_dbg_client_expcreds
+krb5_gss_register_acceptor_identity
+krb5_gss_use_kdc_context
+gss_inquire_name
+gss_acquire_cred_from
+gss_add_cred_from
+gss_store_cred_into
+gssint_g_seqstate_init
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
new file mode 100644
index 000000000000..5e1ed6df6a4c
--- /dev/null
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -0,0 +1,224 @@
+mydir=lib$(S)gssapi$(S)mechglue
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../krb5 -I$(srcdir)/../krb5 -I../spnego -I$(srcdir)/../spnego
+DEFINES=-D_GSS_STATIC_LINK=1
+
+##DOSBUILDTOP = ..\..\..
+##DOS##PREFIXDIR=mechglue
+##DOS##OBJFILE=..\$(OUTPRE)mechglue.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+SRCS = \
+ $(srcdir)/g_accept_sec_context.c \
+ $(srcdir)/g_acquire_cred.c \
+ $(srcdir)/g_acquire_cred_with_pw.c \
+ $(srcdir)/g_acquire_cred_imp_name.c \
+ $(srcdir)/g_authorize_localname.c \
+ $(srcdir)/g_buffer_set.c \
+ $(srcdir)/g_canon_name.c \
+ $(srcdir)/g_compare_name.c \
+ $(srcdir)/g_complete_auth_token.c \
+ $(srcdir)/g_context_time.c \
+ $(srcdir)/g_decapsulate_token.c \
+ $(srcdir)/g_delete_sec_context.c \
+ $(srcdir)/g_del_name_attr.c \
+ $(srcdir)/g_dsp_name.c \
+ $(srcdir)/g_dsp_name_ext.c \
+ $(srcdir)/g_dsp_status.c \
+ $(srcdir)/g_dup_name.c \
+ $(srcdir)/g_encapsulate_token.c \
+ $(srcdir)/g_exp_sec_context.c \
+ $(srcdir)/g_export_cred.c \
+ $(srcdir)/g_export_name.c \
+ $(srcdir)/g_export_name_comp.c \
+ $(srcdir)/g_get_name_attr.c \
+ $(srcdir)/g_glue.c \
+ $(srcdir)/g_imp_cred.c \
+ $(srcdir)/g_imp_name.c \
+ $(srcdir)/g_imp_sec_context.c \
+ $(srcdir)/g_init_sec_context.c \
+ $(srcdir)/g_initialize.c \
+ $(srcdir)/g_inq_context.c \
+ $(srcdir)/g_inq_context_oid.c \
+ $(srcdir)/g_inq_cred.c \
+ $(srcdir)/g_inq_cred_oid.c \
+ $(srcdir)/g_inq_name.c \
+ $(srcdir)/g_inq_names.c \
+ $(srcdir)/g_map_name_to_any.c \
+ $(srcdir)/g_mech_invoke.c \
+ $(srcdir)/g_mechattr.c \
+ $(srcdir)/g_mechname.c \
+ $(srcdir)/g_oid_ops.c \
+ $(srcdir)/g_prf.c \
+ $(srcdir)/g_process_context.c \
+ $(srcdir)/g_rel_buffer.c \
+ $(srcdir)/g_rel_cred.c \
+ $(srcdir)/g_rel_name.c \
+ $(srcdir)/g_rel_name_mapping.c \
+ $(srcdir)/g_rel_oid_set.c \
+ $(srcdir)/g_saslname.c \
+ $(srcdir)/g_seal.c \
+ $(srcdir)/g_set_context_option.c \
+ $(srcdir)/g_set_cred_option.c \
+ $(srcdir)/g_set_name_attr.c \
+ $(srcdir)/g_set_neg_mechs.c \
+ $(srcdir)/g_sign.c \
+ $(srcdir)/g_store_cred.c \
+ $(srcdir)/g_unseal.c \
+ $(srcdir)/g_unwrap_aead.c \
+ $(srcdir)/g_unwrap_iov.c \
+ $(srcdir)/g_verify.c \
+ $(srcdir)/g_wrap_aead.c \
+ $(srcdir)/g_wrap_iov.c \
+ $(srcdir)/gssd_pname_to_uid.c
+
+OBJS = \
+ $(OUTPRE)g_accept_sec_context.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_with_pw.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT) \
+ $(OUTPRE)g_authorize_localname.$(OBJEXT) \
+ $(OUTPRE)g_buffer_set.$(OBJEXT) \
+ $(OUTPRE)g_canon_name.$(OBJEXT) \
+ $(OUTPRE)g_compare_name.$(OBJEXT) \
+ $(OUTPRE)g_complete_auth_token.$(OBJEXT) \
+ $(OUTPRE)g_context_time.$(OBJEXT) \
+ $(OUTPRE)g_decapsulate_token.$(OBJEXT) \
+ $(OUTPRE)g_delete_sec_context.$(OBJEXT) \
+ $(OUTPRE)g_del_name_attr.$(OBJEXT) \
+ $(OUTPRE)g_dsp_name.$(OBJEXT) \
+ $(OUTPRE)g_dsp_name_ext.$(OBJEXT) \
+ $(OUTPRE)g_dsp_status.$(OBJEXT) \
+ $(OUTPRE)g_dup_name.$(OBJEXT) \
+ $(OUTPRE)g_encapsulate_token.$(OBJEXT) \
+ $(OUTPRE)g_exp_sec_context.$(OBJEXT) \
+ $(OUTPRE)g_export_cred.$(OBJEXT) \
+ $(OUTPRE)g_export_name.$(OBJEXT) \
+ $(OUTPRE)g_export_name_comp.$(OBJEXT) \
+ $(OUTPRE)g_get_name_attr.$(OBJEXT) \
+ $(OUTPRE)g_glue.$(OBJEXT) \
+ $(OUTPRE)g_imp_cred.$(OBJEXT) \
+ $(OUTPRE)g_imp_name.$(OBJEXT) \
+ $(OUTPRE)g_imp_sec_context.$(OBJEXT) \
+ $(OUTPRE)g_init_sec_context.$(OBJEXT) \
+ $(OUTPRE)g_initialize.$(OBJEXT) \
+ $(OUTPRE)g_inq_context.$(OBJEXT) \
+ $(OUTPRE)g_inq_context_oid.$(OBJEXT) \
+ $(OUTPRE)g_inq_cred.$(OBJEXT) \
+ $(OUTPRE)g_inq_cred_oid.$(OBJEXT) \
+ $(OUTPRE)g_inq_name.$(OBJEXT) \
+ $(OUTPRE)g_inq_names.$(OBJEXT) \
+ $(OUTPRE)g_map_name_to_any.$(OBJEXT) \
+ $(OUTPRE)g_mech_invoke.$(OBJEXT) \
+ $(OUTPRE)g_mechattr.$(OBJEXT) \
+ $(OUTPRE)g_mechname.$(OBJEXT) \
+ $(OUTPRE)g_oid_ops.$(OBJEXT) \
+ $(OUTPRE)g_prf.$(OBJEXT) \
+ $(OUTPRE)g_process_context.$(OBJEXT) \
+ $(OUTPRE)g_rel_buffer.$(OBJEXT) \
+ $(OUTPRE)g_rel_cred.$(OBJEXT) \
+ $(OUTPRE)g_rel_name.$(OBJEXT) \
+ $(OUTPRE)g_rel_name_mapping.$(OBJEXT) \
+ $(OUTPRE)g_rel_oid_set.$(OBJEXT) \
+ $(OUTPRE)g_saslname.$(OBJEXT) \
+ $(OUTPRE)g_seal.$(OBJEXT) \
+ $(OUTPRE)g_set_context_option.$(OBJEXT) \
+ $(OUTPRE)g_set_cred_option.$(OBJEXT) \
+ $(OUTPRE)g_set_name_attr.$(OBJEXT) \
+ $(OUTPRE)g_set_neg_mechs.$(OBJEXT) \
+ $(OUTPRE)g_sign.$(OBJEXT) \
+ $(OUTPRE)g_store_cred.$(OBJEXT) \
+ $(OUTPRE)g_unseal.$(OBJEXT) \
+ $(OUTPRE)g_unwrap_aead.$(OBJEXT) \
+ $(OUTPRE)g_unwrap_iov.$(OBJEXT) \
+ $(OUTPRE)g_verify.$(OBJEXT) \
+ $(OUTPRE)g_wrap_aead.$(OBJEXT) \
+ $(OUTPRE)g_wrap_iov.$(OBJEXT) \
+ $(OUTPRE)gssd_pname_to_uid.$(OBJEXT)
+
+STLIBOBJS = \
+ g_accept_sec_context.o \
+ g_acquire_cred.o \
+ g_acquire_cred_with_pw.o \
+ g_acquire_cred_imp_name.o \
+ g_authorize_localname.o \
+ g_buffer_set.o \
+ g_canon_name.o \
+ g_compare_name.o \
+ g_complete_auth_token.o \
+ g_context_time.o \
+ g_decapsulate_token.o \
+ g_delete_sec_context.o \
+ g_del_name_attr.o \
+ g_dsp_name.o \
+ g_dsp_name_ext.o \
+ g_dsp_status.o \
+ g_dup_name.o \
+ g_encapsulate_token.o \
+ g_exp_sec_context.o \
+ g_export_cred.o \
+ g_export_name.o \
+ g_export_name_comp.o \
+ g_get_name_attr.o \
+ g_glue.o \
+ g_imp_cred.o \
+ g_imp_name.o \
+ g_imp_sec_context.o \
+ g_init_sec_context.o \
+ g_initialize.o \
+ g_inq_context.o \
+ g_inq_context_oid.o \
+ g_inq_cred.o \
+ g_inq_cred_oid.o \
+ g_inq_name.o \
+ g_inq_names.o \
+ g_map_name_to_any.o \
+ g_mech_invoke.o \
+ g_mechattr.o \
+ g_mechname.o \
+ g_oid_ops.o \
+ g_prf.o \
+ g_process_context.o \
+ g_rel_buffer.o \
+ g_rel_cred.o \
+ g_rel_name.o \
+ g_rel_name_mapping.o \
+ g_rel_oid_set.o \
+ g_saslname.o \
+ g_seal.o \
+ g_set_context_option.o \
+ g_set_cred_option.o \
+ g_set_name_attr.o \
+ g_set_neg_mechs.o \
+ g_sign.o \
+ g_store_cred.o \
+ g_unseal.o \
+ g_unwrap_aead.o \
+ g_unwrap_iov.o \
+ g_verify.o \
+ g_wrap_aead.o \
+ g_wrap_iov.o \
+ gssd_pname_to_uid.o
+
+EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS = mechglue.h
+
+$(OBJS): $(EXPORTED_HEADERS)
+
+all-unix: all-libobjs
+
+##DOS##LIBOBJS = $(OBJS)
+
+clean-unix:: clean-libobjs
+
+# Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5)
+install:
+ @set -x; for f in $(EXPORTED_HEADERS) ; \
+ do $(INSTALL_DATA) $(srcdir)$(S)$$f \
+ $(DESTDIR)$(KRB5_INCDIR)$(S)gssapi$(S)$$f ; \
+ done
+
+includes:
+
+@libobj_frag@
diff --git a/src/lib/gssapi/mechglue/deps b/src/lib/gssapi/mechglue/deps
new file mode 100644
index 000000000000..26f62aa8a2ec
--- /dev/null
+++ b/src/lib/gssapi/mechglue/deps
@@ -0,0 +1,510 @@
+#
+# Generated makefile dependencies follow.
+#
+g_accept_sec_context.so g_accept_sec_context.po $(OUTPRE)g_accept_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_accept_sec_context.c mechglue.h mglueP.h
+g_acquire_cred.so g_acquire_cred.po $(OUTPRE)g_acquire_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_acquire_cred.c mechglue.h mglueP.h
+g_acquire_cred_with_pw.so g_acquire_cred_with_pw.po \
+ $(OUTPRE)g_acquire_cred_with_pw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_acquire_cred_with_pw.c \
+ mechglue.h mglueP.h
+g_acquire_cred_imp_name.so g_acquire_cred_imp_name.po \
+ $(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_acquire_cred_imp_name.c \
+ mechglue.h mglueP.h
+g_authorize_localname.so g_authorize_localname.po $(OUTPRE)g_authorize_localname.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_authorize_localname.c mechglue.h mglueP.h
+g_buffer_set.so g_buffer_set.po $(OUTPRE)g_buffer_set.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_buffer_set.c mechglue.h mglueP.h
+g_canon_name.so g_canon_name.po $(OUTPRE)g_canon_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_canon_name.c mechglue.h mglueP.h
+g_compare_name.so g_compare_name.po $(OUTPRE)g_compare_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_compare_name.c mechglue.h mglueP.h
+g_complete_auth_token.so g_complete_auth_token.po $(OUTPRE)g_complete_auth_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_complete_auth_token.c mechglue.h mglueP.h
+g_context_time.so g_context_time.po $(OUTPRE)g_context_time.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_context_time.c mechglue.h mglueP.h
+g_decapsulate_token.so g_decapsulate_token.po $(OUTPRE)g_decapsulate_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_decapsulate_token.c mechglue.h mglueP.h
+g_delete_sec_context.so g_delete_sec_context.po $(OUTPRE)g_delete_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_delete_sec_context.c mechglue.h mglueP.h
+g_del_name_attr.so g_del_name_attr.po $(OUTPRE)g_del_name_attr.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_del_name_attr.c mechglue.h mglueP.h
+g_dsp_name.so g_dsp_name.po $(OUTPRE)g_dsp_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_dsp_name.c mechglue.h mglueP.h
+g_dsp_name_ext.so g_dsp_name_ext.po $(OUTPRE)g_dsp_name_ext.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_dsp_name_ext.c mechglue.h mglueP.h
+g_dsp_status.so g_dsp_status.po $(OUTPRE)g_dsp_status.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_dsp_status.c mechglue.h mglueP.h
+g_dup_name.so g_dup_name.po $(OUTPRE)g_dup_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_dup_name.c mechglue.h mglueP.h
+g_encapsulate_token.so g_encapsulate_token.po $(OUTPRE)g_encapsulate_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_encapsulate_token.c mechglue.h mglueP.h
+g_exp_sec_context.so g_exp_sec_context.po $(OUTPRE)g_exp_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_exp_sec_context.c mechglue.h mglueP.h
+g_export_cred.so g_export_cred.po $(OUTPRE)g_export_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_export_cred.c mechglue.h mglueP.h
+g_export_name.so g_export_name.po $(OUTPRE)g_export_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_export_name.c mechglue.h mglueP.h
+g_export_name_comp.so g_export_name_comp.po $(OUTPRE)g_export_name_comp.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_export_name_comp.c mechglue.h mglueP.h
+g_get_name_attr.so g_get_name_attr.po $(OUTPRE)g_get_name_attr.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_get_name_attr.c mechglue.h mglueP.h
+g_glue.so g_glue.po $(OUTPRE)g_glue.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_glue.c mechglue.h \
+ mglueP.h
+g_imp_cred.so g_imp_cred.po $(OUTPRE)g_imp_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_imp_cred.c mechglue.h mglueP.h
+g_imp_name.so g_imp_name.po $(OUTPRE)g_imp_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_imp_name.c mechglue.h mglueP.h
+g_imp_sec_context.so g_imp_sec_context.po $(OUTPRE)g_imp_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_imp_sec_context.c mechglue.h mglueP.h
+g_init_sec_context.so g_init_sec_context.po $(OUTPRE)g_init_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_init_sec_context.c mechglue.h mglueP.h
+g_initialize.so g_initialize.po $(OUTPRE)g_initialize.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../krb5/gssapiP_krb5.h $(srcdir)/../krb5/gssapi_krb5.h \
+ $(srcdir)/../spnego/gssapiP_spnego.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h ../generic/gssapi_err_generic.h \
+ ../krb5/gssapi_err_krb5.h g_initialize.c mechglue.h \
+ mglueP.h
+g_inq_context.so g_inq_context.po $(OUTPRE)g_inq_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_context.c mechglue.h mglueP.h
+g_inq_context_oid.so g_inq_context_oid.po $(OUTPRE)g_inq_context_oid.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_context_oid.c mechglue.h mglueP.h
+g_inq_cred.so g_inq_cred.po $(OUTPRE)g_inq_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_cred.c mechglue.h mglueP.h
+g_inq_cred_oid.so g_inq_cred_oid.po $(OUTPRE)g_inq_cred_oid.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_cred_oid.c mechglue.h mglueP.h
+g_inq_name.so g_inq_name.po $(OUTPRE)g_inq_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_name.c mechglue.h mglueP.h
+g_inq_names.so g_inq_names.po $(OUTPRE)g_inq_names.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_inq_names.c mechglue.h mglueP.h
+g_map_name_to_any.so g_map_name_to_any.po $(OUTPRE)g_map_name_to_any.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_map_name_to_any.c mechglue.h mglueP.h
+g_mech_invoke.so g_mech_invoke.po $(OUTPRE)g_mech_invoke.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_mech_invoke.c mechglue.h mglueP.h
+g_mechattr.so g_mechattr.po $(OUTPRE)g_mechattr.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_mechattr.c mechglue.h mglueP.h
+g_mechname.so g_mechname.po $(OUTPRE)g_mechname.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_mechname.c mechglue.h mglueP.h
+g_oid_ops.so g_oid_ops.po $(OUTPRE)g_oid_ops.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_oid_ops.c mechglue.h mglueP.h
+g_prf.so g_prf.po $(OUTPRE)g_prf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_prf.c mechglue.h \
+ mglueP.h
+g_process_context.so g_process_context.po $(OUTPRE)g_process_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_process_context.c mechglue.h mglueP.h
+g_rel_buffer.so g_rel_buffer.po $(OUTPRE)g_rel_buffer.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_rel_buffer.c mechglue.h mglueP.h
+g_rel_cred.so g_rel_cred.po $(OUTPRE)g_rel_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_rel_cred.c mechglue.h mglueP.h
+g_rel_name.so g_rel_name.po $(OUTPRE)g_rel_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_rel_name.c mechglue.h mglueP.h
+g_rel_name_mapping.so g_rel_name_mapping.po $(OUTPRE)g_rel_name_mapping.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_rel_name_mapping.c mechglue.h mglueP.h
+g_rel_oid_set.so g_rel_oid_set.po $(OUTPRE)g_rel_oid_set.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_rel_oid_set.c mechglue.h mglueP.h
+g_saslname.so g_saslname.po $(OUTPRE)g_saslname.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_saslname.c mechglue.h mglueP.h
+g_seal.so g_seal.po $(OUTPRE)g_seal.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_seal.c mechglue.h \
+ mglueP.h
+g_set_context_option.so g_set_context_option.po $(OUTPRE)g_set_context_option.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_set_context_option.c mechglue.h mglueP.h
+g_set_cred_option.so g_set_cred_option.po $(OUTPRE)g_set_cred_option.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_set_cred_option.c mechglue.h mglueP.h
+g_set_name_attr.so g_set_name_attr.po $(OUTPRE)g_set_name_attr.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_set_name_attr.c mechglue.h mglueP.h
+g_set_neg_mechs.so g_set_neg_mechs.po $(OUTPRE)g_set_neg_mechs.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_set_neg_mechs.c mechglue.h mglueP.h
+g_sign.so g_sign.po $(OUTPRE)g_sign.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(COM_ERR_DEPS) \
+ $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_ext.h \
+ $(srcdir)/../generic/gssapi_generic.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ ../generic/gssapi_err_generic.h g_sign.c mechglue.h \
+ mglueP.h
+g_store_cred.so g_store_cred.po $(OUTPRE)g_store_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_store_cred.c mechglue.h mglueP.h
+g_unseal.so g_unseal.po $(OUTPRE)g_unseal.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_unseal.c mechglue.h mglueP.h
+g_unwrap_aead.so g_unwrap_aead.po $(OUTPRE)g_unwrap_aead.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_unwrap_aead.c mechglue.h mglueP.h
+g_unwrap_iov.so g_unwrap_iov.po $(OUTPRE)g_unwrap_iov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_unwrap_iov.c mechglue.h mglueP.h
+g_verify.so g_verify.po $(OUTPRE)g_verify.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_verify.c mechglue.h mglueP.h
+g_wrap_aead.so g_wrap_aead.po $(OUTPRE)g_wrap_aead.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_wrap_aead.c mechglue.h mglueP.h
+g_wrap_iov.so g_wrap_iov.po $(OUTPRE)g_wrap_iov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ g_wrap_iov.c mechglue.h mglueP.h
+gssd_pname_to_uid.so gssd_pname_to_uid.po $(OUTPRE)gssd_pname_to_uid.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h ../generic/gssapi_err_generic.h \
+ gssd_pname_to_uid.c mechglue.h mglueP.h
diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c
new file mode 100644
index 000000000000..ddaf87412e9e
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -0,0 +1,399 @@
+/* #pragma ident "@(#)g_accept_sec_context.c 1.19 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_accept_sec_context
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#ifndef LEAN_CLIENT
+static OM_uint32
+val_acc_sec_ctx_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token_buffer,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *d_cred)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ if (d_cred != NULL)
+ *d_cred = GSS_C_NO_CREDENTIAL;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_token_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (output_token == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+/* Return true if mech should be accepted with no acceptor credential. */
+static int
+allow_mech_by_default(gss_OID mech)
+{
+ OM_uint32 status, minor;
+ gss_OID_set attrs;
+ int reject = 0, p;
+
+ /* Whether we accept an interposer mech depends on whether we accept the
+ * mech it interposes. */
+ mech = gssint_get_public_oid(mech);
+ if (mech == GSS_C_NO_OID)
+ return 0;
+
+ status = gss_inquire_attrs_for_mech(&minor, mech, &attrs, NULL);
+ if (status)
+ return 0;
+
+ /* Check for each attribute which would cause us to exclude this mech from
+ * the default credential. */
+ if (generic_gss_test_oid_set_member(&minor, GSS_C_MA_DEPRECATED,
+ attrs, &p) != GSS_S_COMPLETE || p)
+ reject = 1;
+ else if (generic_gss_test_oid_set_member(&minor, GSS_C_MA_NOT_DFLT_MECH,
+ attrs, &p) != GSS_S_COMPLETE || p)
+ reject = 1;
+
+ (void) gss_release_oid_set(&minor, &attrs);
+ return !reject;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_accept_sec_context (minor_status,
+ context_handle,
+ verifier_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ d_cred)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t * context_handle;
+gss_cred_id_t verifier_cred_handle;
+gss_buffer_t input_token_buffer;
+gss_channel_bindings_t input_chan_bindings;
+gss_name_t * src_name;
+gss_OID * mech_type;
+gss_buffer_t output_token;
+OM_uint32 * ret_flags;
+OM_uint32 * time_rec;
+gss_cred_id_t * d_cred;
+
+{
+ OM_uint32 status, temp_status, temp_minor_status;
+ OM_uint32 temp_ret_flags = 0;
+ gss_union_ctx_id_t union_ctx_id = NULL;
+ gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t tmp_d_cred = GSS_C_NO_CREDENTIAL;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t tmp_src_name = GSS_C_NO_NAME;
+ gss_OID_desc token_mech_type_desc;
+ gss_OID token_mech_type = &token_mech_type_desc;
+ gss_OID actual_mech = GSS_C_NO_OID;
+ gss_OID selected_mech = GSS_C_NO_OID;
+ gss_OID public_mech;
+ gss_mechanism mech = NULL;
+ gss_union_cred_t uc;
+ int i;
+
+ status = val_acc_sec_ctx_args(minor_status,
+ context_handle,
+ verifier_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ d_cred);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
+ * descriptor to hold the mech type information as well as the
+ * underlying mechanism context handle. Otherwise, cast the
+ * value of *context_handle to the union context variable.
+ */
+
+ if(*context_handle == GSS_C_NO_CONTEXT) {
+
+ if (input_token_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ /* Get the token mech type */
+ status = gssint_get_mech_type(token_mech_type, input_token_buffer);
+ if (status)
+ return status;
+
+ /*
+ * An interposer calling back into the mechglue can't pass in a special
+ * mech, so we have to recognize it using verifier_cred_handle. Use
+ * the mechanism for which we have matching creds, if available.
+ */
+ if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) {
+ uc = (gss_union_cred_t)verifier_cred_handle;
+ for (i = 0; i < uc->count; i++) {
+ public_mech = gssint_get_public_oid(&uc->mechs_array[i]);
+ if (public_mech && g_OID_equal(token_mech_type, public_mech)) {
+ selected_mech = &uc->mechs_array[i];
+ break;
+ }
+ }
+ }
+
+ if (selected_mech == GSS_C_NO_OID) {
+ status = gssint_select_mech_type(minor_status, token_mech_type,
+ &selected_mech);
+ if (status)
+ return status;
+ }
+
+ } else {
+ union_ctx_id = (gss_union_ctx_id_t)*context_handle;
+ selected_mech = union_ctx_id->mech_type;
+ }
+
+ /* Now create a new context if we didn't get one. */
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ status = GSS_S_FAILURE;
+ union_ctx_id = (gss_union_ctx_id_t)
+ malloc(sizeof(gss_union_ctx_id_desc));
+ if (!union_ctx_id)
+ return (GSS_S_FAILURE);
+
+ union_ctx_id->loopback = union_ctx_id;
+ union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
+ status = generic_gss_copy_oid(&temp_minor_status, selected_mech,
+ &union_ctx_id->mech_type);
+ if (status != GSS_S_COMPLETE) {
+ free(union_ctx_id);
+ return (status);
+ }
+
+ /* set the new context handle to caller's data */
+ *context_handle = (gss_ctx_id_t)union_ctx_id;
+ }
+
+ /*
+ * get the appropriate cred handle from the union cred struct.
+ */
+ if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) {
+ input_cred_handle =
+ gssint_get_mechanism_cred((gss_union_cred_t)verifier_cred_handle,
+ selected_mech);
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ /* verifier credential specified but no acceptor credential found */
+ status = GSS_S_NO_CRED;
+ goto error_out;
+ }
+ } else if (!allow_mech_by_default(selected_mech)) {
+ status = GSS_S_NO_CRED;
+ goto error_out;
+ }
+
+ /*
+ * now select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech && mech->gss_accept_sec_context) {
+
+ status = mech->gss_accept_sec_context(minor_status,
+ &union_ctx_id->internal_ctx_id,
+ input_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name ? &internal_name : NULL,
+ &actual_mech,
+ output_token,
+ &temp_ret_flags,
+ time_rec,
+ d_cred ? &tmp_d_cred : NULL);
+
+ /* If there's more work to do, keep going... */
+ if (status == GSS_S_CONTINUE_NEEDED)
+ return GSS_S_CONTINUE_NEEDED;
+
+ /* if the call failed, return with failure */
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto error_out;
+ }
+
+ /*
+ * if src_name is non-NULL,
+ * convert internal_name into a union name equivalent
+ * First call the mechanism specific display_name()
+ * then call gss_import_name() to create
+ * the union name struct cast to src_name
+ */
+ if (src_name != NULL) {
+ if (internal_name != GSS_C_NO_NAME) {
+ /* consumes internal_name regardless of success */
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ status = temp_status;
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ if (output_token->length)
+ (void) gss_release_buffer(&temp_minor_status,
+ output_token);
+ goto error_out;
+ }
+ *src_name = tmp_src_name;
+ } else
+ *src_name = GSS_C_NO_NAME;
+ }
+
+#define g_OID_prefix_equal(o1, o2) \
+ (((o1)->length >= (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
+ /* Ensure we're returning correct creds format */
+ if ((temp_ret_flags & GSS_C_DELEG_FLAG) &&
+ tmp_d_cred != GSS_C_NO_CREDENTIAL) {
+ public_mech = gssint_get_public_oid(selected_mech);
+ if (actual_mech != GSS_C_NO_OID &&
+ public_mech != GSS_C_NO_OID &&
+ !g_OID_prefix_equal(actual_mech, public_mech)) {
+ *d_cred = tmp_d_cred; /* unwrapped pseudo-mech */
+ } else {
+ gss_union_cred_t d_u_cred = NULL;
+
+ d_u_cred = malloc(sizeof (gss_union_cred_desc));
+ if (d_u_cred == NULL) {
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+ (void) memset(d_u_cred, 0, sizeof (gss_union_cred_desc));
+
+ d_u_cred->count = 1;
+
+ status = generic_gss_copy_oid(&temp_minor_status,
+ selected_mech,
+ &d_u_cred->mechs_array);
+
+ if (status != GSS_S_COMPLETE) {
+ free(d_u_cred);
+ goto error_out;
+ }
+
+ d_u_cred->cred_array = malloc(sizeof(gss_cred_id_t));
+ if (d_u_cred->cred_array != NULL) {
+ d_u_cred->cred_array[0] = tmp_d_cred;
+ } else {
+ free(d_u_cred);
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+
+ d_u_cred->loopback = d_u_cred;
+ *d_cred = (gss_cred_id_t)d_u_cred;
+ }
+ }
+
+ if (mech_type != NULL)
+ *mech_type = gssint_get_public_oid(actual_mech);
+ if (ret_flags != NULL)
+ *ret_flags = temp_ret_flags;
+ return (status);
+ } else {
+
+ status = GSS_S_BAD_MECH;
+ }
+
+error_out:
+ if (union_ctx_id) {
+ if (union_ctx_id->mech_type) {
+ if (union_ctx_id->mech_type->elements)
+ free(union_ctx_id->mech_type->elements);
+ free(union_ctx_id->mech_type);
+ }
+ if (union_ctx_id->internal_ctx_id && mech &&
+ mech->gss_delete_sec_context) {
+ mech->gss_delete_sec_context(&temp_minor_status,
+ &union_ctx_id->internal_ctx_id,
+ GSS_C_NO_BUFFER);
+ }
+ free(union_ctx_id);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ if (src_name)
+ *src_name = GSS_C_NO_NAME;
+
+ if (tmp_src_name != GSS_C_NO_NAME)
+ (void) gss_release_buffer(&temp_minor_status,
+ (gss_buffer_t)tmp_src_name);
+
+ return (status);
+}
+#endif /* LEAN_CLIENT */
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c
new file mode 100644
index 000000000000..9bd500b60285
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred.c
@@ -0,0 +1,565 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_acquire_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_args(
+ OM_uint32 *minor_status,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred(minor_status,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec)
+
+OM_uint32 * minor_status;
+gss_name_t desired_name;
+OM_uint32 time_req;
+gss_OID_set desired_mechs;
+int cred_usage;
+gss_cred_id_t * output_cred_handle;
+gss_OID_set * actual_mechs;
+OM_uint32 * time_rec;
+
+{
+ return gss_acquire_cred_from(minor_status, desired_name, time_req,
+ desired_mechs, cred_usage, NULL,
+ output_cred_handle, actual_mechs, time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_from(minor_status,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ cred_store,
+ output_cred_handle,
+ actual_mechs,
+ time_rec)
+
+OM_uint32 * minor_status;
+gss_name_t desired_name;
+OM_uint32 time_req;
+gss_OID_set desired_mechs;
+int cred_usage;
+gss_const_key_value_set_t cred_store;
+gss_cred_id_t * output_cred_handle;
+gss_OID_set * actual_mechs;
+OM_uint32 * time_rec;
+
+{
+ OM_uint32 major = GSS_S_FAILURE, tmpMinor;
+ OM_uint32 first_major = GSS_S_COMPLETE, first_minor = 0;
+ OM_uint32 initTimeOut = 0, acceptTimeOut = 0, outTime = GSS_C_INDEFINITE;
+ gss_OID_set mechs = GSS_C_NO_OID_SET;
+ gss_OID_set_desc except_attrs;
+ gss_OID_desc attr_oids[2];
+ unsigned int i;
+ gss_union_cred_t creds = NULL;
+
+ major = val_acq_cred_args(minor_status,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ cred_store,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ goto cleanup;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then try to
+ * acquire credentials for all non-deprecated mechanisms.
+ */
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ attr_oids[0] = *GSS_C_MA_DEPRECATED;
+ attr_oids[1] = *GSS_C_MA_NOT_DFLT_MECH;
+ except_attrs.count = 2;
+ except_attrs.elements = attr_oids;
+ major = gss_indicate_mechs_by_attrs(minor_status, GSS_C_NO_OID_SET,
+ &except_attrs, GSS_C_NO_OID_SET,
+ &mechs);
+ if (major != GSS_S_COMPLETE)
+ goto cleanup;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0) {
+ major = GSS_S_BAD_MECH;
+ goto cleanup;
+ }
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)calloc(1, sizeof (gss_union_cred_desc));
+ if (creds == NULL) {
+ major = GSS_S_FAILURE;
+ *minor_status = ENOMEM;
+ goto cleanup;
+ }
+
+ creds->count = 0;
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0, major = GSS_S_UNAVAILABLE; i < mechs->count; i++) {
+ major = gss_add_cred_from(&tmpMinor, (gss_cred_id_t)creds,
+ desired_name, &mechs->elements[i],
+ cred_usage, time_req, time_req,
+ cred_store, NULL, NULL,
+ time_rec ? &initTimeOut : NULL,
+ time_rec ? &acceptTimeOut : NULL);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ } else if (first_major == GSS_S_COMPLETE) {
+ first_major = major;
+ first_minor = tmpMinor;
+ }
+ } /* for */
+
+ /* If we didn't get any creds, return the error status from the first mech
+ * (which is often the preferred one). */
+ if (creds->count < 1) {
+ major = first_major;
+ *minor_status = first_minor;
+ goto cleanup;
+ }
+ major = GSS_S_COMPLETE;
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ major = gssint_make_public_oid_set(minor_status, creds->mechs_array,
+ creds->count, actual_mechs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+ *output_cred_handle = (gss_cred_id_t)creds;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_cred(&tmpMinor, (gss_cred_id_t *)&creds);
+ if (desired_mechs == GSS_C_NO_OID_SET)
+ generic_gss_release_oid_set(&tmpMinor, &mechs);
+
+ return (major);
+}
+
+static OM_uint32
+val_add_cred_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_name_t desired_name,
+ gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred(minor_status, input_cred_handle,
+ desired_name, desired_mech, cred_usage,
+ initiator_time_req, acceptor_time_req,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t input_cred_handle;
+ gss_name_t desired_name;
+ gss_OID desired_mech;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ return gss_add_cred_from(minor_status, input_cred_handle, desired_name,
+ desired_mech, cred_usage, initiator_time_req,
+ acceptor_time_req, NULL, output_cred_handle,
+ actual_mechs, initiator_time_rec,
+ acceptor_time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_from(minor_status, input_cred_handle,
+ desired_name, desired_mech,
+ cred_usage,
+ initiator_time_req, acceptor_time_req,
+ cred_store,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t input_cred_handle;
+ gss_name_t desired_name;
+ gss_OID desired_mech;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_const_key_value_set_t cred_store;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec = 0, *time_recp = NULL;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+ gss_OID_set target_mechs = GSS_C_NO_OID_SET;
+ gss_OID selected_mech = GSS_C_NO_OID;
+
+ status = val_add_cred_args(minor_status,
+ input_cred_handle,
+ desired_name,
+ desired_mech,
+ cred_usage,
+ cred_store,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gssint_select_mech_type(minor_status, desired_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred)
+ return (GSS_S_UNAVAILABLE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, selected_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ if (input_cred_handle != GSS_C_NO_CREDENTIAL ||
+ cred_store != GSS_C_NO_CRED_STORE) {
+ /* may need to create a mechanism specific name */
+ if (desired_name) {
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type, selected_mech))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status, selected_mech,
+ union_name, &allocated_name) !=
+ GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+ }
+ }
+
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = gss_create_empty_oid_set(minor_status, &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ status = gss_add_oid_set_member(minor_status,
+ gssint_get_public_oid(selected_mech),
+ &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ if (initiator_time_rec != NULL || acceptor_time_rec != NULL)
+ time_recp = &time_rec;
+
+ if (mech->gss_acquire_cred_from) {
+ status = mech->gss_acquire_cred_from(minor_status, internal_name,
+ time_req, target_mechs,
+ cred_usage, cred_store, &cred,
+ NULL, time_recp);
+ } else if (cred_store == GSS_C_NO_CRED_STORE) {
+ status = mech->gss_acquire_cred(minor_status, internal_name, time_req,
+ target_mechs, cred_usage, &cred, NULL,
+ time_recp);
+ } else {
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(selected_mech->length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count], selected_mech);
+
+ if (actual_mechs != NULL) {
+ status = gssint_make_public_oid_set(minor_status, new_mechs_array,
+ union_cred->count + 1,
+ actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech,
+ &allocated_name);
+ (void) generic_gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech,
+ &allocated_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred)
+ free(union_cred);
+
+ (void) generic_gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c b/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c
new file mode 100644
index 000000000000..9eab25e4cd8e
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c
@@ -0,0 +1,529 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 2009 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 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/* Glue routine for gss_acquire_cred_impersonate_name */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_impersonate_name_args(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_impersonate_name_args(minor_status,
+ impersonator_cred_handle,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_impersonate_name(minor_status,
+ (gss_cred_id_t)creds,
+ impersonator_cred_handle,
+ desired_name,
+ &mechs->elements[i],
+ cred_usage,
+ time_req,
+ time_req, NULL,
+ NULL,
+ &initTimeOut,
+ &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_impersonate_name_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_cred_handle,
+ gss_name_t desired_name,
+ gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_cred_id_t mech_impersonator_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+ gss_OID_set target_mechs = GSS_C_NO_OID_SET;
+ gss_OID selected_mech = GSS_C_NO_OID;
+
+ status = val_add_cred_impersonate_name_args(minor_status,
+ input_cred_handle,
+ impersonator_cred_handle,
+ desired_name,
+ desired_mech,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gssint_select_mech_type(minor_status, desired_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred_impersonate_name)
+ return (GSS_S_UNAVAILABLE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, selected_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ mech_impersonator_cred =
+ gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
+ selected_mech);
+ if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ /* may need to create a mechanism specific name */
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type, selected_mech))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ selected_mech, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = gss_create_empty_oid_set(minor_status, &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ status = gss_add_oid_set_member(minor_status,
+ gssint_get_public_oid(selected_mech),
+ &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ status = mech->gss_acquire_cred_impersonate_name(minor_status,
+ mech_impersonator_cred,
+ internal_name,
+ time_req,
+ target_mechs,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(selected_mech->length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count], selected_mech);
+
+ if (actual_mechs != NULL) {
+ status = gssint_make_public_oid_set(minor_status, new_mechs_array,
+ union_cred->count + 1,
+ actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status, selected_mech,
+ &allocated_name);
+
+ if (target_mechs)
+ (void) gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech, &allocated_name);
+
+ if (target_mechs)
+ (void) gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred)
+ free(union_cred);
+
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c b/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c
new file mode 100644
index 000000000000..7835d59726d3
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c
@@ -0,0 +1,524 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_acquire_cred_with_password
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_pw_args(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_BAD_NAME);
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ if (password == GSS_C_NO_BUFFER ||
+ password->length == 0 ||
+ password->value == NULL) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_password(
+ minor_status,
+ desired_name,
+ password,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec)
+
+OM_uint32 * minor_status;
+const gss_name_t desired_name;
+const gss_buffer_t password;
+OM_uint32 time_req;
+const gss_OID_set desired_mechs;
+int cred_usage;
+gss_cred_id_t * output_cred_handle;
+gss_OID_set * actual_mechs;
+OM_uint32 * time_rec;
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_pw_args(minor_status,
+ desired_name,
+ password,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_with_password(minor_status, (gss_cred_id_t)creds,
+ desired_name,
+ &mechs->elements[i],
+ password,
+ cred_usage, time_req, time_req, NULL,
+ NULL, &initTimeOut, &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ major = gssint_make_public_oid_set(minor_status, creds->mechs_array,
+ creds->count, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_pw_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ const gss_buffer_t password,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_BAD_NAME);
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ if (password == GSS_C_NO_BUFFER ||
+ password->length == 0 ||
+ password->value == NULL) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_password(minor_status, input_cred_handle,
+ desired_name, desired_mech, password, cred_usage,
+ initiator_time_req, acceptor_time_req,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ const gss_cred_id_t input_cred_handle;
+ const gss_name_t desired_name;
+ const gss_OID desired_mech;
+ const gss_buffer_t password;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+ gss_OID_set target_mechs = GSS_C_NO_OID_SET;
+ gss_OID selected_mech = GSS_C_NO_OID;
+
+ status = val_add_cred_pw_args(minor_status,
+ input_cred_handle,
+ desired_name,
+ desired_mech,
+ password,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gssint_select_mech_type(minor_status, desired_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ if (!mech->gssspi_acquire_cred_with_password)
+ return GSS_S_UNAVAILABLE;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, selected_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ /* may need to create a mechanism specific name */
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type, selected_mech))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ selected_mech, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = gss_create_empty_oid_set(minor_status, &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ status = gss_add_oid_set_member(minor_status,
+ gssint_get_public_oid(selected_mech),
+ &target_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+
+ status = mech->gssspi_acquire_cred_with_password(minor_status,
+ internal_name,
+ password,
+ time_req,
+ target_mechs,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(selected_mech->length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count], selected_mech);
+
+ if (actual_mechs != NULL) {
+ status = gssint_make_public_oid_set(minor_status, new_mechs_array,
+ union_cred->count + 1,
+ actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech,
+ &allocated_name);
+
+ if (target_mechs)
+ (void)gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech, &allocated_name);
+
+ if (target_mechs)
+ (void)gss_release_oid_set(&temp_minor_status, &target_mechs);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred)
+ free(union_cred);
+
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_authorize_localname.c b/src/lib/gssapi/mechglue/g_authorize_localname.c
new file mode 100644
index 000000000000..0e4fb0722924
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_authorize_localname.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2011, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_userok.c 1.1 04/03/25 SMI" */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <mglueP.h>
+#include <gssapi/gssapi.h>
+
+static OM_uint32
+mech_authorize_localname(OM_uint32 *minor,
+ const gss_union_name_t unionName,
+ const gss_union_name_t unionUser)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE;
+ gss_mechanism mech;
+
+ if (unionName->mech_type == GSS_C_NO_OID)
+ return (GSS_S_NAME_NOT_MN);
+
+ mech = gssint_get_mechanism(unionName->mech_type);
+ if (mech == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ if (mech->gssspi_authorize_localname != NULL) {
+ major = mech->gssspi_authorize_localname(minor,
+ unionName->mech_name,
+ unionUser->external_name,
+ unionUser->name_type);
+ if (major != GSS_S_COMPLETE)
+ map_error(minor, mech);
+ }
+
+ return (major);
+}
+
+/*
+ * Naming extensions based local login authorization.
+ */
+static OM_uint32
+attr_authorize_localname(OM_uint32 *minor,
+ const gss_name_t name,
+ const gss_union_name_t unionUser)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE; /* attribute not present */
+ gss_buffer_t externalName;
+ int more = -1;
+
+ if (unionUser->name_type != GSS_C_NO_OID &&
+ !g_OID_equal(unionUser->name_type, GSS_C_NT_USER_NAME))
+ return (GSS_S_BAD_NAMETYPE);
+
+ externalName = unionUser->external_name;
+ assert(externalName != GSS_C_NO_BUFFER);
+
+ while (more != 0 && major != GSS_S_COMPLETE) {
+ OM_uint32 tmpMajor, tmpMinor;
+ gss_buffer_desc value;
+ gss_buffer_desc display_value;
+ int authenticated = 0, complete = 0;
+
+ tmpMajor = gss_get_name_attribute(minor,
+ name,
+ GSS_C_ATTR_LOCAL_LOGIN_USER,
+ &authenticated,
+ &complete,
+ &value,
+ &display_value,
+ &more);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ break;
+ }
+
+ if (authenticated &&
+ value.length == externalName->length &&
+ memcmp(value.value, externalName->value, externalName->length) == 0)
+ major = GSS_S_COMPLETE;
+ else
+ major = GSS_S_UNAUTHORIZED;
+
+ gss_release_buffer(&tmpMinor, &value);
+ gss_release_buffer(&tmpMinor, &display_value);
+ }
+
+ return (major);
+}
+
+/*
+ * Equality based local login authorization.
+ */
+static OM_uint32
+compare_names_authorize_localname(OM_uint32 *minor,
+ const gss_union_name_t unionName,
+ const gss_name_t user)
+{
+
+ OM_uint32 status, tmpMinor;
+ gss_name_t canonName;
+ int match = 0;
+
+ status = gss_canonicalize_name(minor,
+ user,
+ unionName->mech_type,
+ &canonName);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gss_compare_name(minor,
+ (gss_name_t)unionName,
+ canonName,
+ &match);
+ if (status == GSS_S_COMPLETE && match == 0)
+ status = GSS_S_UNAUTHORIZED;
+
+ (void) gss_release_name(&tmpMinor, &canonName);
+
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_authorize_localname(OM_uint32 *minor,
+ const gss_name_t name,
+ const gss_name_t user)
+
+{
+ OM_uint32 major;
+ gss_union_name_t unionName;
+ gss_union_name_t unionUser;
+ int mechAvailable = 0;
+
+ if (minor == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (name == GSS_C_NO_NAME || user == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ *minor = 0;
+
+ unionName = (gss_union_name_t)name;
+ unionUser = (gss_union_name_t)user;
+
+ if (unionUser->mech_type != GSS_C_NO_OID)
+ return (GSS_S_BAD_NAME);
+
+ /* If mech returns yes, we return yes */
+ major = mech_authorize_localname(minor, unionName, unionUser);
+ if (major == GSS_S_COMPLETE)
+ return (GSS_S_COMPLETE);
+ else if (major != GSS_S_UNAVAILABLE)
+ mechAvailable = 1;
+
+ /* If attribute exists, we evaluate attribute */
+ major = attr_authorize_localname(minor, unionName, unionUser);
+ if (major == GSS_S_COMPLETE || major == GSS_S_UNAUTHORIZED)
+ return (major);
+
+ /* If mech did not implement SPI, compare the local name */
+ if (mechAvailable == 0 &&
+ unionName->mech_type != GSS_C_NO_OID) {
+ major = compare_names_authorize_localname(minor,
+ unionName,
+ unionUser);
+ }
+
+ return (major);
+}
+
+int KRB5_CALLCONV
+gss_userok(const gss_name_t name,
+ const char *user)
+{
+ OM_uint32 major, minor;
+ gss_buffer_desc userBuf;
+ gss_name_t userName;
+
+ userBuf.value = (void *)user;
+ userBuf.length = strlen(user);
+
+ major = gss_import_name(&minor, &userBuf, GSS_C_NT_USER_NAME, &userName);
+ if (GSS_ERROR(major))
+ return (0);
+
+ major = gss_authorize_localname(&minor, name, userName);
+
+ (void) gss_release_name(&minor, &userName);
+
+ return (major == GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_buffer_set.c b/src/lib/gssapi/mechglue/g_buffer_set.c
new file mode 100644
index 000000000000..9310ddb4b728
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_buffer_set.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 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.
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV gss_create_empty_buffer_set
+ (OM_uint32 * minor_status,
+ gss_buffer_set_t *buffer_set)
+{
+ return generic_gss_create_empty_buffer_set(minor_status, buffer_set);
+}
+
+OM_uint32 KRB5_CALLCONV gss_add_buffer_set_member
+ (OM_uint32 * minor_status,
+ const gss_buffer_t member_buffer,
+ gss_buffer_set_t *buffer_set)
+{
+ return generic_gss_add_buffer_set_member(minor_status,
+ member_buffer,
+ buffer_set);
+}
+
+OM_uint32 KRB5_CALLCONV gss_release_buffer_set
+ (OM_uint32 * minor_status,
+ gss_buffer_set_t *buffer_set)
+{
+ return generic_gss_release_buffer_set(minor_status, buffer_set);
+}
diff --git a/src/lib/gssapi/mechglue/g_canon_name.c b/src/lib/gssapi/mechglue/g_canon_name.c
new file mode 100644
index 000000000000..61f657f91f71
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_canon_name.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_canon_name.c 1.15 04/02/23 SMI" */
+
+/*
+ * routine gss_canonicalize_name
+ *
+ * This routine is used to produce a mechanism specific
+ * representation of name that has been previously
+ * imported with gss_import_name. The routine uses the mechanism
+ * specific implementation of gss_import_name to implement this
+ * function.
+ *
+ * We allow a NULL output_name, in which case we modify the
+ * input_name to include the mechanism specific name.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+static OM_uint32
+val_canon_name_args(
+ OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ const gss_OID mech_type,
+ gss_name_t *output_name)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_name != NULL)
+ *output_name = GSS_C_NO_NAME;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_name == GSS_C_NO_NAME || mech_type == GSS_C_NULL_OID)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_canonicalize_name(minor_status,
+ input_name,
+ mech_type,
+ output_name)
+OM_uint32 *minor_status;
+const gss_name_t input_name;
+const gss_OID mech_type;
+gss_name_t *output_name;
+{
+ gss_union_name_t in_union, out_union = NULL, dest_union = NULL;
+ OM_uint32 major_status = GSS_S_FAILURE, tmpmin;
+ gss_OID selected_mech;
+
+ major_status = val_canon_name_args(minor_status,
+ input_name,
+ mech_type,
+ output_name);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ major_status = gssint_select_mech_type(minor_status, mech_type,
+ &selected_mech);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ /* Initial value needed below. */
+ major_status = GSS_S_FAILURE;
+
+ in_union = (gss_union_name_t)input_name;
+ /*
+ * If the caller wants to reuse the name, and the name has already
+ * been converted, then there is nothing for us to do.
+ */
+ if (!output_name && in_union->mech_type &&
+ g_OID_equal(in_union->mech_type, selected_mech))
+ return (GSS_S_COMPLETE);
+
+ /* ok, then we need to do something - start by creating data struct */
+ if (output_name) {
+ out_union =
+ (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+ if (!out_union)
+ goto allocation_failure;
+
+ out_union->mech_type = 0;
+ out_union->mech_name = 0;
+ out_union->name_type = 0;
+ out_union->external_name = 0;
+ out_union->loopback = out_union;
+
+ /* Allocate the buffer for the user specified representation */
+ if (gssint_create_copy_buffer(in_union->external_name,
+ &out_union->external_name, 1))
+ goto allocation_failure;
+
+ if (in_union->name_type != GSS_C_NULL_OID) {
+ major_status = generic_gss_copy_oid(minor_status,
+ in_union->name_type,
+ &out_union->name_type);
+ if (major_status) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ }
+
+ }
+
+ /*
+ * might need to delete any old mechanism names if we are
+ * reusing the buffer.
+ */
+ if (!output_name) {
+ if (in_union->mech_type) {
+ (void) gssint_release_internal_name(minor_status,
+ in_union->mech_type,
+ &in_union->mech_name);
+ (void) gss_release_oid(minor_status,
+ &in_union->mech_type);
+ in_union->mech_type = 0;
+ }
+ dest_union = in_union;
+ } else
+ dest_union = out_union;
+
+ /* now let's create the new mech name */
+ if ((major_status = generic_gss_copy_oid(minor_status, selected_mech,
+ &dest_union->mech_type))) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+
+ if ((major_status =
+ gssint_import_internal_name(minor_status, selected_mech,
+ in_union,
+ &dest_union->mech_name)))
+ goto allocation_failure;
+
+ if (output_name)
+ *output_name = (gss_name_t)dest_union;
+
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ if (out_union) {
+ /* Release the partly constructed out_union. */
+ gss_name_t name = (gss_name_t)out_union;
+ (void) gss_release_name(&tmpmin, &name);
+ } else if (!output_name) {
+ /* Release only the mech name fields in in_union. */
+ if (in_union->mech_name) {
+ (void) gssint_release_internal_name(&tmpmin,
+ dest_union->mech_type,
+ &dest_union->mech_name);
+ }
+ if (in_union->mech_type)
+ (void) gss_release_oid(&tmpmin, &dest_union->mech_type);
+ }
+
+ return (major_status);
+} /********** gss_canonicalize_name ********/
diff --git a/src/lib/gssapi/mechglue/g_compare_name.c b/src/lib/gssapi/mechglue/g_compare_name.c
new file mode 100644
index 000000000000..af2e76bbdabd
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_compare_name.c
@@ -0,0 +1,210 @@
+/* #pragma ident "@(#)g_compare_name.c 1.16 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_compare_name
+ *
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_comp_name_args(
+ OM_uint32 *minor_status,
+ gss_name_t name1,
+ gss_name_t name2,
+ int *name_equal)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ /* Validate arguments. */
+
+ if (name1 == GSS_C_NO_NAME || name2 == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (name_equal == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_compare_name (minor_status,
+ name1,
+ name2,
+ name_equal)
+
+OM_uint32 * minor_status;
+gss_name_t name1;
+gss_name_t name2;
+int * name_equal;
+
+{
+ OM_uint32 major_status, temp_minor;
+ gss_union_name_t union_name1, union_name2;
+ gss_mechanism mech = NULL;
+ gss_name_t internal_name;
+
+ major_status = val_comp_name_args(minor_status,
+ name1, name2, name_equal);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ union_name1 = (gss_union_name_t) name1;
+ union_name2 = (gss_union_name_t) name2;
+ /*
+ * Try our hardest to make union_name1 be the mechanism-specific
+ * name. (Of course we can't if both names aren't
+ * mechanism-specific.)
+ */
+ if (union_name1->mech_type == 0) {
+ union_name1 = (gss_union_name_t) name2;
+ union_name2 = (gss_union_name_t) name1;
+ }
+ /*
+ * If union_name1 is mechanism specific, then fetch its mechanism
+ * information.
+ */
+ if (union_name1->mech_type) {
+ mech = gssint_get_mechanism (union_name1->mech_type);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+ if (!mech->gss_compare_name)
+ return (GSS_S_UNAVAILABLE);
+ }
+
+ *name_equal = 0; /* Default to *not* equal.... */
+
+ /*
+ * First case... both names are mechanism-specific
+ */
+ if (union_name1->mech_type && union_name2->mech_type) {
+ if (!g_OID_equal(union_name1->mech_type, union_name2->mech_type))
+ return (GSS_S_COMPLETE);
+ if ((union_name1->mech_name == 0) || (union_name2->mech_name == 0))
+ /* should never happen */
+ return (GSS_S_BAD_NAME);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+ if (!mech->gss_compare_name)
+ return (GSS_S_UNAVAILABLE);
+ major_status = mech->gss_compare_name(minor_status,
+ union_name1->mech_name,
+ union_name2->mech_name,
+ name_equal);
+ if (major_status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return major_status;
+ }
+
+ /*
+ * Second case... both names are NOT mechanism specific.
+ *
+ * All we do here is make sure the two name_types are equal and then
+ * that the external_names are equal. Note the we do not take care
+ * of the case where two different external names map to the same
+ * internal name. We cannot determine this, since we as yet do not
+ * know what mechanism to use for calling the underlying
+ * gss_import_name().
+ */
+ if (!union_name1->mech_type && !union_name2->mech_type) {
+ /*
+ * Second case, first sub-case... one name has null
+ * name_type, the other doesn't.
+ *
+ * Not knowing a mech_type we can't import the name with
+ * null name_type so we can't compare.
+ */
+ if ((union_name1->name_type == GSS_C_NULL_OID &&
+ union_name2->name_type != GSS_C_NULL_OID) ||
+ (union_name1->name_type != GSS_C_NULL_OID &&
+ union_name2->name_type == GSS_C_NULL_OID))
+ return (GSS_S_COMPLETE);
+ /*
+ * Second case, second sub-case... both names have
+ * name_types, but they are different.
+ */
+ if ((union_name1->name_type != GSS_C_NULL_OID &&
+ union_name2->name_type != GSS_C_NULL_OID) &&
+ !g_OID_equal(union_name1->name_type,
+ union_name2->name_type))
+ return (GSS_S_COMPLETE);
+ /*
+ * Second case, third sub-case... both names have equal
+ * name_types (and both have no mech_types) so we just
+ * compare the external_names.
+ */
+ if ((union_name1->external_name->length !=
+ union_name2->external_name->length) ||
+ (memcmp(union_name1->external_name->value,
+ union_name2->external_name->value,
+ union_name1->external_name->length) != 0))
+ return (GSS_S_COMPLETE);
+ *name_equal = 1;
+ return (GSS_S_COMPLETE);
+ }
+
+ /*
+ * Final case... one name is mechanism specific, the other isn't.
+ *
+ * We attempt to convert the general name to the mechanism type of
+ * the mechanism-specific name, and then do the compare. If we
+ * can't import the general name, then we return that the name is
+ * _NOT_ equal.
+ */
+ if (union_name2->mech_type) {
+ /* We make union_name1 the mechanism specific name. */
+ union_name1 = (gss_union_name_t) name2;
+ union_name2 = (gss_union_name_t) name1;
+ }
+ major_status = gssint_import_internal_name(minor_status,
+ union_name1->mech_type,
+ union_name2,
+ &internal_name);
+ if (major_status != GSS_S_COMPLETE)
+ return (GSS_S_COMPLETE); /* return complete, but not equal */
+
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+ if (!mech->gss_compare_name)
+ return (GSS_S_UNAVAILABLE);
+ major_status = mech->gss_compare_name(minor_status,
+ union_name1->mech_name,
+ internal_name, name_equal);
+ if (major_status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ gssint_release_internal_name(&temp_minor, union_name1->mech_type,
+ &internal_name);
+ return (major_status);
+
+}
diff --git a/src/lib/gssapi/mechglue/g_complete_auth_token.c b/src/lib/gssapi/mechglue/g_complete_auth_token.c
new file mode 100644
index 000000000000..91815513017f
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_complete_auth_token.c
@@ -0,0 +1,70 @@
+/* #ident "@(#)gss_seal.c 1.10 95/08/07 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_complete_auth_token
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_complete_auth_token (OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech != NULL) {
+ if (mech->gss_complete_auth_token != NULL) {
+ status = mech->gss_complete_auth_token(minor_status,
+ ctx->internal_ctx_id,
+ input_message_buffer);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_COMPLETE;
+ } else
+ status = GSS_S_BAD_MECH;
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c
new file mode 100644
index 000000000000..2ff8d0996ef0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_context_time.c
@@ -0,0 +1,79 @@
+/* #pragma ident "@(#)g_context_time.c 1.12 98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routines for gss_context_time
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_context_time (minor_status,
+ context_handle,
+ time_rec)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+OM_uint32 * time_rec;
+
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (time_rec == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+
+ if (mech->gss_context_time) {
+ status = mech->gss_context_time(
+ minor_status,
+ ctx->internal_ctx_id,
+ time_rec);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
diff --git a/src/lib/gssapi/mechglue/g_decapsulate_token.c b/src/lib/gssapi/mechglue/g_decapsulate_token.c
new file mode 100644
index 000000000000..934d2607cc6c
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_decapsulate_token.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_decapsulate_token(gss_const_buffer_t input_token,
+ gss_const_OID token_oid,
+ gss_buffer_t output_token)
+{
+ OM_uint32 minor;
+ unsigned int body_size = 0;
+ unsigned char *buf_in;
+
+ if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ buf_in = input_token->value;
+
+ minor = g_verify_token_header(token_oid, &body_size, &buf_in,
+ -1, input_token->length,
+ G_VFY_TOKEN_HDR_WRAPPER_REQUIRED);
+ if (minor != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ output_token->value = malloc(body_size);
+ if (output_token->value == NULL)
+ return GSS_S_FAILURE;
+
+ memcpy(output_token->value, buf_in, body_size);
+ output_token->length = body_size;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/mechglue/g_del_name_attr.c b/src/lib/gssapi/mechglue/g_del_name_attr.c
new file mode 100644
index 000000000000..e81e3315ade4
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_del_name_attr.c
@@ -0,0 +1,66 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_delete_name_attribute */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_delete_name_attribute == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_delete_name_attribute)(minor_status,
+ union_name->mech_name,
+ attr);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c
new file mode 100644
index 000000000000..4bf0dec5ce33
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c
@@ -0,0 +1,104 @@
+/* #pragma ident "@(#)g_delete_sec_context.c 1.11 97/11/09 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_delete_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+static OM_uint32
+val_del_sec_ctx_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_delete_sec_context (minor_status,
+ context_handle,
+ output_token)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t * context_handle;
+gss_buffer_t output_token;
+
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+
+ status = val_del_sec_ctx_args(minor_status, context_handle, output_token);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) *context_handle;
+ if (GSSINT_CHK_LOOP(ctx))
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ status = gssint_delete_internal_sec_context(minor_status,
+ ctx->mech_type,
+ &ctx->internal_ctx_id,
+ output_token);
+ if (status)
+ return status;
+
+ /* now free up the space for the union context structure */
+ free(ctx->mech_type->elements);
+ free(ctx->mech_type);
+ free(*context_handle);
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_dsp_name.c b/src/lib/gssapi/mechglue/g_dsp_name.c
new file mode 100644
index 000000000000..21867c814ec5
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_dsp_name.c
@@ -0,0 +1,118 @@
+/* #pragma ident "@(#)g_dsp_name.c 1.13 04/02/23 SMI" */
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_display_name()
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_dsp_name_args(
+ OM_uint32 *minor_status,
+ gss_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_name_buffer != GSS_C_NO_BUFFER) {
+ output_name_buffer->length = 0;
+ output_name_buffer->value = NULL;
+ }
+
+ if (output_name_type != NULL)
+ *output_name_type = GSS_C_NO_OID;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_name_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_display_name (minor_status,
+ input_name,
+ output_name_buffer,
+ output_name_type)
+
+OM_uint32 * minor_status;
+gss_name_t input_name;
+gss_buffer_t output_name_buffer;
+gss_OID * output_name_type;
+
+{
+ OM_uint32 major_status;
+ gss_union_name_t union_name;
+
+ major_status = val_dsp_name_args(minor_status, input_name,
+ output_name_buffer, output_name_type);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ union_name = (gss_union_name_t) input_name;
+
+ if (union_name->mech_type) {
+ /*
+ * OK, we have a mechanism-specific name; let's use it!
+ */
+ return (gssint_display_internal_name(minor_status,
+ union_name->mech_type,
+ union_name->mech_name,
+ output_name_buffer,
+ output_name_type));
+ }
+
+ if ((output_name_buffer->value =
+ gssalloc_malloc(union_name->external_name->length + 1)) == NULL)
+ return (GSS_S_FAILURE);
+ output_name_buffer->length = union_name->external_name->length;
+ (void) memcpy(output_name_buffer->value,
+ union_name->external_name->value,
+ union_name->external_name->length);
+ ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0';
+
+ if (output_name_type != NULL)
+ *output_name_type = union_name->name_type;
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_dsp_name_ext.c b/src/lib/gssapi/mechglue/g_dsp_name_ext.c
new file mode 100644
index 000000000000..be08dd16c4a3
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_dsp_name_ext.c
@@ -0,0 +1,133 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_display_name_ext()
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_dsp_name_ext_args(
+ OM_uint32 *minor_status,
+ gss_name_t input_name,
+ gss_OID display_as_name_type,
+ gss_buffer_t output_name_buffer)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_name_buffer != GSS_C_NO_BUFFER) {
+ output_name_buffer->length = 0;
+ output_name_buffer->value = NULL;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (output_name_buffer == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (input_name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ if (display_as_name_type == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAMETYPE;
+
+ return GSS_S_COMPLETE;
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_display_name_ext (OM_uint32 *minor_status,
+ gss_name_t input_name,
+ gss_OID display_as_name_type,
+ gss_buffer_t output_name_buffer)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ status = val_dsp_name_ext_args(minor_status,
+ input_name,
+ display_as_name_type,
+ output_name_buffer);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ union_name = (gss_union_name_t) input_name;
+
+ if (union_name->mech_type) {
+ mech = gssint_get_mechanism(union_name->mech_type);
+ if (mech == NULL)
+ status = GSS_S_BAD_NAME;
+ else if (mech->gss_display_name_ext == NULL) {
+ if (mech->gss_display_name != NULL &&
+ union_name->name_type != GSS_C_NO_OID &&
+ g_OID_equal(display_as_name_type, union_name->name_type)) {
+ status = (*mech->gss_display_name)(minor_status,
+ union_name->mech_name,
+ output_name_buffer,
+ NULL);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+ } else {
+ status = (*mech->gss_display_name_ext)(minor_status,
+ union_name->mech_name,
+ display_as_name_type,
+ output_name_buffer);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ }
+ return status;
+ }
+
+ if (union_name->name_type == GSS_C_NO_OID ||
+ !g_OID_equal(display_as_name_type, union_name->name_type))
+ return GSS_S_UNAVAILABLE;
+
+ if ((output_name_buffer->value =
+ malloc(union_name->external_name->length + 1)) == NULL) {
+ return GSS_S_FAILURE;
+ }
+ output_name_buffer->length = union_name->external_name->length;
+ (void) memcpy(output_name_buffer->value,
+ union_name->external_name->value,
+ union_name->external_name->length);
+ ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0';
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/mechglue/g_dsp_status.c b/src/lib/gssapi/mechglue/g_dsp_status.c
new file mode 100644
index 000000000000..70e8492636ad
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_dsp_status.c
@@ -0,0 +1,363 @@
+/* #pragma ident "@(#)g_dsp_status.c 1.17 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_display_status
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* local function */
+static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
+
+OM_uint32 KRB5_CALLCONV
+gss_display_status (minor_status,
+ status_value,
+ status_type,
+ req_mech_type,
+ message_context,
+ status_string)
+
+OM_uint32 * minor_status;
+OM_uint32 status_value;
+int status_type;
+gss_OID req_mech_type;
+OM_uint32 * message_context;
+gss_buffer_t status_string;
+
+{
+ gss_OID mech_type = (gss_OID) req_mech_type;
+ gss_mechanism mech;
+ gss_OID_desc m_oid = { 0, 0 };
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (status_string != GSS_C_NO_BUFFER) {
+ status_string->length = 0;
+ status_string->value = NULL;
+ }
+
+ if (minor_status == NULL ||
+ message_context == NULL ||
+ status_string == GSS_C_NO_BUFFER)
+
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /* we handle major status codes, and the mechs do the minor */
+ if (status_type == GSS_C_GSS_CODE)
+ return (displayMajor(status_value, message_context,
+ status_string));
+
+ /*
+ * must be the minor status - let mechs do the work
+ * select the appropriate underlying mechanism routine and
+ * call it.
+ */
+
+ /* In this version, we only handle status codes that have been
+ mapped to a flat numbering space. Look up the value we got
+ passed. If it's not found, complain. */
+ if (status_value == 0) {
+ status_string->value = gssalloc_strdup("Unknown error");
+ if (status_string->value == NULL) {
+ *minor_status = ENOMEM;
+ map_errcode(minor_status);
+ return GSS_S_FAILURE;
+ }
+ status_string->length = strlen(status_string->value);
+ *message_context = 0;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+ {
+ int err;
+ OM_uint32 m_status = 0, status;
+
+ err = gssint_mecherrmap_get(status_value, &m_oid, &m_status);
+ if (err) {
+ *minor_status = err;
+ map_errcode(minor_status);
+ return GSS_S_BAD_STATUS;
+ }
+ if (m_oid.length == 0) {
+ /* Magic flag for com_err values. */
+ status = g_display_com_err_status(minor_status, m_status, status_string);
+ if (status != GSS_S_COMPLETE)
+ map_errcode(minor_status);
+ return status;
+ }
+ mech_type = &m_oid;
+ status_value = m_status;
+ }
+
+ mech = gssint_get_mechanism (mech_type);
+
+ if (mech && mech->gss_display_status) {
+ OM_uint32 r;
+
+ r = mech->gss_display_status(minor_status,
+ status_value, status_type, mech_type,
+ message_context, status_string);
+ /* How's this for weird? If we get an error returning the
+ mechanism-specific error code, we save away the
+ mechanism-specific error code describing the error. */
+ if (r != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return r;
+ }
+
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ return (GSS_S_UNAVAILABLE);
+}
+
+/*
+ * function to map the major error codes
+ * it uses case statements so that the strings could be wrapped by gettext
+ * msgCtxt is interpreted as:
+ * 0 - first call
+ * 1 - routine error
+ * >= 2 - the supplementary error code bit shifted by 1
+ */
+static OM_uint32
+displayMajor(status, msgCtxt, outStr)
+OM_uint32 status;
+OM_uint32 *msgCtxt;
+gss_buffer_t outStr;
+{
+ OM_uint32 oneVal, mask = 0x1, currErr;
+ char *errStr = NULL;
+ int i, haveErr = 0;
+
+ /* take care of the success value first */
+ if (status == GSS_S_COMPLETE)
+ errStr = _("The routine completed successfully");
+ else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
+ switch (oneVal) {
+ case GSS_S_CALL_INACCESSIBLE_READ:
+ errStr = _("A required input parameter could not be "
+ "read");
+ break;
+
+ case GSS_S_CALL_INACCESSIBLE_WRITE:
+ errStr = _("A required output parameter could not be "
+ "written");
+ break;
+
+ case GSS_S_CALL_BAD_STRUCTURE:
+ errStr = _("A parameter was malformed");
+ break;
+
+ default:
+ errStr = _("An invalid status code was supplied");
+ break;
+ }
+
+ /* we now need to determine new value of msgCtxt */
+ if (GSS_ROUTINE_ERROR(status))
+ *msgCtxt = 1;
+ else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+ *msgCtxt = (OM_uint32)(oneVal << 1);
+ else
+ *msgCtxt = 0;
+
+ } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
+ (oneVal = GSS_ROUTINE_ERROR(status))) {
+ switch (oneVal) {
+ case GSS_S_BAD_MECH:
+ errStr = _("An unsupported mechanism was requested");
+ break;
+
+ case GSS_S_BAD_NAME:
+ errStr = _("An invalid name was supplied");
+ break;
+
+ case GSS_S_BAD_NAMETYPE:
+ errStr = _("A supplied name was of an unsupported "
+ "type");
+ break;
+
+ case GSS_S_BAD_BINDINGS:
+ errStr = _("Incorrect channel bindings were supplied");
+ break;
+
+ case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
+ errStr = _("A token had an invalid Message Integrity "
+ "Check (MIC)");
+ break;
+
+ case GSS_S_NO_CRED:
+ errStr = _("No credentials were supplied, or the "
+ "credentials were unavailable or "
+ "inaccessible");
+ break;
+
+ case GSS_S_NO_CONTEXT:
+ errStr = _("No context has been established");
+ break;
+
+ case GSS_S_DEFECTIVE_TOKEN:
+ errStr = _("Invalid token was supplied");
+ break;
+
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ errStr = _("Invalid credential was supplied");
+ break;
+
+ case GSS_S_CREDENTIALS_EXPIRED:
+ errStr = _("The referenced credential has expired");
+ break;
+
+ case GSS_S_CONTEXT_EXPIRED:
+ errStr = _("The referenced context has expired");
+ break;
+
+ case GSS_S_FAILURE:
+ errStr = _("Unspecified GSS failure. Minor code "
+ "may provide more information");
+ break;
+
+ case GSS_S_BAD_QOP:
+ errStr = _("The quality-of-protection (QOP) "
+ "requested could not be provided");
+ break;
+
+ case GSS_S_UNAUTHORIZED:
+ errStr = _("The operation is forbidden by local "
+ "security policy");
+ break;
+
+ case GSS_S_UNAVAILABLE:
+ errStr = _("The operation or option is not "
+ "available or unsupported");
+ break;
+
+ case GSS_S_DUPLICATE_ELEMENT:
+ errStr = _("The requested credential element "
+ "already exists");
+ break;
+
+ case GSS_S_NAME_NOT_MN:
+ errStr = _("The provided name was not mechanism "
+ "specific (MN)");
+ break;
+
+ case GSS_S_BAD_STATUS:
+ default:
+ errStr = _("An invalid status code was supplied");
+ }
+
+ /* we must determine if the caller should call us again */
+ if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+ *msgCtxt = (OM_uint32)(oneVal << 1);
+ else
+ *msgCtxt = 0;
+
+ } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
+ (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
+ /*
+ * if msgCtxt is not 0, then it should encode
+ * the supplementary error code we should be printing
+ */
+ if (*msgCtxt >= 2)
+ oneVal = (OM_uint32) (*msgCtxt) >> 1;
+ else
+ oneVal = GSS_SUPPLEMENTARY_INFO(status);
+
+ /* we display the errors LSB first */
+ for (i = 0; i < 16; i++) {
+ if (oneVal & mask) {
+ haveErr = 1;
+ break;
+ }
+ mask <<= 1;
+ }
+
+ /* isolate the bit or if not found set to illegal value */
+ if (haveErr)
+ currErr = oneVal & mask;
+ else
+ currErr = 1 << 17; /* illegal value */
+
+ switch (currErr) {
+ case GSS_S_CONTINUE_NEEDED:
+ errStr = _("The routine must be called again to "
+ "complete its function");
+ break;
+
+ case GSS_S_DUPLICATE_TOKEN:
+ errStr = _("The token was a duplicate of an earlier "
+ "token");
+ break;
+
+ case GSS_S_OLD_TOKEN:
+ errStr = _("The token's validity period has expired");
+ break;
+
+ case GSS_S_UNSEQ_TOKEN:
+ errStr = _("A later token has already been processed");
+ break;
+
+ case GSS_S_GAP_TOKEN:
+ errStr = _("An expected per-message token was not "
+ "received");
+ break;
+
+ default:
+ errStr = _("An invalid status code was supplied");
+ }
+
+ /*
+ * we must check if there is any other supplementary errors
+ * if found, then turn off current bit, and store next value
+ * in msgCtxt shifted by 1 bit
+ */
+ if (!haveErr)
+ *msgCtxt = 0;
+ else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
+ *msgCtxt = (OM_uint32)
+ ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
+ else
+ *msgCtxt = 0;
+ }
+
+ if (errStr == NULL)
+ errStr = "An invalid status code was supplied";
+
+ /* now copy the status code and return to caller */
+ outStr->length = strlen(errStr);
+ outStr->value = gssalloc_strdup(errStr);
+ if (outStr->value == NULL) {
+ outStr->length = 0;
+ return (GSS_S_FAILURE);
+ }
+
+ return (GSS_S_COMPLETE);
+} /* displayMajor */
diff --git a/src/lib/gssapi/mechglue/g_dup_name.c b/src/lib/gssapi/mechglue/g_dup_name.c
new file mode 100644
index 000000000000..85306fcc1913
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_dup_name.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_dup_name.c 1.14 04/02/23 SMI" */
+
+/*
+ * routine gss_duplicate_name
+ *
+ * This routine does not rely on mechanism implementation of this
+ * name, but instead uses mechanism specific gss_import_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+static OM_uint32
+val_dup_name_args(
+ OM_uint32 *minor_status,
+ const gss_name_t src_name,
+ gss_name_t *dest_name)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (dest_name != NULL)
+ *dest_name = GSS_C_NO_NAME;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /* if output_name is NULL, simply return */
+ if (dest_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (src_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_duplicate_name(minor_status,
+ src_name,
+ dest_name)
+OM_uint32 *minor_status;
+const gss_name_t src_name;
+gss_name_t *dest_name;
+{
+ gss_union_name_t src_union, dest_union;
+ OM_uint32 major_status = GSS_S_FAILURE;
+
+ major_status = val_dup_name_args(minor_status, src_name, dest_name);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ src_union = (gss_union_name_t)src_name;
+
+ /*
+ * First create the union name struct that will hold the external
+ * name and the name type.
+ */
+ dest_union = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+ if (!dest_union)
+ goto allocation_failure;
+
+ dest_union->loopback = 0;
+ dest_union->mech_type = 0;
+ dest_union->mech_name = 0;
+ dest_union->name_type = 0;
+ dest_union->external_name = 0;
+
+ /* Now copy the external representaion */
+ if (gssint_create_copy_buffer(src_union->external_name,
+ &dest_union->external_name, 0))
+ goto allocation_failure;
+
+ if (src_union->name_type != GSS_C_NULL_OID) {
+ major_status = generic_gss_copy_oid(minor_status,
+ src_union->name_type,
+ &dest_union->name_type);
+ if (major_status != GSS_S_COMPLETE) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ }
+
+ /*
+ * See if source name is mechanim specific, if so then need to import it
+ */
+ if (src_union->mech_type) {
+ major_status = generic_gss_copy_oid(minor_status,
+ src_union->mech_type,
+ &dest_union->mech_type);
+ if (major_status != GSS_S_COMPLETE) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+
+ major_status = gssint_import_internal_name(minor_status,
+ src_union->mech_type,
+ src_union,
+ &dest_union->mech_name);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+ }
+
+
+ dest_union->loopback = dest_union;
+ *dest_name = (gss_name_t)dest_union;
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ if (dest_union) {
+ if (dest_union->external_name) {
+ if (dest_union->external_name->value)
+ free(dest_union->external_name->value);
+ free(dest_union->external_name);
+ }
+ if (dest_union->name_type)
+ (void) generic_gss_release_oid(minor_status,
+ &dest_union->name_type);
+ if (dest_union->mech_name)
+ (void) gssint_release_internal_name(minor_status,
+ dest_union->mech_type,
+ &dest_union->mech_name);
+ if (dest_union->mech_type)
+ (void) generic_gss_release_oid(minor_status,
+ &dest_union->mech_type);
+ free(dest_union);
+ }
+ return (major_status);
+} /* gss_duplicate_name */
diff --git a/src/lib/gssapi/mechglue/g_encapsulate_token.c b/src/lib/gssapi/mechglue/g_encapsulate_token.c
new file mode 100644
index 000000000000..6ce0eeb0f5d0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_encapsulate_token.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_encapsulate_token(gss_const_buffer_t input_token,
+ gss_const_OID token_oid,
+ gss_buffer_t output_token)
+{
+ unsigned int tokenSize;
+ unsigned char *buf;
+
+ if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ tokenSize = g_token_size(token_oid, input_token->length);
+
+ assert(tokenSize > 2);
+ tokenSize -= 2; /* TOK_ID */
+
+ output_token->value = malloc(tokenSize);
+ if (output_token->value == NULL)
+ return GSS_S_FAILURE;
+
+ buf = output_token->value;
+
+ g_make_token_header(token_oid, input_token->length, &buf, -1);
+ memcpy(buf, input_token->value, input_token->length);
+ output_token->length = tokenSize;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c
new file mode 100644
index 000000000000..b63745299f64
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c
@@ -0,0 +1,144 @@
+/* #pragma ident "@(#)g_exp_sec_context.c 1.14 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_export_sec_context
+ */
+#ifndef LEAN_CLIENT
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_exp_sec_ctx_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (interprocess_token != GSS_C_NO_BUFFER) {
+ interprocess_token->length = 0;
+ interprocess_token->value = NULL;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (interprocess_token == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_export_sec_context(minor_status,
+ context_handle,
+ interprocess_token)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t * context_handle;
+gss_buffer_t interprocess_token;
+
+{
+ OM_uint32 status;
+ OM_uint32 length;
+ gss_union_ctx_id_t ctx = NULL;
+ gss_mechanism mech;
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ char *buf;
+
+ status = val_exp_sec_ctx_args(minor_status,
+ context_handle, interprocess_token);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) *context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ if (!mech->gss_export_sec_context)
+ return (GSS_S_UNAVAILABLE);
+
+ status = mech->gss_export_sec_context(minor_status,
+ &ctx->internal_ctx_id, &token);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto cleanup;
+ }
+
+ length = token.length + 4 + ctx->mech_type->length;
+ interprocess_token->length = length;
+ interprocess_token->value = malloc(length);
+ if (interprocess_token->value == 0) {
+ *minor_status = ENOMEM;
+ status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ buf = interprocess_token->value;
+ length = ctx->mech_type->length;
+ buf[3] = (unsigned char) (length & 0xFF);
+ length >>= 8;
+ buf[2] = (unsigned char) (length & 0xFF);
+ length >>= 8;
+ buf[1] = (unsigned char) (length & 0xFF);
+ length >>= 8;
+ buf[0] = (unsigned char) (length & 0xFF);
+ memcpy(buf+4, ctx->mech_type->elements, (size_t) ctx->mech_type->length);
+ memcpy(buf+4+ctx->mech_type->length, token.value, token.length);
+
+ status = GSS_S_COMPLETE;
+
+cleanup:
+ (void) gss_release_buffer(minor_status, &token);
+ if (ctx != NULL && ctx->internal_ctx_id == GSS_C_NO_CONTEXT) {
+ /* If the mech deleted its context, delete the union context. */
+ free(ctx->mech_type->elements);
+ free(ctx->mech_type);
+ free(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ return status;
+}
+#endif /*LEAN_CLIENT */
diff --git a/src/lib/gssapi/mechglue/g_export_cred.c b/src/lib/gssapi/mechglue/g_export_cred.c
new file mode 100644
index 000000000000..8f5fe4ad5a2b
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_export_cred.c
@@ -0,0 +1,114 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/mechglue/g_export_cred.c - gss_export_cred definition */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_exp_cred_args(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token)
+{
+
+ /* Initialize outputs. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (token != GSS_C_NO_BUFFER) {
+ token->length = 0;
+ token->value = NULL;
+ }
+
+ /* Validate arguments. */
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
+ if (token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_export_cred(OM_uint32 * minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token)
+{
+ OM_uint32 status, tmpmin;
+ gss_union_cred_t cred;
+ gss_OID mech_oid;
+ gss_OID public_oid;
+ gss_mechanism mech;
+ gss_buffer_desc mech_token;
+ struct k5buf buf;
+ char lenbuf[4];
+ int i;
+
+ status = val_exp_cred_args(minor_status, cred_handle, token);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ k5_buf_init_dynamic(&buf);
+
+ cred = (gss_union_cred_t) cred_handle;
+ for (i = 0; i < cred->count; i++) {
+ /* Get an export token for this mechanism. */
+ mech_oid = &cred->mechs_array[i];
+ public_oid = gssint_get_public_oid(mech_oid);
+ mech = gssint_get_mechanism(mech_oid);
+ if (mech == NULL) {
+ status = GSS_S_DEFECTIVE_CREDENTIAL;
+ goto error;
+ }
+ if (mech->gss_export_cred == NULL) {
+ status = GSS_S_UNAVAILABLE;
+ goto error;
+ }
+ status = mech->gss_export_cred(minor_status, cred->cred_array[i],
+ &mech_token);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto error;
+ }
+
+ /* Append the mech OID and token to buf. */
+ store_32_be(public_oid->length, lenbuf);
+ k5_buf_add_len(&buf, lenbuf, 4);
+ k5_buf_add_len(&buf, public_oid->elements, public_oid->length);
+ store_32_be(mech_token.length, lenbuf);
+ k5_buf_add_len(&buf, lenbuf, 4);
+ k5_buf_add_len(&buf, mech_token.value, mech_token.length);
+ gss_release_buffer(&tmpmin, &mech_token);
+ }
+
+ return k5buf_to_gss(minor_status, &buf, token);
+
+error:
+ k5_buf_free(&buf);
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_export_name.c b/src/lib/gssapi/mechglue/g_export_name.c
new file mode 100644
index 000000000000..c845f8caf70f
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_export_name.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1996,1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* #pragma ident "@(#)g_export_name.c 1.11 00/07/17 SMI" */
+
+/*
+ * glue routine gss_export_name
+ *
+ * Will either call the mechanism defined gss_export_name, or if one is
+ * not defined will call a generic_gss_export_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_export_name(minor_status,
+ input_name,
+ exported_name)
+OM_uint32 * minor_status;
+const gss_name_t input_name;
+gss_buffer_t exported_name;
+{
+ gss_union_name_t union_name;
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (exported_name != GSS_C_NO_BUFFER) {
+ exported_name->value = NULL;
+ exported_name->length = 0;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL || exported_name == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ union_name = (gss_union_name_t)input_name;
+
+ /* the name must be in mechanism specific format */
+ if (!union_name->mech_type)
+ return (GSS_S_NAME_NOT_MN);
+
+ return gssint_export_internal_name(minor_status, union_name->mech_type,
+ union_name->mech_name, exported_name);
+}
diff --git a/src/lib/gssapi/mechglue/g_export_name_comp.c b/src/lib/gssapi/mechglue/g_export_name_comp.c
new file mode 100644
index 000000000000..ab538a095d6a
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_export_name_comp.c
@@ -0,0 +1,72 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ *
+ */
+
+/*
+ * glue routine for gss_export_name_composite
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ if (exp_composite_name == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_export_name_composite == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_export_name_composite)(minor_status,
+ union_name->mech_name,
+ exp_composite_name);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_get_name_attr.c b/src/lib/gssapi/mechglue/g_get_name_attr.c
new file mode 100644
index 000000000000..047d5d428fb0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_get_name_attr.c
@@ -0,0 +1,93 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_get_name_attribute */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ if (attr == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+ if (more == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (authenticated != NULL)
+ *authenticated = 0;
+ if (complete != NULL)
+ *complete = 0;
+ if (value != GSS_C_NO_BUFFER) {
+ value->value = NULL;
+ value->length = 0;
+ }
+ if (display_value != GSS_C_NO_BUFFER) {
+ display_value->value = NULL;
+ display_value->length = 0;
+ }
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_get_name_attribute == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_get_name_attribute)(minor_status,
+ union_name->mech_name,
+ attr,
+ authenticated,
+ complete,
+ value,
+ display_value,
+ more);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c
new file mode 100644
index 000000000000..4aa3591a0d06
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_glue.c
@@ -0,0 +1,752 @@
+/* #pragma ident "@(#)g_glue.c 1.25 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */
+
+extern gss_mechanism *gssint_mechs_array;
+
+/*
+ * This file contains the support routines for the glue layer.
+ */
+
+/*
+ * get_der_length: Givin a pointer to a buffer that contains a DER encoded
+ * length, decode the length updating the buffer to point to the character
+ * after the DER encoding. The parameter bytes will point to the number of
+ * bytes that made up the DER encoding of the length originally pointed to
+ * by the buffer. Note we return -1 on error.
+ */
+int
+gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+{
+ /* p points to the beginning of the buffer */
+ unsigned char *p = *buf;
+ int length, new_length;
+ unsigned int octets;
+
+ if (buf_len < 1)
+ return (-1);
+
+ /* We should have at least one byte */
+ *bytes = 1;
+
+ /*
+ * If the High order bit is not set then the length is just the value
+ * of *p.
+ */
+ if (*p < 128) {
+ *buf = p+1; /* Advance the buffer */
+ return (*p); /* return the length */
+ }
+
+ /*
+ * if the High order bit is set, then the low order bits represent
+ * the number of bytes that contain the DER encoding of the length.
+ */
+
+ octets = *p++ & 0x7f;
+ *bytes += octets;
+
+ /* See if the supplied buffer contains enough bytes for the length. */
+ if (octets > buf_len - 1)
+ return (-1);
+
+ /*
+ * Calculate a multibyte length. The length is encoded as an
+ * unsigned integer base 256.
+ */
+ for (length = 0; octets; octets--) {
+ new_length = (length << 8) + *p++;
+ if (new_length < length) /* overflow */
+ return (-1);
+ length = new_length;
+ }
+
+ *buf = p; /* Advance the buffer */
+
+ return (length);
+}
+
+/*
+ * der_length_size: Return the number of bytes to encode a given length.
+ */
+unsigned int
+gssint_der_length_size(unsigned int len)
+{
+ int i;
+
+ if (len < 128)
+ return (1);
+
+ for (i = 0; len; i++) {
+ len >>= 8;
+ }
+
+ return (i+1);
+}
+
+/*
+ * put_der_length: Encode the supplied length into the buffer pointed to
+ * by buf. max_length represents the maximum length of the buffer pointed
+ * to by buff. We will advance buf to point to the character after the newly
+ * DER encoded length. We return 0 on success or -l it the length cannot
+ * be encoded in max_len characters.
+ */
+int
+gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
+{
+ unsigned char *s, *p;
+ unsigned int buf_len = 0;
+ int i, first;
+
+ /* Oops */
+ if (buf == 0 || max_len < 1)
+ return (-1);
+
+ s = *buf;
+
+ /* Single byte is the length */
+ if (length < 128) {
+ *s++ = length;
+ *buf = s;
+ return (0);
+ }
+
+ /* First byte contains the number of octets */
+ p = s + 1;
+
+ /* Running total of the DER encoding length */
+ buf_len = 0;
+
+ /*
+ * Encode MSB first. We do the encoding by setting a shift
+ * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
+ * by the factor. We then encode the resulting low order byte.
+ * We subtract 8 from the shift factor and repeat to ecnode the next
+ * byte. We stop when the shift factor is zero or we've run out of
+ * buffer to encode into.
+ */
+ first = 0;
+ for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
+ unsigned int v;
+ v = (length >> i) & 0xff;
+ if ((v) || first) {
+ buf_len += 1;
+ *p++ = v;
+ first = 1;
+ }
+ }
+ if (i >= 0) /* buffer overflow */
+ return (-1);
+
+ /*
+ * We go back now and set the first byte to be the length with
+ * the high order bit set.
+ */
+ *s = buf_len | 0x80;
+ *buf = p;
+
+ return (0);
+}
+
+
+/*
+ * glue routine for get_mech_type
+ *
+ */
+
+OM_uint32 gssint_get_mech_type_oid(OID, token)
+ gss_OID OID;
+ gss_buffer_t token;
+{
+ unsigned char * buffer_ptr;
+ int length;
+
+ /*
+ * This routine reads the prefix of "token" in order to determine
+ * its mechanism type. It assumes the encoding suggested in
+ * Appendix B of RFC 1508. This format starts out as follows :
+ *
+ * tag for APPLICATION 0, Sequence[constructed, definite length]
+ * length of remainder of token
+ * tag of OBJECT IDENTIFIER
+ * length of mechanism OID
+ * encoding of mechanism OID
+ * <the rest of the token>
+ *
+ * Numerically, this looks like :
+ *
+ * 0x60
+ * <length> - could be multiple bytes
+ * 0x06
+ * <length> - assume only one byte, hence OID length < 127
+ * <mech OID bytes>
+ *
+ * The routine fills in the OID value and returns an error as necessary.
+ */
+
+ if (OID == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if ((token == NULL) || (token->value == NULL))
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /* Skip past the APP/Sequnce byte and the token length */
+
+ buffer_ptr = (unsigned char *) token->value;
+
+ if (*(buffer_ptr++) != 0x60)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ length = *buffer_ptr++;
+
+ /* check if token length is null */
+ if (length == 0)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ if (length & 0x80) {
+ if ((length & 0x7f) > 4)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ buffer_ptr += length & 0x7f;
+ }
+
+ if (*(buffer_ptr++) != 0x06)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ OID->length = (OM_uint32) *(buffer_ptr++);
+ OID->elements = (void *) buffer_ptr;
+ return (GSS_S_COMPLETE);
+}
+
+/*
+ * The following mechanisms do not always identify themselves
+ * per the GSS-API specification, when interoperating with MS
+ * peers. We include the OIDs here so we do not have to ilnk
+ * with the mechanism.
+ */
+static gss_OID_desc gss_ntlm_mechanism_oid_desc =
+ {10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+ {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+ {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+
+#define NTLMSSP_SIGNATURE "NTLMSSP"
+
+OM_uint32 gssint_get_mech_type(OID, token)
+ gss_OID OID;
+ gss_buffer_t token;
+{
+ /* Check for interoperability exceptions */
+ if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&
+ memcmp(token->value, NTLMSSP_SIGNATURE,
+ sizeof(NTLMSSP_SIGNATURE)) == 0) {
+ *OID = gss_ntlm_mechanism_oid_desc;
+ } else if (token->length != 0 &&
+ ((char *)token->value)[0] == 0x6E) {
+ /* Could be a raw AP-REQ (check for APPLICATION tag) */
+ *OID = gss_krb5_mechanism_oid_desc;
+ } else if (token->length == 0) {
+ *OID = gss_spnego_mechanism_oid_desc;
+ } else {
+ return gssint_get_mech_type_oid(OID, token);
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+import_internal_attributes(OM_uint32 *minor,
+ gss_mechanism dmech,
+ gss_union_name_t sname,
+ gss_name_t dname)
+{
+ OM_uint32 major, tmpMinor;
+ gss_mechanism smech;
+ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
+ size_t i;
+
+ if (sname->mech_name == GSS_C_NO_NAME)
+ return (GSS_S_UNAVAILABLE);
+
+ smech = gssint_get_mechanism (sname->mech_type);
+ if (smech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (smech->gss_inquire_name == NULL ||
+ smech->gss_get_name_attribute == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ if (dmech->gss_set_name_attribute == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ major = smech->gss_inquire_name(minor, sname->mech_name,
+ NULL, NULL, &attrs);
+ if (GSS_ERROR(major) || attrs == GSS_C_NO_BUFFER_SET) {
+ gss_release_buffer_set(&tmpMinor, &attrs);
+ return (major);
+ }
+
+ for (i = 0; i < attrs->count; i++) {
+ int more = -1;
+
+ while (more != 0) {
+ gss_buffer_desc value, display_value;
+ int authenticated, complete;
+
+ major = smech->gss_get_name_attribute(minor, sname->mech_name,
+ &attrs->elements[i],
+ &authenticated, &complete,
+ &value, &display_value,
+ &more);
+ if (GSS_ERROR(major))
+ continue;
+
+ if (authenticated) {
+ dmech->gss_set_name_attribute(minor, dname, complete,
+ &attrs->elements[i], &value);
+ }
+
+ gss_release_buffer(&tmpMinor, &value);
+ gss_release_buffer(&tmpMinor, &display_value);
+ }
+ }
+
+ gss_release_buffer_set(&tmpMinor, &attrs);
+
+ return (GSS_S_COMPLETE);
+}
+
+/*
+ * Internal routines to get and release an internal mechanism name
+ */
+
+OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name,
+ internal_name)
+OM_uint32 *minor_status;
+gss_OID mech_type;
+gss_union_name_t union_name;
+gss_name_t *internal_name;
+{
+ OM_uint32 status, tmpMinor;
+ gss_mechanism mech;
+ gss_OID public_mech;
+
+ mech = gssint_get_mechanism (mech_type);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ /*
+ * If we are importing a name for the same mechanism, and the
+ * mechanism implements gss_duplicate_name, then use that.
+ */
+ if (union_name->mech_type != GSS_C_NO_OID &&
+ union_name->mech_name != GSS_C_NO_NAME &&
+ g_OID_equal(union_name->mech_type, mech_type) &&
+ mech->gss_duplicate_name != NULL) {
+ status = mech->gss_duplicate_name(minor_status,
+ union_name->mech_name,
+ internal_name);
+ if (status != GSS_S_UNAVAILABLE) {
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return (status);
+ }
+ }
+
+ if (mech->gssspi_import_name_by_mech) {
+ public_mech = gssint_get_public_oid(mech_type);
+ status = mech->gssspi_import_name_by_mech(minor_status, public_mech,
+ union_name->external_name,
+ union_name->name_type,
+ internal_name);
+ } else if (mech->gss_import_name) {
+ status = mech->gss_import_name(minor_status, union_name->external_name,
+ union_name->name_type, internal_name);
+ } else {
+ return (GSS_S_UNAVAILABLE);
+ }
+
+ if (status == GSS_S_COMPLETE) {
+ /* Attempt to round-trip attributes */
+ (void) import_internal_attributes(&tmpMinor, mech,
+ union_name, *internal_name);
+ } else {
+ map_error(minor_status, mech);
+ }
+
+ return (status);
+}
+
+OM_uint32 gssint_export_internal_name(minor_status, mech_type,
+ internal_name, name_buf)
+ OM_uint32 *minor_status;
+ const gss_OID mech_type;
+ const gss_name_t internal_name;
+ gss_buffer_t name_buf;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+ gss_buffer_desc dispName;
+ gss_OID nameOid;
+ unsigned char *buf = NULL;
+ const unsigned char tokId[] = "\x04\x01";
+ const unsigned int tokIdLen = 2;
+ const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
+ int mechOidDERLen = 0;
+ int mechOidLen = 0;
+
+ mech = gssint_get_mechanism(mech_type);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_export_name) {
+ status = mech->gss_export_name(minor_status,
+ internal_name,
+ name_buf);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return status;
+ }
+
+ /*
+ * if we are here it is because the mechanism does not provide
+ * a gss_export_name so we will use our implementation. We
+ * do required that the mechanism define a gss_display_name.
+ */
+ if (!mech->gss_display_name)
+ return (GSS_S_UNAVAILABLE);
+
+ /*
+ * NOTE: RFC2743 (section 3.2) governs the format of the outer
+ * wrapper of exported names; the mechanisms' specs govern
+ * the format of the inner portion of the exported name
+ * and, for some (e.g., RFC1964, the Kerberos V mech), a
+ * generic default as implemented here will do.
+ *
+ * The outer wrapper of an exported MN is: 2-octet tok Id
+ * (0x0401) + 2-octet network-byte order mech OID length + mech
+ * oid (in DER format, including DER tag and DER length) +
+ * 4-octet network-byte order length of inner portion + inner
+ * portion.
+ *
+ * For the Kerberos V mechanism the inner portion of an exported
+ * MN is the display name string and ignores the name type OID
+ * altogether. And we hope this will be so for any future
+ * mechanisms also, so that factoring name export/import out of
+ * the mech and into libgss pays off.
+ */
+ if ((status = mech->gss_display_name(minor_status,
+ internal_name,
+ &dispName,
+ &nameOid))
+ != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return (status);
+ }
+
+ /* determine the size of the buffer needed */
+ mechOidDERLen = gssint_der_length_size(mech_type->length);
+ name_buf->length = tokIdLen + mechOidLenLen +
+ mechOidTagLen + mechOidDERLen +
+ mech_type->length +
+ nameLenLen + dispName.length;
+ if ((name_buf->value = (void*)gssalloc_malloc(name_buf->length)) ==
+ (void*)NULL) {
+ name_buf->length = 0;
+ (void) gss_release_buffer(&status, &dispName);
+ return (GSS_S_FAILURE);
+ }
+
+ /* now create the name ..... */
+ buf = (unsigned char *)name_buf->value;
+ (void) memset(name_buf->value, 0, name_buf->length);
+ (void) memcpy(buf, tokId, tokIdLen);
+ buf += tokIdLen;
+
+ /* spec allows only 2 bytes for the mech oid length */
+ mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
+ store_16_be(mechOidLen, buf);
+ buf += 2;
+
+ /*
+ * DER Encoding of mech OID contains OID Tag (0x06), length and
+ * mech OID value
+ */
+ *buf++ = 0x06;
+ if (gssint_put_der_length(mech_type->length, &buf,
+ (name_buf->length - tokIdLen -2)) != 0) {
+ name_buf->length = 0;
+ free(name_buf->value);
+ (void) gss_release_buffer(&status, &dispName);
+ return (GSS_S_FAILURE);
+ }
+
+ (void) memcpy(buf, mech_type->elements, mech_type->length);
+ buf += mech_type->length;
+
+ /* spec designates the next 4 bytes for the name length */
+ store_32_be(dispName.length, buf);
+ buf += 4;
+
+ /* for the final ingredient - add the name from gss_display_name */
+ (void) memcpy(buf, dispName.value, dispName.length);
+
+ /* release the buffer obtained from gss_display_name */
+ (void) gss_release_buffer(minor_status, &dispName);
+ return (GSS_S_COMPLETE);
+} /* gssint_export_internal_name */
+
+OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name,
+ external_name, name_type)
+OM_uint32 *minor_status;
+gss_OID mech_type;
+gss_name_t internal_name;
+gss_buffer_t external_name;
+gss_OID *name_type;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+
+ mech = gssint_get_mechanism (mech_type);
+ if (mech) {
+ if (mech->gss_display_name) {
+ status = mech->gss_display_name (
+ minor_status,
+ internal_name,
+ external_name,
+ name_type);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return (status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name)
+OM_uint32 *minor_status;
+gss_OID mech_type;
+gss_name_t *internal_name;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+
+ mech = gssint_get_mechanism (mech_type);
+ if (mech) {
+ if (mech->gss_release_name) {
+ status = mech->gss_release_name (
+ minor_status,
+ internal_name);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return (status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 gssint_delete_internal_sec_context (minor_status,
+ mech_type,
+ internal_ctx,
+ output_token)
+OM_uint32 *minor_status;
+gss_OID mech_type;
+gss_ctx_id_t *internal_ctx;
+gss_buffer_t output_token;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+
+ mech = gssint_get_mechanism (mech_type);
+ if (mech) {
+ if (mech->gss_delete_sec_context)
+ status = mech->gss_delete_sec_context (minor_status,
+ internal_ctx,
+ output_token);
+ else
+ status = GSS_S_UNAVAILABLE;
+
+ return (status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+/*
+ * This function converts an internal gssapi name to a union gssapi
+ * name. Note that internal_name should be considered "consumed" by
+ * this call, whether or not we return an error.
+ */
+OM_uint32 gssint_convert_name_to_union_name(minor_status, mech,
+ internal_name, external_name)
+ OM_uint32 *minor_status;
+ gss_mechanism mech;
+ gss_name_t internal_name;
+ gss_name_t *external_name;
+{
+ OM_uint32 major_status,tmp;
+ gss_union_name_t union_name;
+
+ union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
+ if (!union_name) {
+ major_status = GSS_S_FAILURE;
+ *minor_status = ENOMEM;
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ union_name->mech_type = 0;
+ union_name->mech_name = internal_name;
+ union_name->name_type = 0;
+ union_name->external_name = 0;
+
+ major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
+ &union_name->mech_type);
+ if (major_status != GSS_S_COMPLETE) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+
+ union_name->external_name =
+ (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
+ if (!union_name->external_name) {
+ major_status = GSS_S_FAILURE;
+ goto allocation_failure;
+ }
+ union_name->external_name->length = 0;
+ union_name->external_name->value = NULL;
+
+ major_status = mech->gss_display_name(minor_status,
+ internal_name,
+ union_name->external_name,
+ &union_name->name_type);
+ if (major_status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto allocation_failure;
+ }
+
+ union_name->loopback = union_name;
+ *external_name = /*(gss_name_t) CHECK */union_name;
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ if (union_name) {
+ if (union_name->external_name) {
+ if (union_name->external_name->value)
+ free(union_name->external_name->value);
+ free(union_name->external_name);
+ }
+ if (union_name->name_type)
+ gss_release_oid(&tmp, &union_name->name_type);
+ if (union_name->mech_type)
+ gss_release_oid(&tmp, &union_name->mech_type);
+ free(union_name);
+ }
+ /*
+ * do as the top comment says - since we are now owners of
+ * internal_name, we must clean it up
+ */
+ if (internal_name)
+ (void) gssint_release_internal_name(&tmp, &mech->mech_type,
+ &internal_name);
+ return (major_status);
+}
+
+/*
+ * Glue routine for returning the mechanism-specific credential from a
+ * external union credential.
+ */
+gss_cred_id_t
+gssint_get_mechanism_cred(union_cred, mech_type)
+ gss_union_cred_t union_cred;
+ gss_OID mech_type;
+{
+ int i;
+
+ if (union_cred == GSS_C_NO_CREDENTIAL)
+ return GSS_C_NO_CREDENTIAL;
+
+ for (i=0; i < union_cred->count; i++) {
+ if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
+ return union_cred->cred_array[i];
+ }
+ return GSS_C_NO_CREDENTIAL;
+}
+
+/*
+ * Routine to create and copy the gss_buffer_desc structure.
+ * Both space for the structure and the data is allocated.
+ */
+OM_uint32
+gssint_create_copy_buffer(srcBuf, destBuf, addNullChar)
+ const gss_buffer_t srcBuf;
+ gss_buffer_t *destBuf;
+ int addNullChar;
+{
+ gss_buffer_t aBuf;
+ unsigned int len;
+
+ if (destBuf == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *destBuf = 0;
+
+ aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+ if (!aBuf)
+ return (GSS_S_FAILURE);
+
+ if (addNullChar)
+ len = srcBuf->length + 1;
+ else
+ len = srcBuf->length;
+
+ if (!(aBuf->value = (void*)gssalloc_malloc(len))) {
+ free(aBuf);
+ return (GSS_S_FAILURE);
+ }
+
+
+ (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
+ aBuf->length = srcBuf->length;
+ *destBuf = aBuf;
+
+ /* optionally add a NULL character */
+ if (addNullChar)
+ ((char *)aBuf->value)[aBuf->length] = '\0';
+
+ return (GSS_S_COMPLETE);
+} /* ****** gssint_create_copy_buffer ****** */
diff --git a/src/lib/gssapi/mechglue/g_imp_cred.c b/src/lib/gssapi/mechglue/g_imp_cred.c
new file mode 100644
index 000000000000..77e2ff55ce57
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_imp_cred.c
@@ -0,0 +1,177 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/mechglue/g_imp_cred.c - gss_import_cred definition */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_imp_cred_args(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle)
+{
+ /* Initialize outputs. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (cred_handle != NULL)
+ *cred_handle = GSS_C_NO_CREDENTIAL;
+
+ /* Validate arguments. */
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ if (cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ if (token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN;
+ if (GSS_EMPTY_BUFFER(token))
+ return GSS_S_DEFECTIVE_TOKEN;
+ return GSS_S_COMPLETE;
+}
+
+/* Populate mech_oid and mech_token with the next entry in token, using aliased
+ * memory from token. Advance token by the amount consumed. */
+static OM_uint32
+get_entry(OM_uint32 *minor_status, gss_buffer_t token, gss_OID mech_oid,
+ gss_buffer_t mech_token)
+{
+ OM_uint32 len;
+
+ /* Get the mechanism OID. */
+ if (token->length < 4)
+ return GSS_S_DEFECTIVE_TOKEN;
+ len = load_32_be(token->value);
+ if (token->length - 4 < len)
+ return GSS_S_DEFECTIVE_TOKEN;
+ mech_oid->length = len;
+ mech_oid->elements = (char *)token->value + 4;
+ token->value = (char *)token->value + 4 + len;
+ token->length -= 4 + len;
+
+ /* Get the mechanism token. */
+ if (token->length < 4)
+ return GSS_S_DEFECTIVE_TOKEN;
+ len = load_32_be(token->value);
+ if (token->length - 4 < len)
+ return GSS_S_DEFECTIVE_TOKEN;
+ mech_token->length = len;
+ mech_token->value = (char *)token->value + 4;
+ token->value = (char *)token->value + 4 + len;
+ token->length -= 4 + len;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle)
+{
+ OM_uint32 status, tmpmin, count;
+ gss_union_cred_t cred = NULL;
+ gss_mechanism mech;
+ gss_buffer_desc tok, mech_token;
+ gss_OID_desc mech_oid;
+ gss_OID selected_mech;
+ gss_cred_id_t mech_cred;
+ void *elemcopy;
+
+ status = val_imp_cred_args(minor_status, token, cred_handle);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ /* Count the entries in token. */
+ for (tok = *token, count = 0; tok.length > 0; count++) {
+ status = get_entry(minor_status, &tok, &mech_oid, &mech_token);
+ if (status != GSS_S_COMPLETE)
+ return status;
+ }
+
+ /* Allocate a union credential. */
+ cred = calloc(1, sizeof(*cred));
+ if (cred == NULL)
+ goto oom;
+ cred->loopback = cred;
+ cred->count = 0;
+ cred->mechs_array = calloc(count, sizeof(*cred->mechs_array));
+ if (cred->mechs_array == NULL)
+ goto oom;
+ cred->cred_array = calloc(count, sizeof(*cred->cred_array));
+ if (cred->cred_array == NULL)
+ goto oom;
+
+ tok = *token;
+ while (tok.length > 0) {
+ (void)get_entry(minor_status, &tok, &mech_oid, &mech_token);
+
+ /* Import this entry's mechanism token. */
+ status = gssint_select_mech_type(minor_status, &mech_oid,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ goto error;
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL || (mech->gss_import_cred == NULL &&
+ mech->gssspi_import_cred_by_mech == NULL)) {
+ status = GSS_S_DEFECTIVE_TOKEN;
+ goto error;
+ }
+ if (mech->gssspi_import_cred_by_mech) {
+ status = mech->gssspi_import_cred_by_mech(minor_status,
+ gssint_get_public_oid(selected_mech),
+ &mech_token, &mech_cred);
+ } else {
+ status = mech->gss_import_cred(minor_status, &mech_token,
+ &mech_cred);
+ }
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto error;
+ }
+
+ /* Add the resulting mechanism cred to the union cred. */
+ elemcopy = malloc(selected_mech->length);
+ if (elemcopy == NULL) {
+ if (mech->gss_release_cred != NULL)
+ mech->gss_release_cred(&tmpmin, &mech_cred);
+ goto oom;
+ }
+ memcpy(elemcopy, selected_mech->elements, selected_mech->length);
+ cred->mechs_array[cred->count].length = selected_mech->length;
+ cred->mechs_array[cred->count].elements = elemcopy;
+ cred->cred_array[cred->count++] = mech_cred;
+ }
+
+ *cred_handle = cred;
+ return GSS_S_COMPLETE;
+
+oom:
+ status = GSS_S_FAILURE;
+ *minor_status = ENOMEM;
+error:
+ (void)gss_release_cred(&tmpmin, &cred);
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_imp_name.c b/src/lib/gssapi/mechglue/g_imp_name.c
new file mode 100644
index 000000000000..374965bc9288
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_imp_name.c
@@ -0,0 +1,387 @@
+/* #pragma ident "@(#)g_imp_name.c 1.26 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_import_name
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+/* local function to import GSS_C_EXPORT_NAME names */
+static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t, gss_OID);
+
+static OM_uint32
+val_imp_name_args(
+ OM_uint32 *minor_status,
+ gss_buffer_t input_name_buffer,
+ gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_name != NULL)
+ *output_name = GSS_C_NO_NAME;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_name_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (input_name_type == GSS_C_NO_OID ||
+ !g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
+ if (input_name_buffer->length == 0)
+ return (GSS_S_BAD_NAME);
+
+ if (input_name_buffer->value == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+static gss_buffer_desc emptyNameBuffer;
+
+OM_uint32 KRB5_CALLCONV
+gss_import_name(minor_status,
+ input_name_buffer,
+ input_name_type,
+ output_name)
+
+OM_uint32 * minor_status;
+gss_buffer_t input_name_buffer;
+gss_OID input_name_type;
+gss_name_t * output_name;
+
+{
+ gss_union_name_t union_name;
+ OM_uint32 tmp, major_status = GSS_S_FAILURE;
+
+ if (input_name_buffer == GSS_C_NO_BUFFER)
+ input_name_buffer = &emptyNameBuffer;
+
+ major_status = val_imp_name_args(minor_status,
+ input_name_buffer, input_name_type,
+ output_name);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ /*
+ * First create the union name struct that will hold the external
+ * name and the name type.
+ */
+ union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
+ if (!union_name)
+ return (GSS_S_FAILURE);
+
+ union_name->loopback = 0;
+ union_name->mech_type = 0;
+ union_name->mech_name = 0;
+ union_name->name_type = 0;
+ union_name->external_name = 0;
+
+ /*
+ * All we do here is record the external name and name_type.
+ * When the name is actually used, the underlying gss_import_name()
+ * is called for the appropriate mechanism. The exception to this
+ * rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is
+ * the case, then we make it MN in this call.
+ */
+ major_status = gssint_create_copy_buffer(input_name_buffer,
+ &union_name->external_name, 0);
+ if (major_status != GSS_S_COMPLETE) {
+ free(union_name);
+ return (major_status);
+ }
+
+ if (input_name_type != GSS_C_NULL_OID) {
+ major_status = generic_gss_copy_oid(minor_status,
+ input_name_type,
+ &union_name->name_type);
+ if (major_status != GSS_S_COMPLETE) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ }
+
+ /*
+ * In MIT Distribution the mechanism is determined from the nametype;
+ * This is not a good idea - first mechanism that supports a given
+ * name type is picked up; later on the caller can request a
+ * different mechanism. So we don't determine the mechanism here. Now
+ * the user level and kernel level import_name routine looks similar
+ * except the kernel routine makes a copy of the nametype structure. We
+ * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
+ */
+ if (input_name_type != GSS_C_NULL_OID &&
+ (g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME) ||
+ g_OID_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT))) {
+ major_status = importExportName(minor_status, union_name, input_name_type);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+ }
+
+ union_name->loopback = union_name;
+ *output_name = (gss_name_t)union_name;
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ if (union_name) {
+ if (union_name->external_name) {
+ if (union_name->external_name->value)
+ free(union_name->external_name->value);
+ free(union_name->external_name);
+ }
+ if (union_name->name_type)
+ generic_gss_release_oid(&tmp, &union_name->name_type);
+ if (union_name->mech_name)
+ gssint_release_internal_name(minor_status, union_name->mech_type,
+ &union_name->mech_name);
+ if (union_name->mech_type)
+ generic_gss_release_oid(&tmp, &union_name->mech_type);
+ free(union_name);
+ }
+ return (major_status);
+}
+
+/*
+ * GSS export name constants
+ */
+static const unsigned int expNameTokIdLen = 2;
+static const unsigned int mechOidLenLen = 2;
+static const unsigned int nameTypeLenLen = 2;
+
+static OM_uint32
+importExportName(minor, unionName, inputNameType)
+ OM_uint32 *minor;
+ gss_union_name_t unionName;
+ gss_OID inputNameType;
+{
+ gss_OID_desc mechOid;
+ gss_buffer_desc expName;
+ unsigned char *buf;
+ gss_mechanism mech;
+ OM_uint32 major, mechOidLen, nameLen, curLength;
+ unsigned int bytes;
+
+ expName.value = unionName->external_name->value;
+ expName.length = unionName->external_name->length;
+
+ curLength = expNameTokIdLen + mechOidLenLen;
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf = (unsigned char *)expName.value;
+ if (buf[0] != 0x04)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if (buf[1] != 0x01 && buf[1] != 0x02) /* allow composite names */
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += expNameTokIdLen;
+
+ /* extract the mechanism oid length */
+ mechOidLen = (*buf++ << 8);
+ mechOidLen |= (*buf++);
+ curLength += mechOidLen;
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ /*
+ * The mechOid itself is encoded in DER format, OID Tag (0x06)
+ * length and the value of mech_OID
+ */
+ if (*buf++ != 0x06)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * mechoid Length is encoded twice; once in 2 bytes as
+ * explained in RFC2743 (under mechanism independent exported
+ * name object format) and once using DER encoding
+ *
+ * We verify both lengths.
+ */
+
+ mechOid.length = gssint_get_der_length(&buf,
+ (expName.length - curLength), &bytes);
+ mechOid.elements = (void *)buf;
+
+ /*
+ * 'bytes' is the length of the DER length, '1' is for the DER
+ * tag for OID
+ */
+ if ((bytes + mechOid.length + 1) != mechOidLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += mechOid.length;
+ if ((mech = gssint_get_mechanism(&mechOid)) == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gssspi_import_name_by_mech == NULL &&
+ mech->gss_import_name == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ /*
+ * we must now determine if we should unwrap the name ourselves
+ * or make the mechanism do it - we should only unwrap it
+ * if we create it; so if mech->gss_export_name == NULL, we must
+ * have created it.
+ */
+ if (mech->gss_export_name) {
+ if (mech->gssspi_import_name_by_mech) {
+ major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,
+ inputNameType,
+ &unionName->mech_name);
+ } else {
+ major = mech->gss_import_name(minor, &expName, inputNameType,
+ &unionName->mech_name);
+ }
+ if (major != GSS_S_COMPLETE)
+ map_error(minor, mech);
+ else {
+ major = generic_gss_copy_oid(minor, &mechOid,
+ &unionName->mech_type);
+ if (major != GSS_S_COMPLETE)
+ map_errcode(minor);
+ }
+ return (major);
+ }
+ /*
+ * we must have exported the name - so we now need to reconstruct it
+ * and call the mechanism to create it
+ *
+ * WARNING: Older versions of gssint_export_internal_name() did
+ * not export names correctly, but now it does. In
+ * order to stay compatible with existing exported
+ * names we must support names exported the broken
+ * way.
+ *
+ * Specifically, gssint_export_internal_name() used to include
+ * the name type OID in the encoding of the exported MN.
+ * Additionally, the Kerberos V mech used to make display names
+ * that included a null terminator which was counted in the
+ * display name gss_buffer_desc.
+ */
+ curLength += 4; /* 4 bytes for name len */
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /* next 4 bytes in the name are the name length */
+ nameLen = load_32_be(buf);
+ buf += 4;
+
+ /*
+ * we use < here because bad code in rpcsec_gss rounds up exported
+ * name token lengths and pads with nulls, otherwise != would be
+ * appropriate
+ */
+ curLength += nameLen; /* this is the total length */
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * We detect broken exported names here: they always start with
+ * a two-octet network-byte order OID length, which is always
+ * less than 256 bytes, so the first octet of the length is
+ * always '\0', which is not allowed in GSS-API display names
+ * (or never occurs in them anyways). Of course, the OID
+ * shouldn't be there, but it is. After the OID (sans DER tag
+ * and length) there's the name itself, though null-terminated;
+ * this null terminator should also not be there, but it is.
+ */
+ if (nameLen > 0 && *buf == '\0') {
+ OM_uint32 nameTypeLen;
+ /* next two bytes are the name oid */
+ if (nameLen < nameTypeLenLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ nameLen -= nameTypeLenLen;
+
+ nameTypeLen = (*buf++) << 8;
+ nameTypeLen |= (*buf++);
+
+ if (nameLen < nameTypeLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += nameTypeLen;
+ nameLen -= nameTypeLen;
+
+ /*
+ * adjust for expected null terminator that should
+ * really not be there
+ */
+ if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
+ nameLen--;
+ }
+
+ /*
+ * Can a name be null? Let the mech decide.
+ *
+ * NOTE: We use GSS_C_NULL_OID as the name type when importing
+ * the unwrapped name. Presumably the exported name had,
+ * prior to being exported been obtained in such a way
+ * that it has been properly perpared ("canonicalized," in
+ * GSS-API terms) accroding to some name type; we cannot
+ * tell what that name type was now, but the name should
+ * need no further preparation other than the lowest
+ * common denominator afforded by the mech to names
+ * imported with GSS_C_NULL_OID. For the Kerberos V mech
+ * this means doing less busywork too (particularly once
+ * IDN is thrown in with Kerberos V extensions).
+ */
+ expName.length = nameLen;
+ expName.value = nameLen ? (void *)buf : NULL;
+ if (mech->gssspi_import_name_by_mech) {
+ major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,
+ GSS_C_NULL_OID,
+ &unionName->mech_name);
+ } else {
+ major = mech->gss_import_name(minor, &expName,
+ GSS_C_NULL_OID, &unionName->mech_name);
+ }
+ if (major != GSS_S_COMPLETE) {
+ map_error(minor, mech);
+ return (major);
+ }
+
+ major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type);
+ if (major != GSS_S_COMPLETE) {
+ map_errcode(minor);
+ }
+ return major;
+} /* importExportName */
diff --git a/src/lib/gssapi/mechglue/g_imp_sec_context.c b/src/lib/gssapi/mechglue/g_imp_sec_context.c
new file mode 100644
index 000000000000..a0e2d71221b6
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_imp_sec_context.c
@@ -0,0 +1,175 @@
+/* #pragma ident "@(#)g_imp_sec_context.c 1.18 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_export_sec_context
+ */
+
+#ifndef LEAN_CLIENT
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_imp_sec_ctx_args(
+ OM_uint32 *minor_status,
+ gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+
+ /* Initialize outputs. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (context_handle != NULL)
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (interprocess_token == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN);
+
+ if (GSS_EMPTY_BUFFER(interprocess_token))
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_import_sec_context(minor_status,
+ interprocess_token,
+ context_handle)
+
+OM_uint32 * minor_status;
+gss_buffer_t interprocess_token;
+gss_ctx_id_t * context_handle;
+
+{
+ OM_uint32 length = 0;
+ OM_uint32 status;
+ char *p;
+ gss_union_ctx_id_t ctx;
+ gss_ctx_id_t mctx;
+ gss_buffer_desc token;
+ gss_OID_desc token_mech;
+ gss_OID selected_mech = GSS_C_NO_OID;
+ gss_OID public_mech;
+ gss_mechanism mech;
+
+ status = val_imp_sec_ctx_args(minor_status,
+ interprocess_token, context_handle);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /* Initial value needed below. */
+ status = GSS_S_FAILURE;
+
+ ctx = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc));
+ if (!ctx)
+ return (GSS_S_FAILURE);
+
+ if (interprocess_token->length >= sizeof (OM_uint32)) {
+ p = interprocess_token->value;
+ length = (OM_uint32)*p++;
+ length = (OM_uint32)(length << 8) + *p++;
+ length = (OM_uint32)(length << 8) + *p++;
+ length = (OM_uint32)(length << 8) + *p++;
+ }
+
+ if (length == 0 ||
+ length > (interprocess_token->length - sizeof (OM_uint32))) {
+ free(ctx);
+ return (GSS_S_CALL_BAD_STRUCTURE | GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ token_mech.length = length;
+ token_mech.elements = p;
+
+ p += length;
+
+ token.length = interprocess_token->length - sizeof (OM_uint32) - length;
+ token.value = p;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ status = gssint_select_mech_type(minor_status, &token_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ goto error_out;
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (!mech) {
+ status = GSS_S_BAD_MECH;
+ goto error_out;
+ }
+ if (!mech->gssspi_import_sec_context_by_mech &&
+ !mech->gss_import_sec_context) {
+ status = GSS_S_UNAVAILABLE;
+ goto error_out;
+ }
+
+ if (generic_gss_copy_oid(minor_status, selected_mech,
+ &ctx->mech_type) != GSS_S_COMPLETE) {
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+
+ if (mech->gssspi_import_sec_context_by_mech) {
+ public_mech = gssint_get_public_oid(selected_mech);
+ status = mech->gssspi_import_sec_context_by_mech(minor_status,
+ public_mech,
+ &token, &mctx);
+ } else {
+ status = mech->gss_import_sec_context(minor_status, &token, &mctx);
+ }
+ if (status == GSS_S_COMPLETE) {
+ ctx->internal_ctx_id = mctx;
+ ctx->loopback = ctx;
+ *context_handle = (gss_ctx_id_t)ctx;
+ return (GSS_S_COMPLETE);
+ }
+ map_error(minor_status, mech);
+ free(ctx->mech_type->elements);
+ free(ctx->mech_type);
+
+error_out:
+ free(ctx);
+ return status;
+}
+#endif /* LEAN_CLIENT */
diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c
new file mode 100644
index 000000000000..9f154b8936d0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_init_sec_context.c
@@ -0,0 +1,254 @@
+/* #pragma ident "@(#)g_init_sec_context.c 1.20 03/10/24 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_init_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+static OM_uint32
+val_init_sec_ctx_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID req_mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (actual_mech_type != NULL)
+ *actual_mech_type = GSS_C_NO_OID;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
+
+ if (target_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (output_token == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_init_sec_context (minor_status,
+ claimant_cred_handle,
+ context_handle,
+ target_name,
+ req_mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec)
+
+OM_uint32 * minor_status;
+gss_cred_id_t claimant_cred_handle;
+gss_ctx_id_t * context_handle;
+gss_name_t target_name;
+gss_OID req_mech_type;
+OM_uint32 req_flags;
+OM_uint32 time_req;
+gss_channel_bindings_t input_chan_bindings;
+gss_buffer_t input_token;
+gss_OID * actual_mech_type;
+gss_buffer_t output_token;
+OM_uint32 * ret_flags;
+OM_uint32 * time_rec;
+
+{
+ OM_uint32 status, temp_minor_status;
+ gss_union_name_t union_name;
+ gss_union_cred_t union_cred;
+ gss_name_t internal_name;
+ gss_union_ctx_id_t union_ctx_id;
+ gss_OID selected_mech;
+ gss_mechanism mech;
+ gss_cred_id_t input_cred_handle;
+
+ status = val_init_sec_ctx_args(minor_status,
+ claimant_cred_handle,
+ context_handle,
+ target_name,
+ req_mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gssint_select_mech_type(minor_status, req_mech_type,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ union_name = (gss_union_name_t)target_name;
+
+ /*
+ * obtain the gss mechanism information for the requested
+ * mechanism. If mech_type is NULL, set it to the resultant
+ * mechanism
+ */
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_init_sec_context == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ /*
+ * If target_name is mechanism_specific, then it must match the
+ * mech_type that we're about to use. Otherwise, do an import on
+ * the external_name form of the target name.
+ */
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type, selected_mech)) {
+ internal_name = union_name->mech_name;
+ } else {
+ if ((status = gssint_import_internal_name(minor_status, selected_mech,
+ union_name,
+ &internal_name)) != GSS_S_COMPLETE)
+ return (status);
+ }
+
+ /*
+ * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
+ * descriptor to hold the mech type information as well as the
+ * underlying mechanism context handle. Otherwise, cast the
+ * value of *context_handle to the union context variable.
+ */
+
+ if(*context_handle == GSS_C_NO_CONTEXT) {
+ status = GSS_S_FAILURE;
+ union_ctx_id = (gss_union_ctx_id_t)
+ malloc(sizeof(gss_union_ctx_id_desc));
+ if (union_ctx_id == NULL)
+ goto end;
+
+ if (generic_gss_copy_oid(&temp_minor_status, selected_mech,
+ &union_ctx_id->mech_type) != GSS_S_COMPLETE) {
+ free(union_ctx_id);
+ goto end;
+ }
+
+ /* copy the supplied context handle */
+ union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
+ } else
+ union_ctx_id = (gss_union_ctx_id_t)*context_handle;
+
+ /*
+ * get the appropriate cred handle from the union cred struct.
+ * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
+ * use the default credential.
+ */
+ union_cred = (gss_union_cred_t) claimant_cred_handle;
+ input_cred_handle = gssint_get_mechanism_cred(union_cred, selected_mech);
+
+ /*
+ * now call the approprate underlying mechanism routine
+ */
+
+ status = mech->gss_init_sec_context(
+ minor_status,
+ input_cred_handle,
+ &union_ctx_id->internal_ctx_id,
+ internal_name,
+ gssint_get_public_oid(selected_mech),
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+
+ if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
+ /*
+ * The spec says the preferred method is to delete all context info on
+ * the first call to init, and on all subsequent calls make the caller
+ * responsible for calling gss_delete_sec_context. However, if the
+ * mechanism decided to delete the internal context, we should also
+ * delete the union context.
+ */
+ map_error(minor_status, mech);
+ if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
+ *context_handle = GSS_C_NO_CONTEXT;
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ free(union_ctx_id->mech_type->elements);
+ free(union_ctx_id->mech_type);
+ free(union_ctx_id);
+ }
+ } else if (*context_handle == GSS_C_NO_CONTEXT) {
+ union_ctx_id->loopback = union_ctx_id;
+ *context_handle = (gss_ctx_id_t)union_ctx_id;
+ }
+
+end:
+ if (union_name->mech_name == NULL ||
+ union_name->mech_name != internal_name) {
+ (void) gssint_release_internal_name(&temp_minor_status,
+ selected_mech, &internal_name);
+ }
+
+ return(status);
+}
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
new file mode 100644
index 000000000000..9197666e1072
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -0,0 +1,1615 @@
+/* #pragma ident "@(#)g_initialize.c 1.36 05/02/02 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * This function will initialize the gssapi mechglue library
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef _WIN32
+#include <glob.h>
+#endif
+
+#define M_DEFAULT "default"
+
+#include "k5-thread.h"
+#include "k5-plugin.h"
+#include "osconf.h"
+#ifdef _GSS_STATIC_LINK
+#include "gssapiP_krb5.h"
+#include "gssapiP_spnego.h"
+#endif
+
+#define MECH_SYM "gss_mech_initialize"
+#define MECH_INTERPOSER_SYM "gss_mech_interposer"
+
+#ifndef MECH_CONF
+#define MECH_CONF "/etc/gss/mech"
+#endif
+#define MECH_CONF_PATTERN MECH_CONF ".d/*.conf"
+
+/* Local functions */
+static void addConfigEntry(const char *oidStr, const char *oid,
+ const char *sharedLib, const char *kernMod,
+ const char *modOptions, const char *modType);
+static gss_mech_info searchMechList(gss_const_OID);
+static void loadConfigFile(const char *);
+#if defined(_WIN32)
+#ifndef MECH_KEY
+#define MECH_KEY "SOFTWARE\\gss\\mech"
+#endif
+static time_t getRegKeyModTime(HKEY hBaseKey, const char *keyPath);
+static time_t getRegConfigModTime(const char *keyPath);
+static void getRegKeyValue(HKEY key, const char *keyPath, const char *valueName, void **data, DWORD *dataLen);
+static void loadConfigFromRegistry(HKEY keyBase, const char *keyPath);
+#endif
+static void updateMechList(void);
+static void initMechList(void);
+static void loadInterMech(gss_mech_info aMech);
+static void freeMechList(void);
+
+static OM_uint32 build_mechSet(void);
+static void free_mechSet(void);
+
+/*
+ * list of mechanism libraries and their entry points.
+ * the list also maintains state of the mech libraries (loaded or not).
+ */
+static gss_mech_info g_mechList = NULL;
+static gss_mech_info g_mechListTail = NULL;
+static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
+static time_t g_confFileModTime = (time_t)0;
+static time_t g_confLastCall = (time_t)0;
+
+static gss_OID_set_desc g_mechSet = { 0, NULL };
+static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+MAKE_INIT_FUNCTION(gssint_mechglue_init);
+MAKE_FINI_FUNCTION(gssint_mechglue_fini);
+
+int
+gssint_mechglue_init(void)
+{
+ int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_init\n");
+#endif
+
+ add_error_table(&et_ggss_error_table);
+
+ err = k5_mutex_finish_init(&g_mechSetLock);
+ err = k5_mutex_finish_init(&g_mechListLock);
+
+#ifdef _GSS_STATIC_LINK
+ err = gss_krb5int_lib_init();
+ err = gss_spnegoint_lib_init();
+#endif
+
+ err = gssint_mecherrmap_init();
+ return err;
+}
+
+void
+gssint_mechglue_fini(void)
+{
+ if (!INITIALIZER_RAN(gssint_mechglue_init) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_fini: skipping\n");
+#endif
+ return;
+ }
+
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_fini\n");
+#endif
+#ifdef _GSS_STATIC_LINK
+ gss_spnegoint_lib_fini();
+ gss_krb5int_lib_fini();
+#endif
+ k5_mutex_destroy(&g_mechSetLock);
+ k5_mutex_destroy(&g_mechListLock);
+ free_mechSet();
+ freeMechList();
+ remove_error_table(&et_ggss_error_table);
+ gssint_mecherrmap_destroy();
+}
+
+int
+gssint_mechglue_initialize_library(void)
+{
+ return CALL_INIT_FUNCTION(gssint_mechglue_init);
+}
+
+/*
+ * function used to reclaim the memory used by a gss_OID structure.
+ * This routine requires direct access to the mechList.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_release_oid(minor_status, oid)
+OM_uint32 *minor_status;
+gss_OID *oid;
+{
+ OM_uint32 major;
+ gss_mech_info aMech;
+
+ if (minor_status == NULL || oid == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = gssint_mechglue_initialize_library();
+ if (*minor_status != 0)
+ return (GSS_S_FAILURE);
+
+ k5_mutex_lock(&g_mechListLock);
+ aMech = g_mechList;
+ while (aMech != NULL) {
+
+ /*
+ * look through the loaded mechanism libraries for
+ * gss_internal_release_oid until one returns success.
+ * gss_internal_release_oid will only return success when
+ * the OID was recognized as an internal mechanism OID. if no
+ * mechanisms recognize the OID, then call the generic version.
+ */
+ if (aMech->mech && aMech->mech->gss_internal_release_oid) {
+ major = aMech->mech->gss_internal_release_oid(
+ minor_status, oid);
+ if (major == GSS_S_COMPLETE) {
+ k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_COMPLETE);
+ }
+ map_error(minor_status, aMech->mech);
+ }
+ aMech = aMech->next;
+ } /* while */
+ k5_mutex_unlock(&g_mechListLock);
+
+ return (generic_gss_release_oid(minor_status, oid));
+} /* gss_release_oid */
+
+/*
+ * Wrapper around inquire_attrs_for_mech to determine whether a mechanism has
+ * the deprecated attribute. Must be called without g_mechSetLock since it
+ * will call into the mechglue.
+ */
+static int
+is_deprecated(gss_OID element)
+{
+ OM_uint32 major, minor;
+ gss_OID_set mech_attrs = GSS_C_NO_OID_SET;
+ int deprecated = 0;
+
+ major = gss_inquire_attrs_for_mech(&minor, element, &mech_attrs, NULL);
+ if (major == GSS_S_COMPLETE) {
+ gss_test_oid_set_member(&minor, (gss_OID)GSS_C_MA_DEPRECATED,
+ mech_attrs, &deprecated);
+ }
+
+ if (mech_attrs != GSS_C_NO_OID_SET)
+ gss_release_oid_set(&minor, &mech_attrs);
+
+ return deprecated;
+}
+
+/*
+ * Removes mechs with the deprecated attribute from an OID set. Must be
+ * called without g_mechSetLock held since it calls into the mechglue.
+ */
+static void
+prune_deprecated(gss_OID_set mech_set)
+{
+ OM_uint32 i, j;
+
+ j = 0;
+ for (i = 0; i < mech_set->count; i++) {
+ if (!is_deprecated(&mech_set->elements[i]))
+ mech_set->elements[j++] = mech_set->elements[i];
+ else
+ gssalloc_free(mech_set->elements[i].elements);
+ }
+ mech_set->count = j;
+}
+
+/*
+ * this function will return an oid set indicating available mechanisms.
+ * The set returned is based on configuration file entries and
+ * NOT on the loaded mechanisms. This function does not check if any
+ * of these can actually be loaded.
+ * Deprecated mechanisms will not be returned.
+ * This routine needs direct access to the mechanism list.
+ * To avoid reading the configuration file each call, we will save a
+ * a mech oid set, and only update it once the file has changed.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs(minorStatus, mechSet_out)
+OM_uint32 *minorStatus;
+gss_OID_set *mechSet_out;
+{
+ OM_uint32 status;
+
+ /* Initialize outputs. */
+
+ if (minorStatus != NULL)
+ *minorStatus = 0;
+
+ if (mechSet_out != NULL)
+ *mechSet_out = GSS_C_NO_OID_SET;
+
+ /* Validate arguments. */
+ if (minorStatus == NULL || mechSet_out == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minorStatus = gssint_mechglue_initialize_library();
+ if (*minorStatus != 0)
+ return (GSS_S_FAILURE);
+
+ if (build_mechSet())
+ return GSS_S_FAILURE;
+
+ /*
+ * need to lock the g_mechSet in case someone tries to update it while
+ * I'm copying it.
+ */
+ k5_mutex_lock(&g_mechSetLock);
+ status = generic_gss_copy_oid_set(minorStatus, &g_mechSet, mechSet_out);
+ k5_mutex_unlock(&g_mechSetLock);
+
+ if (*mechSet_out != GSS_C_NO_OID_SET)
+ prune_deprecated(*mechSet_out);
+
+ return (status);
+} /* gss_indicate_mechs */
+
+
+/* Call with g_mechSetLock held, or during final cleanup. */
+static void
+free_mechSet(void)
+{
+ unsigned int i;
+
+ if (g_mechSet.count != 0) {
+ for (i = 0; i < g_mechSet.count; i++)
+ free(g_mechSet.elements[i].elements);
+ free(g_mechSet.elements);
+ g_mechSet.elements = NULL;
+ g_mechSet.count = 0;
+ }
+}
+
+static OM_uint32
+build_mechSet(void)
+{
+ gss_mech_info mList;
+ size_t i;
+ size_t count;
+ gss_OID curItem;
+
+ /*
+ * lock the mutex since we will be updating
+ * the mechList structure
+ * we need to keep the lock while we build the mechanism list
+ * since we are accessing parts of the mechList which could be
+ * modified.
+ */
+ k5_mutex_lock(&g_mechListLock);
+
+ updateMechList();
+
+ /*
+ * we need to lock the mech set so that no one else will
+ * try to read it as we are re-creating it
+ */
+ k5_mutex_lock(&g_mechSetLock);
+
+ /* if the oid list already exists we must free it first */
+ free_mechSet();
+
+ /* determine how many elements to have in the list */
+ mList = g_mechList;
+ count = 0;
+ while (mList != NULL) {
+ count++;
+ mList = mList->next;
+ }
+
+ /* this should always be true, but.... */
+ if (count > 0) {
+ g_mechSet.elements =
+ (gss_OID) calloc(count, sizeof (gss_OID_desc));
+ if (g_mechSet.elements == NULL) {
+ k5_mutex_unlock(&g_mechSetLock);
+ k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_FAILURE);
+ }
+
+ (void) memset(g_mechSet.elements, 0,
+ count * sizeof (gss_OID_desc));
+
+ /* now copy each oid element */
+ count = 0;
+ for (mList = g_mechList; mList != NULL; mList = mList->next) {
+ /* Don't expose interposer mechanisms. */
+ if (mList->is_interposer)
+ continue;
+ curItem = &(g_mechSet.elements[count]);
+ curItem->elements = (void*)
+ malloc(mList->mech_type->length);
+ if (curItem->elements == NULL) {
+ /*
+ * this is nasty - we must delete the
+ * part of the array already copied
+ */
+ for (i = 0; i < count; i++) {
+ free(g_mechSet.elements[i].
+ elements);
+ }
+ free(g_mechSet.elements);
+ g_mechSet.count = 0;
+ g_mechSet.elements = NULL;
+ k5_mutex_unlock(&g_mechSetLock);
+ k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_FAILURE);
+ }
+ g_OID_copy(curItem, mList->mech_type);
+ count++;
+ }
+ g_mechSet.count = count;
+ }
+
+#if 0
+ g_mechSetTime = fileInfo.st_mtime;
+#endif
+ k5_mutex_unlock(&g_mechSetLock);
+ k5_mutex_unlock(&g_mechListLock);
+
+ return GSS_S_COMPLETE;
+}
+
+
+/*
+ * this function has been added for use by modules that need to
+ * know what (if any) optional parameters are supplied in the
+ * config file (MECH_CONF).
+ * It will return the option string for a specified mechanism.
+ * caller is responsible for freeing the memory
+ */
+char *
+gssint_get_modOptions(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech;
+ char *modOptions = NULL;
+
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
+
+ /* make sure we have fresh data */
+ k5_mutex_lock(&g_mechListLock);
+ updateMechList();
+
+ if ((aMech = searchMechList(oid)) == NULL ||
+ aMech->optionStr == NULL) {
+ k5_mutex_unlock(&g_mechListLock);
+ return (NULL);
+ }
+
+ if (aMech->optionStr)
+ modOptions = strdup(aMech->optionStr);
+ k5_mutex_unlock(&g_mechListLock);
+
+ return (modOptions);
+} /* gssint_get_modOptions */
+
+/* Return the mtime of filename or its eventual symlink target (if it is a
+ * symlink), whichever is larger. Return (time_t)-1 if lstat or stat fails. */
+static time_t
+check_link_mtime(const char *filename, time_t *mtime_out)
+{
+ struct stat st1, st2;
+
+ if (lstat(filename, &st1) != 0)
+ return (time_t)-1;
+ if (!S_ISLNK(st1.st_mode))
+ return st1.st_mtime;
+ if (stat(filename, &st2) != 0)
+ return (time_t)-1;
+ return (st1.st_mtime > st2.st_mtime) ? st1.st_mtime : st2.st_mtime;
+}
+
+/* Load pathname if it is newer than last. Update *highest to the maximum of
+ * its current value and pathname's mod time. */
+static void
+load_if_changed(const char *pathname, time_t last, time_t *highest)
+{
+ time_t mtime;
+
+ mtime = check_link_mtime(pathname, &mtime);
+ if (mtime == (time_t)-1)
+ return;
+ if (mtime > *highest)
+ *highest = mtime;
+ if (mtime > last)
+ loadConfigFile(pathname);
+}
+
+#ifndef _WIN32
+/* Try to load any config files which have changed since the last call. Config
+ * files are MECH_CONF and any files matching MECH_CONF_PATTERN. */
+static void
+loadConfigFiles()
+{
+ glob_t globbuf;
+ time_t highest = 0, now;
+ char **path;
+
+ /* Don't glob and stat more than once per second. */
+ if (time(&now) == (time_t)-1 || now == g_confLastCall)
+ return;
+ g_confLastCall = now;
+
+ load_if_changed(MECH_CONF, g_confFileModTime, &highest);
+
+ memset(&globbuf, 0, sizeof(globbuf));
+ if (glob(MECH_CONF_PATTERN, 0, NULL, &globbuf) == 0) {
+ for (path = globbuf.gl_pathv; *path != NULL; path++)
+ load_if_changed(*path, g_confFileModTime, &highest);
+ }
+ globfree(&globbuf);
+
+ g_confFileModTime = highest;
+}
+#endif
+
+/*
+ * determines if the mechList needs to be updated from file
+ * and performs the update.
+ * this functions must be called with a lock of g_mechListLock
+ */
+static void
+updateMechList(void)
+{
+ gss_mech_info minfo;
+
+#if defined(_WIN32)
+ time_t lastConfModTime = getRegConfigModTime(MECH_KEY);
+ if (g_confFileModTime >= lastConfModTime)
+ return;
+ g_confFileModTime = lastConfModTime;
+ loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);
+ loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);
+#else /* _WIN32 */
+ loadConfigFiles();
+#endif /* !_WIN32 */
+
+ /* Load any unloaded interposer mechanisms immediately, to make sure we
+ * interpose other mechanisms before they are used. */
+ for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {
+ if (minfo->is_interposer && minfo->mech == NULL)
+ loadInterMech(minfo);
+ }
+} /* updateMechList */
+
+/* Update the mech list from system configuration if we have never done so.
+ * Must be invoked with the g_mechListLock mutex held. */
+static void
+initMechList(void)
+{
+ static int lazy_init = 0;
+
+ if (lazy_init == 0) {
+ updateMechList();
+ lazy_init = 1;
+ }
+}
+
+static void
+releaseMechInfo(gss_mech_info *pCf)
+{
+ gss_mech_info cf;
+ OM_uint32 minor_status;
+
+ if (*pCf == NULL) {
+ return;
+ }
+
+ cf = *pCf;
+
+ if (cf->kmodName != NULL)
+ free(cf->kmodName);
+ if (cf->uLibName != NULL)
+ free(cf->uLibName);
+ if (cf->mechNameStr != NULL)
+ free(cf->mechNameStr);
+ if (cf->optionStr != NULL)
+ free(cf->optionStr);
+ if (cf->mech_type != GSS_C_NO_OID &&
+ cf->mech_type != &cf->mech->mech_type)
+ generic_gss_release_oid(&minor_status, &cf->mech_type);
+ if (cf->freeMech)
+ zapfree(cf->mech, sizeof(*cf->mech));
+ if (cf->dl_handle != NULL)
+ krb5int_close_plugin(cf->dl_handle);
+ if (cf->int_mech_type != GSS_C_NO_OID)
+ generic_gss_release_oid(&minor_status, &cf->int_mech_type);
+
+ memset(cf, 0, sizeof(*cf));
+ free(cf);
+
+ *pCf = NULL;
+}
+
+#ifdef _GSS_STATIC_LINK
+/*
+ * Register a mechanism. Called with g_mechListLock held.
+ */
+int
+gssint_register_mechinfo(gss_mech_info template)
+{
+ gss_mech_info cf, new_cf;
+
+ new_cf = calloc(1, sizeof(*new_cf));
+ if (new_cf == NULL) {
+ return ENOMEM;
+ }
+
+ new_cf->dl_handle = template->dl_handle;
+ /* copy mech so we can rewrite canonical mechanism OID */
+ new_cf->mech = (gss_mechanism)calloc(1, sizeof(struct gss_config));
+ if (new_cf->mech == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ *new_cf->mech = *template->mech;
+ if (template->mech_type != NULL)
+ new_cf->mech->mech_type = *(template->mech_type);
+ new_cf->mech_type = &new_cf->mech->mech_type;
+ new_cf->priority = template->priority;
+ new_cf->freeMech = 1;
+ new_cf->next = NULL;
+
+ if (template->kmodName != NULL) {
+ new_cf->kmodName = strdup(template->kmodName);
+ if (new_cf->kmodName == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->uLibName != NULL) {
+ new_cf->uLibName = strdup(template->uLibName);
+ if (new_cf->uLibName == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->mechNameStr != NULL) {
+ new_cf->mechNameStr = strdup(template->mechNameStr);
+ if (new_cf->mechNameStr == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->optionStr != NULL) {
+ new_cf->optionStr = strdup(template->optionStr);
+ if (new_cf->optionStr == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (g_mechList == NULL) {
+ g_mechList = new_cf;
+ g_mechListTail = new_cf;
+ return 0;
+ } else if (new_cf->priority < g_mechList->priority) {
+ new_cf->next = g_mechList;
+ g_mechList = new_cf;
+ return 0;
+ }
+
+ for (cf = g_mechList; cf != NULL; cf = cf->next) {
+ if (cf->next == NULL ||
+ new_cf->priority < cf->next->priority) {
+ new_cf->next = cf->next;
+ cf->next = new_cf;
+ if (g_mechListTail == cf) {
+ g_mechListTail = new_cf;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif /* _GSS_STATIC_LINK */
+
+#define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \
+ do { \
+ struct errinfo errinfo; \
+ \
+ memset(&errinfo, 0, sizeof(errinfo)); \
+ if (krb5int_get_plugin_func(_dl, \
+ #_symbol, \
+ (void (**)())&(_mech)->_symbol, \
+ &errinfo) || errinfo.code) { \
+ (_mech)->_symbol = NULL; \
+ k5_clear_error(&errinfo); \
+ } \
+ } while (0)
+
+/*
+ * If _symbol is undefined in the shared object but the shared object
+ * is linked against the mechanism glue, it's possible for dlsym() to
+ * return the mechanism glue implementation. Guard against that.
+ */
+#define GSS_ADD_DYNAMIC_METHOD_NOLOOP(_dl, _mech, _symbol) \
+ do { \
+ GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol); \
+ if ((_mech)->_symbol == _symbol) \
+ (_mech)->_symbol = NULL; \
+ } while (0)
+
+static gss_mechanism
+build_dynamicMech(void *dl, const gss_OID mech_type)
+{
+ gss_mechanism mech;
+
+ mech = (gss_mechanism)calloc(1, sizeof(*mech));
+ if (mech == NULL) {
+ return NULL;
+ }
+
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_init_sec_context);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_accept_sec_context);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_process_context_token);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_sec_context);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_context_time);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_status);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_indicate_mechs);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_compare_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_sec_context);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_sec_context);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_mech);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_names_for_mech);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_internal_release_oid);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_size_limit);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_localname);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_authorize_localname);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_duplicate_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_sec_context_by_oid);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_oid);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_sec_context_option);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_set_cred_option);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_mech_invoke);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_aead);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_aead);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_iov);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov_length);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_complete_auth_token);
+ /* Services4User (introduced in 1.8) */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_impersonate_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred_impersonate_name);
+ /* Naming extensions (introduced in 1.8) */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name_ext);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_name);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_name_attribute);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_name_attribute);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_name_attribute);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name_composite);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_map_name_to_any);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_any_name_mapping);
+ /* RFC 4401 (introduced in 1.8) */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_pseudo_random);
+ /* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_neg_mechs);
+ /* draft-ietf-sasl-gs2 */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_saslname_for_mech);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_mech_for_saslname);
+ /* RFC 5587 */
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_from);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred_into);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_acquire_cred_with_password);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_cred);
+ GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_sec_context_by_mech);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_name_by_mech);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_cred_by_mech);
+
+ assert(mech_type != GSS_C_NO_OID);
+
+ mech->mech_type = *(mech_type);
+
+ return mech;
+}
+
+#define RESOLVE_GSSI_SYMBOL(_dl, _mech, _psym, _nsym) \
+ do { \
+ struct errinfo errinfo; \
+ memset(&errinfo, 0, sizeof(errinfo)); \
+ if (krb5int_get_plugin_func(_dl, \
+ "gssi" #_nsym, \
+ (void (**)())&(_mech)->_psym \
+ ## _nsym, \
+ &errinfo) || errinfo.code) { \
+ (_mech)->_psym ## _nsym = NULL; \
+ k5_clear_error(&errinfo); \
+ } \
+ } while (0)
+
+/* Build an interposer mechanism function table from dl. */
+static gss_mechanism
+build_interMech(void *dl, const gss_OID mech_type)
+{
+ gss_mechanism mech;
+
+ mech = calloc(1, sizeof(*mech));
+ if (mech == NULL) {
+ return NULL;
+ }
+
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _init_sec_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _accept_sec_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _process_context_token);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_sec_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _context_time);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_status);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _indicate_mechs);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _compare_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_sec_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_sec_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_names_for_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_context);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _internal_release_oid);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_size_limit);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _localname);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _authorize_localname);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _duplicate_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_sec_context_by_oid);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_oid);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_sec_context_option);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _set_cred_option);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _mech_invoke);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_aead);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_aead);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_iov);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov_length);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _complete_auth_token);
+ /* Services4User (introduced in 1.8) */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_impersonate_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred_impersonate_name);
+ /* Naming extensions (introduced in 1.8) */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name_ext);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_name);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_name_attribute);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_name_attribute);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_name_attribute);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name_composite);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _map_name_to_any);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_any_name_mapping);
+ /* RFC 4401 (introduced in 1.8) */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _pseudo_random);
+ /* RFC 4178 (introduced in 1.8; get_neg_mechs not implemented) */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_neg_mechs);
+ /* draft-ietf-sasl-gs2 */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_saslname_for_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_mech_for_saslname);
+ /* RFC 5587 */
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_attrs_for_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_from);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred_into);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_cred);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_sec_context_by_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_name_by_mech);
+ RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_cred_by_mech);
+
+ mech->mech_type = *mech_type;
+ return mech;
+}
+
+/*
+ * Concatenate an interposer mech OID and a real mech OID to create an
+ * identifier for the interposed mech. (The concatenation will not be a valid
+ * DER OID encoding, but the OID is only used internally.)
+ */
+static gss_OID
+interposed_oid(gss_OID pre, gss_OID real)
+{
+ gss_OID o;
+
+ o = (gss_OID)malloc(sizeof(gss_OID_desc));
+ if (!o)
+ return NULL;
+
+ o->length = pre->length + real->length;
+ o->elements = malloc(o->length);
+ if (!o->elements) {
+ free(o);
+ return NULL;
+ }
+
+ memcpy(o->elements, pre->elements, pre->length);
+ memcpy((char *)o->elements + pre->length, real->elements,
+ real->length);
+
+ return o;
+}
+
+static void
+loadInterMech(gss_mech_info minfo)
+{
+ struct plugin_file_handle *dl = NULL;
+ struct errinfo errinfo;
+ gss_OID_set (*isym)(const gss_OID);
+ gss_OID_set list;
+ gss_OID oid;
+ OM_uint32 min;
+ gss_mech_info mi;
+ size_t i;
+
+ memset(&errinfo, 0, sizeof(errinfo));
+
+ if (krb5int_open_plugin(minfo->uLibName, &dl, &errinfo) != 0 ||
+ errinfo.code != 0) {
+#if 0
+ (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+ aMech->uLibName, dlerror());
+#endif
+ return;
+ }
+
+ if (krb5int_get_plugin_func(dl, MECH_INTERPOSER_SYM,
+ (void (**)())&isym, &errinfo) != 0)
+ goto cleanup;
+
+ /* Get a list of mechs to interpose. */
+ list = (*isym)(minfo->mech_type);
+ if (!list)
+ goto cleanup;
+ minfo->mech = build_interMech(dl, minfo->mech_type);
+ if (minfo->mech == NULL)
+ goto cleanup;
+ minfo->freeMech = 1;
+
+ /* Add interposer fields for each interposed mech. */
+ for (i = 0; i < list->count; i++) {
+ /* Skip this mech if it doesn't exist or is already
+ * interposed. */
+ oid = &list->elements[i];
+ mi = searchMechList(oid);
+ if (mi == NULL || mi->int_mech_type != NULL)
+ continue;
+
+ /* Construct a special OID to represent the interposed mech. */
+ mi->int_mech_type = interposed_oid(minfo->mech_type, oid);
+ if (mi->int_mech_type == NULL)
+ continue;
+
+ /* Save an alias to the interposer's function table. */
+ mi->int_mech = minfo->mech;
+ }
+ (void)gss_release_oid_set(&min, &list);
+
+ minfo->dl_handle = dl;
+ dl = NULL;
+
+cleanup:
+#if 0
+ if (aMech->mech == NULL) {
+ (void) syslog(LOG_INFO, "unable to initialize mechanism"
+ " library [%s]\n", aMech->uLibName);
+ }
+#endif
+ if (dl != NULL)
+ krb5int_close_plugin(dl);
+ k5_clear_error(&errinfo);
+}
+
+static void
+freeMechList(void)
+{
+ gss_mech_info cf, next_cf;
+
+ for (cf = g_mechList; cf != NULL; cf = next_cf) {
+ next_cf = cf->next;
+ releaseMechInfo(&cf);
+ }
+}
+
+/*
+ * Determine the mechanism to use for a caller-specified mech OID. For the
+ * real mech OID of an interposed mech, return the interposed OID. For an
+ * interposed mech OID (which an interposer mech uses when re-entering the
+ * mechglue), return the real mech OID. The returned OID is an alias and
+ * should not be modified or freed.
+ */
+OM_uint32
+gssint_select_mech_type(OM_uint32 *minor, gss_const_OID oid,
+ gss_OID *selected_oid)
+{
+ gss_mech_info minfo;
+ OM_uint32 status;
+
+ *selected_oid = GSS_C_NO_OID;
+
+ if (gssint_mechglue_initialize_library() != 0)
+ return GSS_S_FAILURE;
+
+ k5_mutex_lock(&g_mechListLock);
+
+ /* Read conf file at least once so that interposer plugins have a
+ * chance of getting initialized. */
+ initMechList();
+
+ minfo = g_mechList;
+ if (oid == GSS_C_NULL_OID)
+ oid = minfo->mech_type;
+ while (minfo != NULL) {
+ if (g_OID_equal(minfo->mech_type, oid)) {
+ if (minfo->int_mech_type != GSS_C_NO_OID)
+ *selected_oid = minfo->int_mech_type;
+ else
+ *selected_oid = minfo->mech_type;
+ status = GSS_S_COMPLETE;
+ goto done;
+ } else if ((minfo->int_mech_type != GSS_C_NO_OID) &&
+ (g_OID_equal(minfo->int_mech_type, oid))) {
+ *selected_oid = minfo->mech_type;
+ status = GSS_S_COMPLETE;
+ goto done;
+ }
+ minfo = minfo->next;
+ }
+ status = GSS_S_BAD_MECH;
+
+done:
+ k5_mutex_unlock(&g_mechListLock);
+ return status;
+}
+
+/* If oid is an interposed OID, return the corresponding real mech OID. If
+ * it's a real mech OID, return it unmodified. Otherwised return null. */
+gss_OID
+gssint_get_public_oid(gss_const_OID oid)
+{
+ gss_mech_info minfo;
+ gss_OID public_oid = GSS_C_NO_OID;
+
+ /* if oid is null -> then get default which is the first in the list */
+ if (oid == GSS_C_NO_OID)
+ return GSS_C_NO_OID;
+
+ if (gssint_mechglue_initialize_library() != 0)
+ return GSS_C_NO_OID;
+
+ k5_mutex_lock(&g_mechListLock);
+
+ for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {
+ if (minfo->is_interposer)
+ continue;
+ if (g_OID_equal(minfo->mech_type, oid) ||
+ ((minfo->int_mech_type != GSS_C_NO_OID) &&
+ (g_OID_equal(minfo->int_mech_type, oid)))) {
+ public_oid = minfo->mech_type;
+ break;
+ }
+ }
+
+ k5_mutex_unlock(&g_mechListLock);
+ return public_oid;
+}
+
+/* Translate a vector of oids (as from a union cred struct) into a set of
+ * public OIDs using gssint_get_public_oid. */
+OM_uint32
+gssint_make_public_oid_set(OM_uint32 *minor_status, gss_OID oids, int count,
+ gss_OID_set *public_set)
+{
+ OM_uint32 status, tmpmin;
+ gss_OID_set set;
+ gss_OID public_oid;
+ int i;
+
+ *public_set = GSS_C_NO_OID_SET;
+
+ status = generic_gss_create_empty_oid_set(minor_status, &set);
+ if (GSS_ERROR(status))
+ return status;
+
+ for (i = 0; i < count; i++) {
+ public_oid = gssint_get_public_oid(&oids[i]);
+ if (public_oid == GSS_C_NO_OID)
+ continue;
+ status = generic_gss_add_oid_set_member(minor_status,
+ public_oid, &set);
+ if (GSS_ERROR(status)) {
+ (void) generic_gss_release_oid_set(&tmpmin, &set);
+ return status;
+ }
+ }
+
+ *public_set = set;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Register a mechanism. Called with g_mechListLock held.
+ */
+
+/*
+ * given the mechanism type, return the mechanism structure
+ * containing the mechanism library entry points.
+ * will return NULL if mech type is not found
+ * This function will also trigger the loading of the mechanism
+ * module if it has not been already loaded.
+ */
+gss_mechanism
+gssint_get_mechanism(gss_const_OID oid)
+{
+ gss_mech_info aMech;
+ gss_mechanism (*sym)(const gss_OID);
+ struct plugin_file_handle *dl;
+ struct errinfo errinfo;
+
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
+
+ k5_mutex_lock(&g_mechListLock);
+
+ /* Check if the mechanism is already loaded. */
+ aMech = g_mechList;
+ if (oid == GSS_C_NULL_OID)
+ oid = aMech->mech_type;
+ while (aMech != NULL) {
+ if (g_OID_equal(aMech->mech_type, oid) && aMech->mech) {
+ k5_mutex_unlock(&g_mechListLock);
+ return aMech->mech;
+ } else if (aMech->int_mech_type != GSS_C_NO_OID &&
+ g_OID_equal(aMech->int_mech_type, oid)) {
+ k5_mutex_unlock(&g_mechListLock);
+ return aMech->int_mech;
+ }
+ aMech = aMech->next;
+ }
+
+ /*
+ * might need to re-read the configuration file before loading
+ * the mechanism to ensure we have the latest info.
+ */
+ updateMechList();
+
+ aMech = searchMechList(oid);
+
+ /* is the mechanism present in the list ? */
+ if (aMech == NULL) {
+ k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ /* has another thread loaded the mech */
+ if (aMech->mech) {
+ k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
+ }
+
+ memset(&errinfo, 0, sizeof(errinfo));
+
+ if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
+ errinfo.code != 0) {
+#if 0
+ (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+ aMech->uLibName, dlerror());
+#endif
+ k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)())&sym,
+ &errinfo) == 0) {
+ /* Call the symbol to get the mechanism table */
+ aMech->mech = (*sym)(aMech->mech_type);
+ } else {
+ /* Try dynamic dispatch table */
+ aMech->mech = build_dynamicMech(dl, aMech->mech_type);
+ aMech->freeMech = 1;
+ }
+ if (aMech->mech == NULL) {
+ (void) krb5int_close_plugin(dl);
+#if 0
+ (void) syslog(LOG_INFO, "unable to initialize mechanism"
+ " library [%s]\n", aMech->uLibName);
+#endif
+ k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ aMech->dl_handle = dl;
+
+ k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
+} /* gssint_get_mechanism */
+
+/*
+ * this routine is used for searching the list of mechanism data.
+ *
+ * this needs to be called with g_mechListLock held.
+ */
+static gss_mech_info searchMechList(gss_const_OID oid)
+{
+ gss_mech_info aMech = g_mechList;
+
+ /* if oid is null -> then get default which is the first in the list */
+ if (oid == GSS_C_NULL_OID)
+ return (aMech);
+
+ while (aMech != NULL) {
+ if (g_OID_equal(aMech->mech_type, oid))
+ return (aMech);
+ aMech = aMech->next;
+ }
+
+ /* none found */
+ return ((gss_mech_info) NULL);
+} /* searchMechList */
+
+/* Return the first non-whitespace character starting from str. */
+static char *
+skip_whitespace(char *str)
+{
+ while (isspace(*str))
+ str++;
+ return str;
+}
+
+/* Truncate str at the first whitespace character and return the first
+ * non-whitespace character after that point. */
+static char *
+delimit_ws(char *str)
+{
+ while (*str != '\0' && !isspace(*str))
+ str++;
+ if (*str != '\0')
+ *str++ = '\0';
+ return skip_whitespace(str);
+}
+
+/* Truncate str at the first occurrence of delimiter and return the first
+ * non-whitespace character after that point. */
+static char *
+delimit(char *str, char delimiter)
+{
+ while (*str != '\0' && *str != delimiter)
+ str++;
+ if (*str != '\0')
+ *str++ = '\0';
+ return skip_whitespace(str);
+}
+
+/*
+ * loads the configuration file
+ * this is called while having a mutex lock on the mechanism list
+ * entries for libraries that have been loaded can't be modified
+ * mechNameStr and mech_type fields are not updated during updates
+ */
+static void
+loadConfigFile(const char *fileName)
+{
+ char *sharedLib, *kernMod, *modOptions, *modType, *oid, *next;
+ char buffer[BUFSIZ], *oidStr;
+ FILE *confFile;
+
+ if ((confFile = fopen(fileName, "r")) == NULL) {
+ return;
+ }
+
+ (void) memset(buffer, 0, sizeof (buffer));
+ while (fgets(buffer, BUFSIZ, confFile) != NULL) {
+
+ /* ignore lines beginning with # */
+ if (*buffer == '#')
+ continue;
+
+ /* Parse out the name, oid, and shared library path. */
+ oidStr = buffer;
+ oid = delimit_ws(oidStr);
+ if (*oid == '\0')
+ continue;
+ sharedLib = delimit_ws(oid);
+ if (*sharedLib == '\0')
+ continue;
+ next = delimit_ws(sharedLib);
+
+ /* Parse out the kernel module name if present. */
+ if (*next != '\0' && *next != '[' && *next != '<') {
+ kernMod = next;
+ next = delimit_ws(kernMod);
+ } else {
+ kernMod = NULL;
+ }
+
+ /* Parse out the module options if present. */
+ if (*next == '[') {
+ modOptions = next + 1;
+ next = delimit(modOptions, ']');
+ } else {
+ modOptions = NULL;
+ }
+
+ /* Parse out the module type if present. */
+ if (*next == '<') {
+ modType = next + 1;
+ (void)delimit(modType, '>');
+ } else {
+ modType = NULL;
+ }
+
+ addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
+ modType);
+ } /* while */
+ (void) fclose(confFile);
+} /* loadConfigFile */
+
+#if defined(_WIN32)
+
+static time_t
+filetimeToTimet(const FILETIME *ft)
+{
+ ULARGE_INTEGER ull;
+
+ ull.LowPart = ft->dwLowDateTime;
+ ull.HighPart = ft->dwHighDateTime;
+ return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
+}
+
+static time_t
+getRegConfigModTime(const char *keyPath)
+{
+ time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER,
+ keyPath);
+ time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE,
+ keyPath);
+
+ return currentUserModTime > localMachineModTime ? currentUserModTime :
+ localMachineModTime;
+}
+
+static time_t
+getRegKeyModTime(HKEY hBaseKey, const char *keyPath)
+{
+ HKEY hConfigKey;
+ HRESULT rc;
+ int iSubKey = 0;
+ time_t modTime = 0, keyModTime;
+ FILETIME keyLastWriteTime;
+ char subKeyName[256];
+
+ if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS,
+ &hConfigKey)) != ERROR_SUCCESS) {
+ /* TODO: log error message */
+ return 0;
+ }
+ do {
+ int subKeyNameSize=sizeof(subKeyName)/sizeof(subKeyName[0]);
+ if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName,
+ &subKeyNameSize, NULL, NULL, NULL,
+ &keyLastWriteTime)) != ERROR_SUCCESS) {
+ break;
+ }
+ keyModTime = filetimeToTimet(&keyLastWriteTime);
+ if (modTime < keyModTime) {
+ modTime = keyModTime;
+ }
+ } while (1);
+ RegCloseKey(hConfigKey);
+ return modTime;
+}
+
+static void
+getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName,
+ void **data, DWORD* dataLen)
+{
+ DWORD sizeRequired=*dataLen;
+ HRESULT hr;
+ /* Get data length required */
+ if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
+ NULL, &sizeRequired)) != ERROR_SUCCESS) {
+ /* TODO: LOG registry error */
+ return;
+ }
+ /* adjust data buffer size if necessary */
+ if (*dataLen < sizeRequired) {
+ *dataLen = sizeRequired;
+ *data = realloc(*data, sizeRequired);
+ if (!*data) {
+ *dataLen = 0;
+ /* TODO: LOG OOM ERROR! */
+ return;
+ }
+ }
+ /* get data */
+ if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
+ *data, &sizeRequired)) != ERROR_SUCCESS) {
+ /* LOG registry error */
+ return;
+ }
+}
+
+static void
+loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
+{
+ HKEY hConfigKey;
+ DWORD iSubKey, nSubKeys, maxSubKeyNameLen, modTypeLen;
+ char *oidStr = NULL, *oid = NULL, *sharedLib = NULL, *kernMod = NULL;
+ char *modOptions = NULL, *modType = NULL;
+ DWORD oidStrLen = 0, oidLen = 0, sharedLibLen = 0, kernModLen = 0;
+ DWORD modOptionsLen = 0;
+ HRESULT rc;
+
+ if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0,
+ KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,
+ &hConfigKey)) != ERROR_SUCCESS) {
+ /* TODO: log registry error */
+ return;
+ }
+
+ if ((rc = RegQueryInfoKey(hConfigKey,
+ NULL, /* lpClass */
+ NULL, /* lpcClass */
+ NULL, /* lpReserved */
+ &nSubKeys,
+ &maxSubKeyNameLen,
+ NULL, /* lpcMaxClassLen */
+ NULL, /* lpcValues */
+ NULL, /* lpcMaxValueNameLen */
+ NULL, /* lpcMaxValueLen */
+ NULL, /* lpcbSecurityDescriptor */
+ NULL /* lpftLastWriteTime */ )) != ERROR_SUCCESS) {
+ goto cleanup;
+ }
+ oidStr = malloc(++maxSubKeyNameLen);
+ if (!oidStr) {
+ goto cleanup;
+ }
+ for (iSubKey=0; iSubKey<nSubKeys; iSubKey++) {
+ oidStrLen = maxSubKeyNameLen;
+ if ((rc = RegEnumKeyEx(hConfigKey, iSubKey, oidStr, &oidStrLen,
+ NULL, NULL, NULL, NULL)) !=
+ ERROR_SUCCESS) {
+ /* TODO: log registry error */
+ continue;
+ }
+ getRegKeyValue(hConfigKey, oidStr, "OID", &oid, &oidLen);
+ getRegKeyValue(hConfigKey, oidStr, "Shared Library",
+ &sharedLib, &sharedLibLen);
+ getRegKeyValue(hConfigKey, oidStr, "Kernel Module", &kernMod,
+ &kernModLen);
+ getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,
+ &modOptionsLen);
+ getRegKeyValue(hConfigKey, oidStr, "Type", &modType,
+ &modTypeLen);
+ addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
+ modType);
+ }
+cleanup:
+ RegCloseKey(hConfigKey);
+ if (oidStr) {
+ free(oidStr);
+ }
+ if (oid) {
+ free(oid);
+ }
+ if (sharedLib) {
+ free(sharedLib);
+ }
+ if (kernMod) {
+ free(kernMod);
+ }
+ if (modOptions) {
+ free(modOptions);
+ }
+}
+#endif
+
+static void
+addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
+ const char *kernMod, const char *modOptions,
+ const char *modType)
+{
+#if defined(_WIN32)
+ const char *sharedPath;
+#else
+ char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
+#endif
+ char *tmpStr;
+ gss_OID mechOid;
+ gss_mech_info aMech, tmp;
+ OM_uint32 minor;
+ gss_buffer_desc oidBuf;
+
+ if ((!oid) || (!oidStr)) {
+ return;
+ }
+ /*
+ * check if an entry for this oid already exists
+ * if it does, and the library is already loaded then
+ * we can't modify it, so skip it
+ */
+ oidBuf.value = (void *)oid;
+ oidBuf.length = strlen(oid);
+ if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+ != GSS_S_COMPLETE) {
+#if 0
+ (void) syslog(LOG_INFO, "invalid mechanism oid"
+ " [%s] in configuration file", oid);
+#endif
+ return;
+ }
+
+ aMech = searchMechList(mechOid);
+ if (aMech && aMech->mech) {
+ generic_gss_release_oid(&minor, &mechOid);
+ return;
+ }
+
+ /*
+ * If that's all, then this is a corrupt entry. Skip it.
+ */
+ if (! *sharedLib) {
+ generic_gss_release_oid(&minor, &mechOid);
+ return;
+ }
+#if defined(_WIN32)
+ sharedPath = sharedLib;
+#else
+ if (sharedLib[0] == '/')
+ snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib);
+ else
+ snprintf(sharedPath, sizeof(sharedPath), "%s%s",
+ MECH_LIB_PREFIX, sharedLib);
+#endif
+ /*
+ * are we creating a new mechanism entry or
+ * just modifying existing (non loaded) mechanism entry
+ */
+ if (aMech) {
+ /*
+ * delete any old values and set new
+ * mechNameStr and mech_type are not modified
+ */
+ if (aMech->kmodName) {
+ free(aMech->kmodName);
+ aMech->kmodName = NULL;
+ }
+
+ if (aMech->optionStr) {
+ free(aMech->optionStr);
+ aMech->optionStr = NULL;
+ }
+
+ if ((tmpStr = strdup(sharedPath)) != NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ aMech->uLibName = tmpStr;
+ }
+
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions) /* optional module options */
+ aMech->optionStr = strdup(modOptions);
+
+ /* the oid is already set */
+ generic_gss_release_oid(&minor, &mechOid);
+ return;
+ }
+
+ /* adding a new entry */
+ aMech = calloc(1, sizeof (struct gss_mech_config));
+ if (aMech == NULL) {
+ generic_gss_release_oid(&minor, &mechOid);
+ return;
+ }
+ aMech->mech_type = mechOid;
+ aMech->uLibName = strdup(sharedPath);
+ aMech->mechNameStr = strdup(oidStr);
+ aMech->freeMech = 0;
+
+ /* check if any memory allocations failed - bad news */
+ if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ if (aMech->mechNameStr)
+ free(aMech->mechNameStr);
+ generic_gss_release_oid(&minor, &mechOid);
+ free(aMech);
+ return;
+ }
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions)
+ aMech->optionStr = strdup(modOptions);
+
+ if (modType && strcmp(modType, "interposer") == 0)
+ aMech->is_interposer = 1;
+
+ /*
+ * add the new entry to the end of the list - make sure
+ * that only complete entries are added because other
+ * threads might currently be searching the list.
+ */
+ tmp = g_mechListTail;
+ g_mechListTail = aMech;
+
+ if (tmp != NULL)
+ tmp->next = aMech;
+
+ if (g_mechList == NULL)
+ g_mechList = aMech;
+}
+
diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c
new file mode 100644
index 000000000000..6f1c71eede9d
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_context.c
@@ -0,0 +1,168 @@
+/* #pragma ident "@(#)g_inquire_context.c 1.15 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_inquire_context
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+static OM_uint32
+val_inq_ctx_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *opened)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+
+ if (targ_name != NULL)
+ *targ_name = GSS_C_NO_NAME;
+
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_context(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *opened)
+{
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+ OM_uint32 status, temp_minor;
+ gss_OID actual_mech;
+ gss_name_t localTargName = NULL, localSourceName = NULL;
+
+ status = val_inq_ctx_args(minor_status,
+ context_handle,
+ src_name, targ_name,
+ lifetime_rec,
+ mech_type, ctx_flags,
+ locally_initiated, opened);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
+ !mech->gss_release_name) {
+ return (GSS_S_UNAVAILABLE);
+ }
+
+ status = mech->gss_inquire_context(
+ minor_status,
+ ctx->internal_ctx_id,
+ (src_name ? &localSourceName : NULL),
+ (targ_name ? &localTargName : NULL),
+ lifetime_rec,
+ &actual_mech,
+ ctx_flags,
+ locally_initiated,
+ opened);
+
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return status;
+ }
+
+ /* need to convert names */
+
+ if (src_name) {
+ if (localSourceName) {
+ status = gssint_convert_name_to_union_name(minor_status, mech,
+ localSourceName, src_name);
+
+ if (status != GSS_S_COMPLETE) {
+ if (localTargName)
+ mech->gss_release_name(&temp_minor, &localTargName);
+ return (status);
+ }
+ } else {
+ *src_name = GSS_C_NO_NAME;
+ }
+ }
+
+ if (targ_name) {
+ if (localTargName) {
+ status = gssint_convert_name_to_union_name(minor_status, mech,
+ localTargName, targ_name);
+
+ if (status != GSS_S_COMPLETE) {
+ if (src_name)
+ (void) gss_release_name(&temp_minor, src_name);
+
+ return (status);
+ }
+ }
+ else {
+ *targ_name = GSS_C_NO_NAME;
+ }
+ }
+
+ if (mech_type)
+ *mech_type = gssint_get_public_oid(actual_mech);
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_inq_context_oid.c b/src/lib/gssapi/mechglue/g_inq_context_oid.c
new file mode 100644
index 000000000000..ebdeaaee88b2
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_context_oid.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/* Glue routine for gss_inquire_sec_context_by_oid */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech != NULL) {
+ if (mech->gss_inquire_sec_context_by_oid != NULL) {
+ status = mech->gss_inquire_sec_context_by_oid(minor_status,
+ ctx->internal_ctx_id,
+ desired_object,
+ data_set);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return status;
+ }
+
+ return GSS_S_BAD_MECH;
+}
diff --git a/src/lib/gssapi/mechglue/g_inq_cred.c b/src/lib/gssapi/mechglue/g_inq_cred.c
new file mode 100644
index 000000000000..911196264f1f
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_cred.c
@@ -0,0 +1,233 @@
+/* #pragma ident "@(#)g_inquire_cred.c 1.16 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_inquire_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred(minor_status,
+ cred_handle,
+ name,
+ lifetime,
+ cred_usage,
+ mechanisms)
+
+OM_uint32 * minor_status;
+gss_cred_id_t cred_handle;
+gss_name_t * name;
+OM_uint32 * lifetime;
+int * cred_usage;
+gss_OID_set * mechanisms;
+
+{
+ OM_uint32 status, temp_minor_status;
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+ gss_cred_id_t mech_cred;
+ gss_name_t mech_name;
+ gss_OID_set mechs = NULL;
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (name != NULL)
+ *name = GSS_C_NO_NAME;
+
+ if (mechanisms != NULL)
+ *mechanisms = GSS_C_NO_OID_SET;
+
+ /* Validate arguments. */
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /*
+ * XXX We should iterate over all mechanisms in the credential and
+ * aggregate the results. This requires a union name structure containing
+ * multiple mechanism names, which we don't currently have. For now,
+ * inquire the first mechanism in the credential; this is consistent with
+ * our historical behavior.
+ */
+
+ /* Determine mechanism and mechanism credential. */
+ if (cred_handle != GSS_C_NO_CREDENTIAL) {
+ union_cred = (gss_union_cred_t) cred_handle;
+ if (union_cred->count <= 0)
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+ mech_cred = union_cred->cred_array[0];
+ mech = gssint_get_mechanism(&union_cred->mechs_array[0]);
+ } else {
+ union_cred = NULL;
+ mech_cred = GSS_C_NO_CREDENTIAL;
+ mech = gssint_get_mechanism(GSS_C_NULL_OID);
+ }
+
+ /* Skip the call into the mech if the caller doesn't care about any of the
+ * values we would ask for. */
+ if (name != NULL || lifetime != NULL || cred_usage != NULL) {
+ if (mech == NULL)
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+ if (!mech->gss_inquire_cred)
+ return (GSS_S_UNAVAILABLE);
+
+ status = mech->gss_inquire_cred(minor_status, mech_cred,
+ name ? &mech_name : NULL,
+ lifetime, cred_usage, NULL);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return(status);
+ }
+
+ if (name) {
+ /* Convert mech_name into a union_name equivalent. */
+ status = gssint_convert_name_to_union_name(&temp_minor_status,
+ mech, mech_name, name);
+ if (status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ return (status);
+ }
+ }
+ }
+
+ /*
+ * copy the mechanism set in union_cred into an OID set and return in
+ * the mechanisms parameter.
+ */
+
+ if(mechanisms != NULL) {
+ if (union_cred) {
+ status = gssint_make_public_oid_set(minor_status,
+ union_cred->mechs_array,
+ union_cred->count, &mechs);
+ if (GSS_ERROR(status))
+ goto error;
+ } else {
+ status = gss_create_empty_oid_set(minor_status, &mechs);
+ if (GSS_ERROR(status))
+ goto error;
+
+ status = gss_add_oid_set_member(minor_status,
+ &mech->mech_type, &mechs);
+ if (GSS_ERROR(status))
+ goto error;
+ }
+ *mechanisms = mechs;
+ }
+
+ return(GSS_S_COMPLETE);
+
+error:
+ if (mechs != NULL)
+ (void) gss_release_oid_set(&temp_minor_status, &mechs);
+
+ if (name && *name != NULL)
+ (void) gss_release_name(&temp_minor_status, name);
+
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
+ initiator_lifetime, acceptor_lifetime, cred_usage)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+ gss_OID mech_type;
+ gss_name_t *name;
+ OM_uint32 *initiator_lifetime;
+ OM_uint32 *acceptor_lifetime;
+ gss_cred_usage_t *cred_usage;
+{
+ gss_union_cred_t union_cred;
+ gss_cred_id_t mech_cred;
+ gss_mechanism mech;
+ OM_uint32 status, temp_minor_status;
+ gss_name_t internal_name;
+ gss_OID selected_mech, public_mech;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (name != NULL)
+ *name = GSS_C_NO_NAME;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ status = gssint_select_mech_type(minor_status, mech_type, &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+ if (!mech->gss_inquire_cred_by_mech)
+ return (GSS_S_BAD_BINDINGS);
+
+ union_cred = (gss_union_cred_t) cred_handle;
+ mech_cred = gssint_get_mechanism_cred(union_cred, selected_mech);
+
+#if 0
+ if (mech_cred == NULL)
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+#endif
+
+ public_mech = gssint_get_public_oid(selected_mech);
+ status = mech->gss_inquire_cred_by_mech(minor_status,
+ mech_cred, public_mech,
+ name ? &internal_name : NULL,
+ initiator_lifetime,
+ acceptor_lifetime, cred_usage);
+
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return (status);
+ }
+
+ if (name) {
+ /*
+ * Convert internal_name into a union_name equivalent.
+ */
+ status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, name);
+ if (status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ return (status);
+ }
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_inq_cred_oid.c b/src/lib/gssapi/mechglue/g_inq_cred_oid.c
new file mode 100644
index 000000000000..4c23dfcbd364
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_cred_oid.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/* Glue routine for gss_inquire_cred_by_oid */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+static OM_uint32 append_to_buffer_set(OM_uint32 *minor_status,
+ gss_buffer_set_t *dst,
+ const gss_buffer_set_t src)
+{
+ size_t i;
+ OM_uint32 status;
+
+ if (src == GSS_C_NO_BUFFER_SET)
+ return GSS_S_COMPLETE;
+
+ if (*dst == GSS_C_NO_BUFFER_SET) {
+ status = gss_create_empty_buffer_set(minor_status, dst);
+ if (status != GSS_S_COMPLETE)
+ return status;
+ }
+
+ status = GSS_S_COMPLETE;
+
+ for (i = 0; i < src->count; i++) {
+ status = gss_add_buffer_set_member(minor_status,
+ &src->elements[i],
+ dst);
+ if (status != GSS_S_COMPLETE)
+ break;
+ }
+
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred_by_oid(OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+ int i;
+ gss_buffer_set_t union_set = GSS_C_NO_BUFFER_SET;
+ gss_buffer_set_t ret_set = GSS_C_NO_BUFFER_SET;
+ OM_uint32 status, minor;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
+
+ *minor_status = 0;
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ union_cred = (gss_union_cred_t) cred_handle;
+
+ status = gss_create_empty_buffer_set(minor_status, &ret_set);
+ if (status != GSS_S_COMPLETE) {
+ return status;
+ }
+
+ status = GSS_S_UNAVAILABLE;
+
+ for (i = 0; i < union_cred->count; i++) {
+ mech = gssint_get_mechanism(&union_cred->mechs_array[i]);
+ if (mech == NULL) {
+ status = GSS_S_BAD_MECH;
+ break;
+ }
+
+ if (mech->gss_inquire_cred_by_oid == NULL) {
+ status = GSS_S_UNAVAILABLE;
+ continue;
+ }
+
+ status = (mech->gss_inquire_cred_by_oid)(minor_status,
+ union_cred->cred_array[i],
+ desired_object,
+ &ret_set);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ continue;
+ }
+
+ if (union_cred->count == 1) {
+ union_set = ret_set;
+ break;
+ }
+
+ status = append_to_buffer_set(minor_status, &union_set, ret_set);
+ gss_release_buffer_set(&minor, &ret_set);
+ if (status != GSS_S_COMPLETE)
+ break;
+ }
+
+ if (status != GSS_S_COMPLETE)
+ gss_release_buffer_set(&minor, &union_set);
+
+ *data_set = union_set;
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_inq_name.c b/src/lib/gssapi/mechglue/g_inq_name.c
new file mode 100644
index 000000000000..60a3b54e7990
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_name.c
@@ -0,0 +1,97 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_inquire_name */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ OM_uint32 status, tmp;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ if (MN_mech != NULL)
+ *MN_mech = GSS_C_NO_OID;
+
+ if (attrs != NULL)
+ *attrs = GSS_C_NO_BUFFER_SET;
+
+ *minor_status = 0;
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID) {
+ /* We don't yet support non-mechanism attributes */
+ if (name_is_MN != NULL)
+ *name_is_MN = 0;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ if (name_is_MN != NULL)
+ *name_is_MN = 1;
+
+ if (MN_mech != NULL) {
+ status = generic_gss_copy_oid(minor_status,
+ union_name->mech_type,
+ MN_mech);
+ if (GSS_ERROR(status))
+ return status;
+ }
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL) {
+ gss_release_oid(&tmp, MN_mech);
+ return GSS_S_BAD_NAME;
+ }
+
+ if (mech->gss_inquire_name == NULL) {
+ gss_release_oid(&tmp, MN_mech);
+ return GSS_S_UNAVAILABLE;
+ }
+
+ status = (*mech->gss_inquire_name)(minor_status,
+ union_name->mech_name,
+ NULL,
+ NULL,
+ attrs);
+ if (status != GSS_S_COMPLETE) {
+ generic_gss_release_oid(&tmp, MN_mech);
+ map_error(minor_status, mech);
+ }
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_inq_names.c b/src/lib/gssapi/mechglue/g_inq_names.c
new file mode 100644
index 000000000000..d22af8bcf958
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_inq_names.c
@@ -0,0 +1,168 @@
+/* #pragma ident "@(#)g_inquire_names.c 1.16 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_inquire_context
+ */
+
+#include "mglueP.h"
+
+#define MAX_MECH_OID_PAIRS 32
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+
+OM_uint32 * minor_status;
+gss_OID mechanism;
+gss_OID_set * name_types;
+
+{
+ OM_uint32 status;
+ gss_OID selected_mech = GSS_C_NO_OID, public_mech;
+ gss_mechanism mech;
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (name_types != NULL)
+ *name_types = GSS_C_NO_OID_SET;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (name_types == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ status = gssint_select_mech_type(minor_status, mechanism,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+ else if (mech->gss_inquire_names_for_mech == NULL)
+ return GSS_S_UNAVAILABLE;
+ public_mech = gssint_get_public_oid(selected_mech);
+ status = mech->gss_inquire_names_for_mech(minor_status, public_mech,
+ name_types);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
+
+static OM_uint32
+val_inq_mechs4name_args(
+ OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ gss_OID_set *mech_set)
+{
+
+ /* Initialize outputs. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (mech_set != NULL)
+ *mech_set = GSS_C_NO_OID_SET;
+
+ /* Validate arguments.e
+ */
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_name == GSS_C_NO_NAME)
+ return (GSS_S_BAD_NAME);
+
+ return (GSS_S_COMPLETE);
+}
+
+static int
+mech_supports_nametype(gss_OID mech_oid, gss_OID name_type)
+{
+ OM_uint32 status, minor;
+ gss_OID_set types = GSS_C_NO_OID_SET;
+ int present;
+
+ status = gss_inquire_names_for_mech(&minor, mech_oid, &types);
+ if (status != GSS_S_COMPLETE)
+ return (0);
+ status = gss_test_oid_set_member(&minor, name_type, types, &present);
+ (void) gss_release_oid_set(&minor, &types);
+ return (status == GSS_S_COMPLETE && present);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mechs_for_name(OM_uint32 *minor_status,
+ const gss_name_t input_name, gss_OID_set *mech_set)
+{
+ OM_uint32 status, tmpmin;
+ gss_OID_set all_mechs = GSS_C_NO_OID_SET;
+ gss_OID_set mechs = GSS_C_NO_OID_SET;
+ gss_OID mech_oid, name_type;
+ gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
+ size_t i;
+
+ status = val_inq_mechs4name_args(minor_status, input_name, mech_set);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ status = gss_display_name(minor_status, input_name, &name_buffer,
+ &name_type);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+ status = gss_indicate_mechs(minor_status, &all_mechs);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+ status = gss_create_empty_oid_set(minor_status, &mechs);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+ for (i = 0; i < all_mechs->count; i++) {
+ mech_oid = &all_mechs->elements[i];
+ if (mech_supports_nametype(mech_oid, name_type)) {
+ status = gss_add_oid_set_member(minor_status, mech_oid, &mechs);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+ }
+ }
+
+ *mech_set = mechs;
+ mechs = GSS_C_NO_OID_SET;
+
+cleanup:
+ (void) gss_release_buffer(&tmpmin, &name_buffer);
+ (void) gss_release_oid_set(&tmpmin, &all_mechs);
+ (void) gss_release_oid_set(&tmpmin, &mechs);
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_map_name_to_any.c b/src/lib/gssapi/mechglue/g_map_name_to_any.c
new file mode 100644
index 000000000000..ebf49450f062
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_map_name_to_any.c
@@ -0,0 +1,76 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_map_name_to_any */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ if (type_id == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_map_name_to_any == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_map_name_to_any)(minor_status,
+ union_name->mech_name,
+ authenticated,
+ type_id,
+ output);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_mech_invoke.c b/src/lib/gssapi/mechglue/g_mech_invoke.c
new file mode 100644
index 000000000000..0647cda96945
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_mech_invoke.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/* Glue routine for gssspi_mech_invoke */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gssspi_mech_invoke (OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ OM_uint32 status;
+ gss_OID selected_mech = GSS_C_NO_OID;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ status = gssint_select_mech_type(minor_status, desired_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL || mech->gssspi_mech_invoke == NULL) {
+ return GSS_S_BAD_MECH;
+ }
+
+ status = mech->gssspi_mech_invoke(minor_status,
+ gssint_get_public_oid(selected_mech),
+ desired_object,
+ value);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_mechattr.c b/src/lib/gssapi/mechglue/g_mechattr.c
new file mode 100644
index 000000000000..e49651eb6ade
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_mechattr.c
@@ -0,0 +1,222 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/mechglue/g_mechattr.c */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "mglueP.h"
+
+static int
+testMechAttr(gss_const_OID attr,
+ gss_const_OID_set against)
+{
+ int present = 0;
+ OM_uint32 minor;
+
+ if (GSS_ERROR(generic_gss_test_oid_set_member(&minor, attr,
+ (gss_OID_set)against,
+ &present)))
+ return 0;
+
+ return present;
+}
+
+/*
+ * Return TRUE iff all the elements of desired and none of the elements
+ * of except exist in available.
+ */
+static int
+testMechAttrsOffered(gss_const_OID_set desired,
+ gss_const_OID_set except,
+ gss_const_OID_set available)
+{
+ size_t i;
+
+ if (desired != GSS_C_NO_OID_SET) {
+ for (i = 0; i < desired->count; i++) {
+ if (!testMechAttr(&desired->elements[i], available))
+ return 0;
+ }
+ }
+
+ if (except != GSS_C_NO_OID_SET) {
+ for (i = 0; i < except->count; i++) {
+ if (testMechAttr(&except->elements[i], available))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Return TRUE iff all the elements of critical exist in known.
+ */
+static int
+testMechAttrsKnown(gss_const_OID_set critical,
+ gss_const_OID_set known)
+{
+ size_t i;
+
+ if (critical != GSS_C_NO_OID_SET) {
+ for (i = 0; i < critical->count; i++) {
+ if (!testMechAttr(&critical->elements[i], known))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs_by_attrs(
+ OM_uint32 *minor,
+ gss_const_OID_set desired_mech_attrs,
+ gss_const_OID_set except_mech_attrs,
+ gss_const_OID_set critical_mech_attrs,
+ gss_OID_set *mechs)
+{
+ OM_uint32 status, tmpMinor;
+ gss_OID_set allMechs = GSS_C_NO_OID_SET;
+ size_t i;
+
+ if (minor == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor = 0;
+
+ if (mechs == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *mechs = GSS_C_NO_OID_SET;
+
+ status = gss_indicate_mechs(minor, &allMechs);
+ if (GSS_ERROR(status))
+ goto cleanup;
+
+ status = generic_gss_create_empty_oid_set(minor, mechs);
+ if (GSS_ERROR(status))
+ goto cleanup;
+
+ for (i = 0; i < allMechs->count; i++) {
+ gss_OID_set supportedAttrs = GSS_C_NO_OID_SET;
+ gss_OID_set knownAttrs = GSS_C_NO_OID_SET;
+
+ status = gss_inquire_attrs_for_mech(minor, &allMechs->elements[i],
+ &supportedAttrs, &knownAttrs);
+ if (GSS_ERROR(status))
+ continue;
+
+ if (testMechAttrsOffered(desired_mech_attrs,
+ except_mech_attrs, supportedAttrs) &&
+ testMechAttrsKnown(critical_mech_attrs, knownAttrs)) {
+ status = gss_add_oid_set_member(minor, &allMechs->elements[i],
+ mechs);
+ if (GSS_ERROR(status)) {
+ gss_release_oid_set(&tmpMinor, &supportedAttrs);
+ gss_release_oid_set(&tmpMinor, &knownAttrs);
+ goto cleanup;
+ }
+ }
+
+ gss_release_oid_set(&tmpMinor, &supportedAttrs);
+ gss_release_oid_set(&tmpMinor, &knownAttrs);
+ }
+
+ *minor = 0;
+ status = GSS_S_COMPLETE;
+
+cleanup:
+ gss_release_oid_set(&tmpMinor, &allMechs);
+
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_attrs_for_mech(
+ OM_uint32 *minor,
+ gss_const_OID mech_oid,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs)
+{
+ OM_uint32 status, tmpMinor;
+ gss_OID selected_mech, public_mech;
+ gss_mechanism mech;
+
+ if (minor == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor = 0;
+
+ if (mech_attrs != NULL)
+ *mech_attrs = GSS_C_NO_OID_SET;
+
+ if (known_mech_attrs != NULL)
+ *known_mech_attrs = GSS_C_NO_OID_SET;
+
+ status = gssint_select_mech_type(minor, mech_oid, &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ /* If the mech does not implement RFC 5587, return success with an empty
+ * mech_attrs and known_mech_attrs. */
+ if (mech->gss_inquire_attrs_for_mech == NULL)
+ return GSS_S_COMPLETE;
+
+ public_mech = gssint_get_public_oid(selected_mech);
+ status = mech->gss_inquire_attrs_for_mech(minor, public_mech, mech_attrs,
+ known_mech_attrs);
+ if (GSS_ERROR(status)) {
+ map_error(minor, mech);
+ return status;
+ }
+
+ if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) {
+ status = generic_gss_copy_oid_set(minor,
+ gss_ma_known_attrs,
+ known_mech_attrs);
+ if (GSS_ERROR(status)) {
+ gss_release_oid_set(&tmpMinor, mech_attrs);
+ if (mech_attrs != NULL)
+ *mech_attrs = GSS_C_NO_OID_SET;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_display_mech_attr(
+ OM_uint32 *minor,
+ gss_const_OID mech_attr,
+ gss_buffer_t name,
+ gss_buffer_t short_desc,
+ gss_buffer_t long_desc)
+{
+ return generic_gss_display_mech_attr(minor, mech_attr,
+ name, short_desc, long_desc);
+}
diff --git a/src/lib/gssapi/mechglue/g_mechname.c b/src/lib/gssapi/mechglue/g_mechname.c
new file mode 100644
index 000000000000..cfb0a0d2af8e
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_mechname.c
@@ -0,0 +1,116 @@
+/*
+ * g_mechname.c --- registry of mechanism-specific name types
+ *
+ * This file contains a registry of mechanism-specific name types. It
+ * is used to determine which name types not should be lazy evaluated,
+ * but rather evaluated on the spot.
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static gss_mech_spec_name name_list = NULL;
+
+/*
+ * generic searching helper function.
+ */
+static gss_mech_spec_name search_mech_spec(name_type)
+ gss_OID name_type;
+{
+ gss_mech_spec_name p;
+
+ for (p = name_list; p; p = p->next) {
+ if (g_OID_equal(name_type, p->name_type))
+ return p;
+ }
+ return NULL;
+}
+
+/*
+ * Given a name_type, if it is specific to a mechanism, return the
+ * mechanism OID. Otherwise, return NULL.
+ */
+gss_OID gss_find_mechanism_from_name_type(name_type)
+ gss_OID name_type;
+{
+ gss_mech_spec_name p;
+
+ p = search_mech_spec(name_type);
+ if (!p)
+ return NULL;
+ return p->mech;
+}
+
+/*
+ * This function adds a (name_type, mechanism) pair to the
+ * mechanism-specific name type registry. If an entry for the
+ * name_type already exists, then zero out the mechanism entry.
+ * Otherwise, enter the pair into the registry.
+ */
+OM_uint32
+gss_add_mech_name_type(minor_status, name_type, mech)
+ OM_uint32 *minor_status;
+ gss_OID name_type;
+ gss_OID mech;
+{
+ OM_uint32 major_status, tmp;
+ gss_mech_spec_name p;
+
+ p = search_mech_spec(name_type);
+ if (p) {
+ /*
+ * We found an entry for this name type; mark it as not being
+ * a mechanism-specific name type.
+ */
+ if (p->mech) {
+ if (!g_OID_equal(mech, p->mech)) {
+ generic_gss_release_oid(minor_status, &p->mech);
+ p->mech = 0;
+ }
+ }
+ return GSS_S_COMPLETE;
+ }
+ p = malloc(sizeof(gss_mech_spec_name_desc));
+ if (!p) {
+ *minor_status = ENOMEM;
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ p->name_type = 0;
+ p->mech = 0;
+
+ major_status = generic_gss_copy_oid(minor_status, name_type,
+ &p->name_type);
+ if (major_status) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+ major_status = generic_gss_copy_oid(minor_status, mech,
+ &p->mech);
+ if (major_status) {
+ map_errcode(minor_status);
+ goto allocation_failure;
+ }
+
+ p->next = name_list;
+ p->prev = 0;
+ name_list = p;
+
+ return GSS_S_COMPLETE;
+
+allocation_failure:
+ if (p) {
+ if (p->mech)
+ generic_gss_release_oid(&tmp, &p->mech);
+ if (p->name_type)
+ generic_gss_release_oid(&tmp, &p->name_type);
+ free(p);
+ }
+ return GSS_S_FAILURE;
+}
diff --git a/src/lib/gssapi/mechglue/g_oid_ops.c b/src/lib/gssapi/mechglue/g_oid_ops.c
new file mode 100644
index 000000000000..1d75c63e69d7
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_oid_ops.c
@@ -0,0 +1,112 @@
+/* #pragma ident "@(#)g_oid_ops.c 1.11 98/01/22 SMI" */
+/* lib/gssapi/mechglue/g_oid_ops.c - GSSAPI V2 interfaces to manipulate OIDs */
+/*
+ * Copyright 1995, 2007 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.
+ */
+
+#include "mglueP.h"
+
+/*
+ * gss_release_oid has been moved to g_initialize, becasue it requires access
+ * to the mechanism list. All functions requiring direct access to the
+ * mechanism list are now in g_initialize.c
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_create_empty_oid_set(minor_status, oid_set)
+ OM_uint32 *minor_status;
+ gss_OID_set *oid_set;
+{
+ OM_uint32 status;
+ status = generic_gss_create_empty_oid_set(minor_status, oid_set);
+ if (status != GSS_S_COMPLETE)
+ map_errcode(minor_status);
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_add_oid_set_member(minor_status, member_oid, oid_set)
+ OM_uint32 *minor_status;
+ gss_OID member_oid;
+ gss_OID_set *oid_set;
+{
+ OM_uint32 status;
+ status = generic_gss_add_oid_set_member(minor_status, member_oid, oid_set);
+ if (status != GSS_S_COMPLETE)
+ map_errcode(minor_status);
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_test_oid_set_member(minor_status, member, set, present)
+ OM_uint32 *minor_status;
+ gss_OID member;
+ gss_OID_set set;
+ int *present;
+{
+ return generic_gss_test_oid_set_member(minor_status, member, set, present);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_oid_to_str(minor_status, oid, oid_str)
+ OM_uint32 *minor_status;
+ gss_OID oid;
+ gss_buffer_t oid_str;
+{
+ OM_uint32 status = generic_gss_oid_to_str(minor_status, oid, oid_str);
+ if (status != GSS_S_COMPLETE)
+ map_errcode(minor_status);
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_str_to_oid(minor_status, oid_str, oid)
+ OM_uint32 *minor_status;
+ gss_buffer_t oid_str;
+ gss_OID *oid;
+{
+ OM_uint32 status = generic_gss_str_to_oid(minor_status, oid_str, oid);
+ if (status != GSS_S_COMPLETE)
+ map_errcode(minor_status);
+ return status;
+}
+
+OM_uint32
+gssint_copy_oid_set(
+ OM_uint32 *minor_status,
+ const gss_OID_set_desc * const oidset,
+ gss_OID_set *new_oidset)
+{
+ return generic_gss_copy_oid_set(minor_status, oidset, new_oidset);
+}
+
+int KRB5_CALLCONV
+gss_oid_equal(
+ gss_const_OID first_oid,
+ gss_const_OID second_oid)
+{
+ /* GSS_C_NO_OID doesn't match itself, per draft-josefsson-gss-capsulate. */
+ if (first_oid == GSS_C_NO_OID || second_oid == GSS_C_NO_OID)
+ return 0;
+ return g_OID_equal(first_oid, second_oid);
+}
diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c
new file mode 100644
index 000000000000..fcca3e44c4c0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_prf.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_pseudo_random */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_pseudo_random (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+ if (prf_in == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+ if (prf_out == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT;
+
+ prf_out->length = 0;
+ prf_out->value = NULL;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech != NULL) {
+ if (mech->gss_pseudo_random != NULL) {
+ status = mech->gss_pseudo_random(minor_status,
+ ctx->internal_ctx_id,
+ prf_key,
+ prf_in,
+ desired_output_len,
+ prf_out);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return status;
+ }
+
+ return GSS_S_BAD_MECH;
+}
diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c
new file mode 100644
index 000000000000..bc260aeb10b2
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_process_context.c
@@ -0,0 +1,82 @@
+/* #pragma ident "@(#)g_process_context.c 1.12 98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_process_context
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_process_context_token (minor_status,
+ context_handle,
+ token_buffer)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t token_buffer;
+
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (token_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (GSS_EMPTY_BUFFER(token_buffer))
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+
+ if (mech->gss_process_context_token) {
+ status = mech->gss_process_context_token(
+ minor_status,
+ ctx->internal_ctx_id,
+ token_buffer);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
diff --git a/src/lib/gssapi/mechglue/g_rel_buffer.c b/src/lib/gssapi/mechglue/g_rel_buffer.c
new file mode 100644
index 000000000000..8c3328acc5a6
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_rel_buffer.c
@@ -0,0 +1,58 @@
+/* #ident "@(#)g_rel_buffer.c 1.2 96/02/06 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_release_buffer
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_buffer (minor_status,
+ buffer)
+
+OM_uint32 * minor_status;
+gss_buffer_t buffer;
+{
+ if (minor_status)
+ *minor_status = 0;
+
+ /* if buffer is NULL, return */
+
+ if(buffer == GSS_C_NO_BUFFER)
+ return(GSS_S_COMPLETE);
+
+ if ((buffer->length) &&
+ (buffer->value)) {
+ gssalloc_free(buffer->value);
+ buffer->length = 0;
+ buffer->value = NULL;
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_rel_cred.c b/src/lib/gssapi/mechglue/g_rel_cred.c
new file mode 100644
index 000000000000..ccdee05a5625
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_rel_cred.c
@@ -0,0 +1,99 @@
+/* #pragma ident "@(#)g_rel_cred.c 1.14 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/* Glue routine for gss_release_cred */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_cred(minor_status,
+ cred_handle)
+
+OM_uint32 * minor_status;
+gss_cred_id_t * cred_handle;
+
+{
+ OM_uint32 status, temp_status;
+ int j;
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ if (cred_handle == NULL)
+ return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ);
+
+ /*
+ * Loop through the union_cred struct, selecting the approprate
+ * underlying mechanism routine and calling it. At the end,
+ * release all of the storage taken by the union_cred struct.
+ */
+
+ union_cred = (gss_union_cred_t) *cred_handle;
+ if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
+ return (GSS_S_COMPLETE);
+
+ if (GSSINT_CHK_LOOP(union_cred))
+ return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ);
+ *cred_handle = NULL;
+
+ status = GSS_S_COMPLETE;
+
+ for(j=0; j < union_cred->count; j++) {
+
+ mech = gssint_get_mechanism (&union_cred->mechs_array[j]);
+
+ if (union_cred->mechs_array[j].elements)
+ free(union_cred->mechs_array[j].elements);
+ if (mech) {
+ if (mech->gss_release_cred) {
+ temp_status = mech->gss_release_cred
+ (
+ minor_status,
+ &union_cred->cred_array[j]);
+
+ if (temp_status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ status = GSS_S_NO_CRED;
+ }
+
+ } else
+ status = GSS_S_UNAVAILABLE;
+ } else
+ status = GSS_S_DEFECTIVE_CREDENTIAL;
+ }
+
+ free(union_cred->cred_array);
+ free(union_cred->mechs_array);
+ free(union_cred);
+
+ return(status);
+}
diff --git a/src/lib/gssapi/mechglue/g_rel_name.c b/src/lib/gssapi/mechglue/g_rel_name.c
new file mode 100644
index 000000000000..e00869238323
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_rel_name.c
@@ -0,0 +1,86 @@
+/* #pragma ident "@(#)g_rel_name.c 1.11 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_release_name
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_release_name (minor_status,
+ input_name)
+
+OM_uint32 * minor_status;
+gss_name_t * input_name;
+
+{
+ gss_union_name_t union_name;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ /* if input_name is NULL, return error */
+ if (input_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (*input_name == GSS_C_NO_NAME)
+ return GSS_S_COMPLETE;
+
+ /*
+ * free up the space for the external_name and then
+ * free the union_name descriptor
+ */
+
+ union_name = (gss_union_name_t) *input_name;
+ if (GSSINT_CHK_LOOP(union_name))
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+ *input_name = 0;
+ *minor_status = 0;
+
+ if (union_name->name_type != GSS_C_NO_OID)
+ gss_release_oid(minor_status, &union_name->name_type);
+
+ if (union_name->external_name != GSS_C_NO_BUFFER) {
+ if (union_name->external_name->value != NULL)
+ gssalloc_free(union_name->external_name->value);
+ free(union_name->external_name);
+ }
+
+ if (union_name->mech_type) {
+ gssint_release_internal_name(minor_status, union_name->mech_type,
+ &union_name->mech_name);
+ gss_release_oid(minor_status, &union_name->mech_type);
+ }
+
+ free(union_name);
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/mechglue/g_rel_name_mapping.c b/src/lib/gssapi/mechglue/g_rel_name_mapping.c
new file mode 100644
index 000000000000..f09136afee74
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_rel_name_mapping.c
@@ -0,0 +1,74 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_release_any_name_mapping */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ if (type_id == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (input == NULL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_release_any_name_mapping == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_release_any_name_mapping)(minor_status,
+ union_name->mech_name,
+ type_id,
+ input);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_rel_oid_set.c b/src/lib/gssapi/mechglue/g_rel_oid_set.c
new file mode 100644
index 000000000000..fa008d6bb9bb
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_rel_oid_set.c
@@ -0,0 +1,43 @@
+/* #pragma ident "@(#)g_rel_oid_set.c 1.12 97/11/11 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_release_oid_set
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_oid_set (minor_status,
+ set)
+
+OM_uint32 * minor_status;
+gss_OID_set * set;
+{
+ return generic_gss_release_oid_set(minor_status, set);
+}
diff --git a/src/lib/gssapi/mechglue/g_saslname.c b/src/lib/gssapi/mechglue/g_saslname.c
new file mode 100644
index 000000000000..48060c367172
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_saslname.c
@@ -0,0 +1,220 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/mechglue/g_saslname.c */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "mglueP.h"
+#include <krb5/krb5.h>
+
+static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+#define OID_SASL_NAME_LENGTH (sizeof("GS2-XXXXXXXXXXX") - 1)
+
+static OM_uint32
+oidToSaslName(OM_uint32 *minor, const gss_OID mech,
+ char sasl_name[OID_SASL_NAME_LENGTH + 1])
+{
+ unsigned char derBuf[2];
+ krb5_crypto_iov iov[3];
+ unsigned char cksumBuf[20], *q = cksumBuf;
+ char *p = sasl_name;
+
+ if (mech->length > 127) {
+ *minor = ERANGE;
+ return GSS_S_BAD_MECH;
+ }
+
+ derBuf[0] = 0x06;
+ derBuf[1] = (unsigned char)mech->length;
+
+ iov[0].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ iov[0].data.length = 2;
+ iov[0].data.data = (char *)derBuf;
+ iov[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ iov[1].data.length = mech->length;
+ iov[1].data.data = (char *)mech->elements;
+ iov[2].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ iov[2].data.length = sizeof(cksumBuf);
+ iov[2].data.data = (char *)cksumBuf;
+
+ *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_NIST_SHA,
+ NULL, 0, iov, 3);
+ if (*minor != 0)
+ return GSS_S_FAILURE;
+
+ memcpy(p, "GS2-", 4);
+ p += 4;
+
+ *p++ = basis_32[q[0] >> 3];
+ *p++ = basis_32[((q[0] & 7) << 2) | (q[1] >> 6)];
+ *p++ = basis_32[(q[1] & 0x3f) >> 1];
+ *p++ = basis_32[((q[1] & 1) << 4) | (q[2] >> 4)];
+ *p++ = basis_32[((q[2] & 0xf) << 1) | (q[3] >> 7)];
+ *p++ = basis_32[(q[3] & 0x7f) >> 2];
+ *p++ = basis_32[((q[3] & 3) << 3) | (q[4] >> 5)];
+ *p++ = basis_32[(q[4] & 0x1f)];
+ *p++ = basis_32[q[5] >> 3];
+ *p++ = basis_32[((q[5] & 7) << 2) | (q[6] >> 6)];
+ *p++ = basis_32[(q[6] & 0x3f) >> 1];
+
+ *p++ = '\0';
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+oidToSaslNameAlloc(OM_uint32 *minor, const gss_OID mech,
+ gss_buffer_t sasl_name)
+{
+ OM_uint32 status, tmpMinor;
+
+ sasl_name->value = malloc(OID_SASL_NAME_LENGTH + 1);
+ if (sasl_name->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ sasl_name->length = OID_SASL_NAME_LENGTH;
+
+ status = oidToSaslName(minor, mech, (char *)sasl_name->value);
+ if (GSS_ERROR(status)) {
+ gss_release_buffer(&tmpMinor, sasl_name);
+ return status;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV gss_inquire_saslname_for_mech(
+ OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description)
+{
+ OM_uint32 status;
+ gss_OID selected_mech, public_mech;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (sasl_mech_name != GSS_C_NO_BUFFER) {
+ sasl_mech_name->length = 0;
+ sasl_mech_name->value = NULL;
+ }
+
+ if (mech_name != GSS_C_NO_BUFFER) {
+ mech_name->length = 0;
+ mech_name->value = NULL;
+ }
+
+ if (mech_description != GSS_C_NO_BUFFER) {
+ mech_description->length = 0;
+ mech_description->value = NULL;
+ }
+
+ status = gssint_select_mech_type(minor_status, desired_mech,
+ &selected_mech);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ mech = gssint_get_mechanism(desired_mech);
+ if (mech == NULL) {
+ return GSS_S_BAD_MECH;
+ } else if (mech->gss_inquire_saslname_for_mech == NULL) {
+ status = GSS_S_UNAVAILABLE;
+ } else {
+ public_mech = gssint_get_public_oid(selected_mech);
+ status = mech->gss_inquire_saslname_for_mech(minor_status, public_mech,
+ sasl_mech_name, mech_name,
+ mech_description);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ }
+
+ if (status == GSS_S_UNAVAILABLE) {
+ if (sasl_mech_name != GSS_C_NO_BUFFER)
+ status = oidToSaslNameAlloc(minor_status, desired_mech,
+ sasl_mech_name);
+ else
+ status = GSS_S_COMPLETE;
+ }
+
+ return status;
+}
+
+/* We cannot interpose this function as mech_type is an output parameter. */
+OM_uint32 KRB5_CALLCONV gss_inquire_mech_for_saslname(
+ OM_uint32 *minor_status,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type)
+{
+ OM_uint32 status, tmpMinor;
+ gss_OID_set mechSet = GSS_C_NO_OID_SET;
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+
+ status = gss_indicate_mechs(minor_status, &mechSet);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ for (i = 0, status = GSS_S_BAD_MECH; i < mechSet->count; i++) {
+ gss_mechanism mech;
+ char mappedName[OID_SASL_NAME_LENGTH + 1];
+
+ mech = gssint_get_mechanism(&mechSet->elements[i]);
+ if (mech != NULL && mech->gss_inquire_mech_for_saslname != NULL) {
+ status = mech->gss_inquire_mech_for_saslname(minor_status,
+ sasl_mech_name,
+ mech_type);
+ if (status == GSS_S_COMPLETE)
+ break;
+ }
+ if (status == GSS_S_BAD_MECH &&
+ sasl_mech_name->length == OID_SASL_NAME_LENGTH &&
+ oidToSaslName(&tmpMinor, &mechSet->elements[i],
+ mappedName) == GSS_S_COMPLETE &&
+ memcmp(sasl_mech_name->value, mappedName,
+ OID_SASL_NAME_LENGTH) == 0) {
+ if (mech_type != NULL)
+ *mech_type = &mech->mech_type;
+ status = GSS_S_COMPLETE;
+ break;
+ }
+ }
+
+ gss_release_oid_set(&tmpMinor, &mechSet);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c
new file mode 100644
index 000000000000..f17241c90891
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_seal.c
@@ -0,0 +1,249 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_wrap
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_wrap_args(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_message_buffer != GSS_C_NO_BUFFER) {
+ output_message_buffer->length = 0;
+ output_message_buffer->value = NULL;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (input_message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (output_message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_wrap( OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+
+ /* EXPORT DELETE START */
+
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_wrap_args(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_wrap) {
+ status = mech->gss_wrap(minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag,
+ qop_req,
+ input_message_buffer,
+ conf_state,
+ output_message_buffer);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else if (mech->gss_wrap_aead ||
+ (mech->gss_wrap_iov && mech->gss_wrap_iov_length)) {
+ status = gssint_wrap_aead(mech,
+ minor_status,
+ ctx,
+ conf_req_flag,
+ (gss_qop_t)qop_req,
+ GSS_C_NO_BUFFER,
+ input_message_buffer,
+ conf_state,
+ output_message_buffer);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+ /* EXPORT DELETE END */
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_seal(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ int qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+
+ return gss_wrap(minor_status, context_handle,
+ conf_req_flag, (gss_qop_t) qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer);
+}
+
+/*
+ * It is only possible to implement gss_wrap_size_limit() on top
+ * of gss_wrap_iov_length() for mechanisms that do not use any
+ * padding and have fixed length headers/trailers.
+ */
+static OM_uint32
+gssint_wrap_size_limit_iov_shim(gss_mechanism mech,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ gss_iov_buffer_desc iov[4];
+ OM_uint32 status;
+ OM_uint32 ohlen;
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.length = req_output_size;
+ iov[1].buffer.value = NULL;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
+ iov[2].buffer.value = NULL;
+ iov[2].buffer.length = 0;
+
+ iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[3].buffer.value = NULL;
+ iov[3].buffer.length = 0;
+
+ assert(mech->gss_wrap_iov_length);
+
+ status = mech->gss_wrap_iov_length(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ NULL, iov,
+ sizeof(iov)/sizeof(iov[0]));
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return status;
+ }
+
+ ohlen = iov[0].buffer.length + iov[3].buffer.length;
+
+ if (iov[2].buffer.length == 0 && ohlen < req_output_size)
+ *max_input_size = req_output_size - ohlen;
+ else
+ *max_input_size = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * New for V2
+ */
+OM_uint32 KRB5_CALLCONV
+gss_wrap_size_limit(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req, OM_uint32 req_output_size, OM_uint32 *max_input_size)
+{
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+ OM_uint32 major_status;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (max_input_size == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_wrap_size_limit)
+ major_status = mech->gss_wrap_size_limit(minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag, qop_req,
+ req_output_size, max_input_size);
+ else if (mech->gss_wrap_iov_length)
+ major_status = gssint_wrap_size_limit_iov_shim(mech, minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag, qop_req,
+ req_output_size, max_input_size);
+ else
+ major_status = GSS_S_UNAVAILABLE;
+ if (major_status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return major_status;
+}
diff --git a/src/lib/gssapi/mechglue/g_set_context_option.c b/src/lib/gssapi/mechglue/g_set_context_option.c
new file mode 100644
index 000000000000..87db240df3db
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_set_context_option.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/* Glue routine for gss_set_sec_context_option */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_set_sec_context_option (OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 status, minor;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+ gss_ctx_id_t internal_ctx = GSS_C_NO_CONTEXT;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) *context_handle;
+ if (ctx == NULL) {
+ mech = gssint_get_mechanism (GSS_C_NO_OID);
+ } else {
+ mech = gssint_get_mechanism (ctx->mech_type);
+ }
+
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+ if (mech->gss_set_sec_context_option == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = mech->gss_set_sec_context_option(minor_status,
+ ctx ? &ctx->internal_ctx_id :
+ &internal_ctx,
+ desired_object,
+ value);
+ if (status == GSS_S_COMPLETE) {
+ if (ctx == NULL && internal_ctx != GSS_C_NO_CONTEXT) {
+ /* Allocate a union context handle to wrap new context */
+ ctx = (gss_union_ctx_id_t)malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ *minor_status = ENOMEM;
+ gssint_delete_internal_sec_context(&minor,
+ &mech->mech_type,
+ &internal_ctx,
+ GSS_C_NO_BUFFER);
+ return GSS_S_FAILURE;
+ }
+
+ status = generic_gss_copy_oid(minor_status,
+ &mech->mech_type,
+ &ctx->mech_type);
+ if (status != GSS_S_COMPLETE) {
+ gssint_delete_internal_sec_context(&minor,
+ ctx->mech_type,
+ &internal_ctx,
+ GSS_C_NO_BUFFER);
+ free(ctx);
+ return status;
+ }
+
+ ctx->internal_ctx_id = internal_ctx;
+ *context_handle = (gss_ctx_id_t)ctx;
+ }
+ } else
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_set_cred_option.c b/src/lib/gssapi/mechglue/g_set_cred_option.c
new file mode 100644
index 000000000000..90e5756e5199
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_set_cred_option.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2008-2010 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.
+ */
+
+/* Glue routine for gssspi_set_cred_option */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+static OM_uint32
+alloc_union_cred(OM_uint32 *minor_status,
+ gss_mechanism mech,
+ gss_cred_id_t mech_cred,
+ gss_union_cred_t *pcred)
+{
+ OM_uint32 status;
+ OM_uint32 temp_minor_status;
+ gss_union_cred_t cred = NULL;
+
+ *pcred = NULL;
+
+ status = GSS_S_FAILURE;
+
+ cred = calloc(1, sizeof(*cred));
+ if (cred == NULL) {
+ *minor_status = ENOMEM;
+ goto cleanup;
+ }
+
+ cred->loopback = cred;
+ cred->count = 1;
+
+ cred->cred_array = calloc(cred->count, sizeof(gss_cred_id_t));
+ if (cred->cred_array == NULL) {
+ *minor_status = ENOMEM;
+ goto cleanup;
+ }
+ cred->cred_array[0] = mech_cred;
+
+ status = generic_gss_copy_oid(minor_status,
+ &mech->mech_type,
+ &cred->mechs_array);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ status = GSS_S_COMPLETE;
+ *pcred = cred;
+
+cleanup:
+ if (status != GSS_S_COMPLETE)
+ gss_release_cred(&temp_minor_status, (gss_cred_id_t *)&cred);
+
+ return status;
+}
+
+/*
+ * This differs from gssspi_set_cred_option() as shipped in 1.7, in that
+ * it can return a cred handle. To denote this change we have changed the
+ * name of the function from gssspi_set_cred_option() to gss_set_cred_option().
+ * However, the dlsym() entry point is still gssspi_set_cred_option(). This
+ * fixes a separate issue, namely that a dynamically loaded mechanism could
+ * not itself call set_cred_option() without calling its own implementation
+ * instead of the mechanism glue's. (This is useful where a mechanism wishes
+ * to export a mechanism-specific API that is a wrapper around this function.)
+ */
+OM_uint32 KRB5_CALLCONV
+gss_set_cred_option(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+ int i;
+ OM_uint32 status;
+ OM_uint32 mech_status;
+ OM_uint32 mech_minor_status;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ status = GSS_S_UNAVAILABLE;
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+ gss_cred_id_t mech_cred = GSS_C_NO_CREDENTIAL;
+
+ /*
+ * We need to give a mechanism the opportunity to allocate a
+ * credentials handle. Unfortunately this does mean that only
+ * the default mechanism can allocate a credentials handle.
+ */
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ if (mech->gssspi_set_cred_option == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = mech->gssspi_set_cred_option(minor_status,
+ &mech_cred,
+ desired_object,
+ value);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return status;
+ }
+
+ if (mech_cred != GSS_C_NO_CREDENTIAL) {
+ status = alloc_union_cred(minor_status,
+ mech,
+ mech_cred,
+ &union_cred);
+ if (status != GSS_S_COMPLETE)
+ return status;
+ *cred_handle = (gss_cred_id_t)union_cred;
+ }
+ } else {
+ union_cred = (gss_union_cred_t)*cred_handle;
+
+ for (i = 0; i < union_cred->count; i++) {
+ mech = gssint_get_mechanism(&union_cred->mechs_array[i]);
+ if (mech == NULL) {
+ status = GSS_S_BAD_MECH;
+ break;
+ }
+
+ if (mech->gssspi_set_cred_option == NULL)
+ continue;
+
+ mech_status = mech->gssspi_set_cred_option(&mech_minor_status,
+ &union_cred->cred_array[i],
+ desired_object,
+ value);
+ if (mech_status == GSS_S_UNAVAILABLE)
+ continue;
+ else {
+ status = mech_status;
+ *minor_status = mech_minor_status;
+ }
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * Provide this for backward ABI compatibility, but remove it from the
+ * header.
+ */
+OM_uint32 KRB5_CALLCONV
+gssspi_set_cred_option(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ const gss_OID desired_object,
+ const gss_buffer_t value);
+
+OM_uint32 KRB5_CALLCONV
+gssspi_set_cred_option(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ return gss_set_cred_option(minor_status, &cred,
+ desired_object, value);
+}
diff --git a/src/lib/gssapi/mechglue/g_set_name_attr.c b/src/lib/gssapi/mechglue/g_set_name_attr.c
new file mode 100644
index 000000000000..a479762a7609
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_set_name_attr.c
@@ -0,0 +1,70 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+/* Glue routine for gss_set_name_attribute */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ OM_uint32 status;
+ gss_union_name_t union_name;
+ gss_mechanism mech;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+
+ *minor_status = 0;
+
+ union_name = (gss_union_name_t)name;
+
+ if (union_name->mech_type == GSS_C_NO_OID)
+ return GSS_S_UNAVAILABLE;
+
+ mech = gssint_get_mechanism(name->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (mech->gss_set_name_attribute == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ status = (*mech->gss_set_name_attribute)(minor_status,
+ union_name->mech_name,
+ complete,
+ attr,
+ value);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_set_neg_mechs.c b/src/lib/gssapi/mechglue/g_set_neg_mechs.c
new file mode 100644
index 000000000000..69cac7037334
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_set_neg_mechs.c
@@ -0,0 +1,73 @@
+/* lib/gssapi/mechglue/g_set_neg_mechs.c - Glue for gss_set_neg_mechs */
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_set_neg_mechs(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_set)
+{
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+ int i, avail;
+ OM_uint32 status;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
+
+ *minor_status = 0;
+
+ union_cred = (gss_union_cred_t) cred_handle;
+
+ avail = 0;
+ status = GSS_S_COMPLETE;
+ for (i = 0; i < union_cred->count; i++) {
+ mech = gssint_get_mechanism(&union_cred->mechs_array[i]);
+ if (mech == NULL) {
+ status = GSS_S_BAD_MECH;
+ break;
+ }
+
+ if (mech->gss_set_neg_mechs == NULL)
+ continue;
+
+ avail = 1;
+ status = (mech->gss_set_neg_mechs)(minor_status,
+ union_cred->cred_array[i],
+ mech_set);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ break;
+ }
+ }
+
+ if (status == GSS_S_COMPLETE && !avail)
+ return GSS_S_UNAVAILABLE;
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c
new file mode 100644
index 000000000000..86d641aa2e28
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_sign.c
@@ -0,0 +1,134 @@
+/* #pragma ident "@(#)g_sign.c 1.14 98/04/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_get_mic
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_get_mic_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_buffer_t message_buffer,
+ gss_buffer_t msg_token)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (msg_token != GSS_C_NO_BUFFER) {
+ msg_token->value = NULL;
+ msg_token->length = 0;
+ }
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (msg_token == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic (minor_status,
+ context_handle,
+ qop_req,
+ message_buffer,
+ msg_token)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_qop_t qop_req;
+gss_buffer_t message_buffer;
+gss_buffer_t msg_token;
+
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_get_mic_args(minor_status, context_handle,
+ qop_req, message_buffer, msg_token);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_get_mic) {
+ status = mech->gss_get_mic(
+ minor_status,
+ ctx->internal_ctx_id,
+ qop_req,
+ message_buffer,
+ msg_token);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_sign (minor_status,
+ context_handle,
+ qop_req,
+ message_buffer,
+ msg_token)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+int qop_req;
+gss_buffer_t message_buffer;
+gss_buffer_t msg_token;
+
+{
+ return (gss_get_mic(minor_status, context_handle, (gss_qop_t) qop_req,
+ message_buffer, msg_token));
+}
diff --git a/src/lib/gssapi/mechglue/g_store_cred.c b/src/lib/gssapi/mechglue/g_store_cred.c
new file mode 100644
index 000000000000..c2b6ddf3c0d0
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_store_cred.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_store_cred.c 1.2 04/04/05 SMI" */
+
+/*
+ * glue routine for gss_store_cred
+ */
+
+#include <mglueP.h>
+
+static OM_uint32
+store_cred_fallback(
+ OM_uint32 *minor_status,
+ gss_mechanism mech,
+ gss_cred_id_t mech_cred,
+ gss_cred_usage_t cred_usage,
+ gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ gss_OID public_mech = gssint_get_public_oid(desired_mech);
+
+ if (mech->gss_store_cred_into != NULL) {
+ return mech->gss_store_cred_into(minor_status, mech_cred,
+ cred_usage, public_mech,
+ overwrite_cred, default_cred,
+ cred_store, elements_stored,
+ cred_usage_stored);
+ } else if (cred_store == GSS_C_NO_CRED_STORE) {
+ return mech->gss_store_cred(minor_status, mech_cred,
+ cred_usage, public_mech,
+ overwrite_cred, default_cred,
+ elements_stored,
+ cred_usage_stored);
+ } else {
+ return GSS_S_UNAVAILABLE;
+ }
+}
+
+static OM_uint32
+val_store_cred_args(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (elements_stored != NULL)
+ *elements_stored = GSS_C_NULL_OID_SET;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ if (cred_store != NULL && cred_store->count == 0) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_store_cred(minor_status,
+ input_cred_handle,
+ cred_usage,
+ desired_mech,
+ overwrite_cred,
+ default_cred,
+ elements_stored,
+ cred_usage_stored)
+
+OM_uint32 *minor_status;
+gss_cred_id_t input_cred_handle;
+gss_cred_usage_t cred_usage;
+const gss_OID desired_mech;
+OM_uint32 overwrite_cred;
+OM_uint32 default_cred;
+gss_OID_set *elements_stored;
+gss_cred_usage_t *cred_usage_stored;
+
+{
+ return gss_store_cred_into(minor_status, input_cred_handle, cred_usage,
+ desired_mech, overwrite_cred, default_cred,
+ GSS_C_NO_CRED_STORE, elements_stored,
+ cred_usage_stored);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_store_cred_into(minor_status,
+ input_cred_handle,
+ cred_usage,
+ desired_mech,
+ overwrite_cred,
+ default_cred,
+ cred_store,
+ elements_stored,
+ cred_usage_stored)
+
+OM_uint32 *minor_status;
+gss_cred_id_t input_cred_handle;
+gss_cred_usage_t cred_usage;
+gss_OID desired_mech;
+OM_uint32 overwrite_cred;
+OM_uint32 default_cred;
+gss_const_key_value_set_t cred_store;
+gss_OID_set *elements_stored;
+gss_cred_usage_t *cred_usage_stored;
+
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ gss_union_cred_t union_cred;
+ gss_cred_id_t mech_cred;
+ gss_mechanism mech;
+ gss_OID dmech;
+ gss_OID selected_mech;
+ int i;
+
+ major_status = val_store_cred_args(minor_status,
+ input_cred_handle,
+ cred_usage,
+ desired_mech,
+ overwrite_cred,
+ default_cred,
+ cred_store,
+ elements_stored,
+ cred_usage_stored);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ /* Initial value needed below. */
+ major_status = GSS_S_FAILURE;
+
+ if (cred_usage_stored != NULL)
+ *cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
+
+ union_cred = (gss_union_cred_t)input_cred_handle;
+
+ /* desired_mech != GSS_C_NULL_OID -> store one element */
+ if (desired_mech != GSS_C_NULL_OID) {
+ major_status = gssint_select_mech_type(minor_status,
+ desired_mech,
+ &selected_mech);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ mech = gssint_get_mechanism(selected_mech);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_store_cred_into == NULL &&
+ cred_store != GSS_C_NO_CRED_STORE)
+ return (major_status);
+
+ if (mech->gss_store_cred == NULL &&
+ mech->gss_store_cred_into == NULL)
+ return (major_status);
+
+ mech_cred = gssint_get_mechanism_cred(union_cred, selected_mech);
+ if (mech_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ major_status = store_cred_fallback(minor_status, mech,
+ mech_cred, cred_usage,
+ selected_mech,
+ overwrite_cred,
+ default_cred, cred_store,
+ elements_stored,
+ cred_usage_stored);
+ if (major_status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return major_status;
+ }
+
+ /* desired_mech == GSS_C_NULL_OID -> store all elements */
+
+ *minor_status = 0;
+
+ for (i = 0; i < union_cred->count; i++) {
+ /* Get mech and cred element */
+ dmech = &union_cred->mechs_array[i];
+ mech = gssint_get_mechanism(dmech);
+ if (mech == NULL)
+ continue;
+
+ if (mech->gss_store_cred_into == NULL &&
+ cred_store != GSS_C_NO_CRED_STORE)
+ continue;
+
+ if (mech->gss_store_cred == NULL &&
+ mech->gss_store_cred_into == NULL)
+ continue;
+
+ mech_cred = gssint_get_mechanism_cred(union_cred, dmech);
+ if (mech_cred == GSS_C_NO_CREDENTIAL)
+ continue; /* can't happen, but safe to ignore */
+
+ major_status = store_cred_fallback(minor_status, mech,
+ mech_cred, cred_usage,
+ dmech, overwrite_cred,
+ default_cred, cred_store,
+ NULL, cred_usage_stored);
+ if (major_status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ continue;
+ }
+
+ /* Succeeded for at least one mech */
+
+ if (elements_stored == NULL)
+ continue;
+
+ if (*elements_stored == GSS_C_NULL_OID_SET) {
+ major_status = gss_create_empty_oid_set(minor_status,
+ elements_stored);
+
+ if (GSS_ERROR(major_status))
+ return (major_status);
+ }
+
+ major_status = gss_add_oid_set_member(minor_status, dmech,
+ elements_stored);
+
+ /* The caller should clean up elements_stored */
+ if (GSS_ERROR(major_status))
+ return (major_status);
+ }
+
+ /*
+ * Success with some mechs may mask failure with others, but
+ * that's what elements_stored is for.
+ */
+ return (major_status);
+}
diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c
new file mode 100644
index 000000000000..3e8053c6e9af
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_unseal.c
@@ -0,0 +1,130 @@
+/* #pragma ident "@(#)g_unseal.c 1.13 98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine gss_unwrap
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_unwrap (minor_status,
+ context_handle,
+ input_message_buffer,
+ output_message_buffer,
+ conf_state,
+ qop_state)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t input_message_buffer;
+gss_buffer_t output_message_buffer;
+int * conf_state;
+gss_qop_t * qop_state;
+
+{
+/* EXPORT DELETE START */
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_message_buffer != GSS_C_NO_BUFFER) {
+ output_message_buffer->length = 0;
+ output_message_buffer->value = NULL;
+ }
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (input_message_buffer == GSS_C_NO_BUFFER ||
+ GSS_EMPTY_BUFFER(input_message_buffer))
+
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (output_message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_unwrap) {
+ status = mech->gss_unwrap(minor_status,
+ ctx->internal_ctx_id,
+ input_message_buffer,
+ output_message_buffer,
+ conf_state,
+ qop_state);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else if (mech->gss_unwrap_aead || mech->gss_unwrap_iov) {
+ status = gssint_unwrap_aead(mech,
+ minor_status,
+ ctx,
+ input_message_buffer,
+ GSS_C_NO_BUFFER,
+ output_message_buffer,
+ conf_state,
+ (gss_qop_t *)qop_state);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+
+/* EXPORT DELETE END */
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_unseal (minor_status,
+ context_handle,
+ input_message_buffer,
+ output_message_buffer,
+ conf_state,
+ qop_state)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t input_message_buffer;
+gss_buffer_t output_message_buffer;
+int * conf_state;
+int * qop_state;
+
+{
+ return (gss_unwrap(minor_status, context_handle,
+ input_message_buffer,
+ output_message_buffer, conf_state, (gss_qop_t *) qop_state));
+}
diff --git a/src/lib/gssapi/mechglue/g_unwrap_aead.c b/src/lib/gssapi/mechglue/g_unwrap_aead.c
new file mode 100644
index 000000000000..e78bff2d3289
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_unwrap_aead.c
@@ -0,0 +1,197 @@
+/* #pragma ident "@(#)g_seal.c 1.19 98/04/21 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_unwrap_aead
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_unwrap_aead_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (input_message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (output_payload_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+gssint_unwrap_aead_iov_shim(gss_mechanism mech,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 status;
+ gss_iov_buffer_desc iov[3];
+ int i = 0;
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_STREAM;
+ iov[i].buffer = *input_message_buffer;
+ i++;
+
+ if (input_assoc_buffer != NULL) {
+ iov[i].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[i].buffer = *input_assoc_buffer;
+ i++;
+ }
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[i].buffer.value = NULL;
+ iov[i].buffer.length = 0;
+ i++;
+
+ assert(mech->gss_unwrap_iov);
+
+ status = mech->gss_unwrap_iov(minor_status, context_handle, conf_state,
+ qop_state, iov, i);
+ if (status == GSS_S_COMPLETE) {
+ *output_payload_buffer = iov[i - 1].buffer;
+ } else {
+ OM_uint32 minor;
+
+ map_error(minor_status, mech);
+
+ if (iov[i - 1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ gss_release_buffer(&minor, &iov[i - 1].buffer);
+ iov[i - 1].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+ }
+
+ return status;
+}
+
+OM_uint32
+gssint_unwrap_aead (gss_mechanism mech,
+ OM_uint32 *minor_status,
+ gss_union_ctx_id_t ctx,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 status;
+
+ assert(mech != NULL);
+ assert(ctx != NULL);
+
+ /* EXPORT DELETE START */
+
+ if (mech->gss_unwrap_aead) {
+ status = mech->gss_unwrap_aead(minor_status,
+ ctx->internal_ctx_id,
+ input_message_buffer,
+ input_assoc_buffer,
+ output_payload_buffer,
+ conf_state,
+ qop_state);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else if (mech->gss_unwrap_iov) {
+ status = gssint_unwrap_aead_iov_shim(mech,
+ minor_status,
+ ctx->internal_ctx_id,
+ input_message_buffer,
+ input_assoc_buffer,
+ output_payload_buffer,
+ conf_state,
+ qop_state);
+ } else
+ status = GSS_S_UNAVAILABLE;
+ /* EXPORT DELETE END */
+
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_unwrap_aead (minor_status,
+ context_handle,
+ input_message_buffer,
+ input_assoc_buffer,
+ output_payload_buffer,
+ conf_state,
+ qop_state)
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t input_message_buffer;
+gss_buffer_t input_assoc_buffer;
+gss_buffer_t output_payload_buffer;
+int *conf_state;
+gss_qop_t *qop_state;
+{
+
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_unwrap_aead_args(minor_status, context_handle,
+ input_message_buffer, input_assoc_buffer,
+ output_payload_buffer,
+ conf_state, qop_state);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ return gssint_unwrap_aead(mech, minor_status, ctx,
+ input_message_buffer, input_assoc_buffer,
+ output_payload_buffer, conf_state, qop_state);
+}
diff --git a/src/lib/gssapi/mechglue/g_unwrap_iov.c b/src/lib/gssapi/mechglue/g_unwrap_iov.c
new file mode 100644
index 000000000000..c0dd314b1be8
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_unwrap_iov.c
@@ -0,0 +1,141 @@
+/* #pragma ident "@(#)g_seal.c 1.19 98/04/21 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_unwrap_iov
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_unwrap_iov_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_unwrap_iov (minor_status,
+ context_handle,
+ conf_state,
+ qop_state,
+ iov,
+ iov_count)
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+int * conf_state;
+gss_qop_t *qop_state;
+gss_iov_buffer_desc * iov;
+int iov_count;
+{
+ /* EXPORT DELETE START */
+
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_unwrap_iov_args(minor_status, context_handle,
+ conf_state, qop_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_unwrap_iov) {
+ status = mech->gss_unwrap_iov(
+ minor_status,
+ ctx->internal_ctx_id,
+ conf_state,
+ qop_state,
+ iov,
+ iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+ /* EXPORT DELETE END */
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_unwrap_iov_args(minor_status, context_handle, NULL,
+ qop_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ /* Select the approprate underlying mechanism routine and call it. */
+ ctx = (gss_union_ctx_id_t)context_handle;
+ mech = gssint_get_mechanism(ctx->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+ if (mech->gss_verify_mic_iov == NULL)
+ return GSS_S_UNAVAILABLE;
+ status = mech->gss_verify_mic_iov(minor_status, ctx->internal_ctx_id,
+ qop_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c
new file mode 100644
index 000000000000..1578ae111092
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_verify.c
@@ -0,0 +1,106 @@
+/* #pragma ident "@(#)g_verify.c 1.13 98/04/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_verify_mic
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic (minor_status,
+ context_handle,
+ message_buffer,
+ token_buffer,
+ qop_state)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t message_buffer;
+gss_buffer_t token_buffer;
+gss_qop_t * qop_state;
+
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if ((message_buffer == GSS_C_NO_BUFFER) ||
+ GSS_EMPTY_BUFFER(token_buffer))
+
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_verify_mic) {
+ status = mech->gss_verify_mic(
+ minor_status,
+ ctx->internal_ctx_id,
+ message_buffer,
+ token_buffer,
+ qop_state);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_verify (minor_status,
+ context_handle,
+ message_buffer,
+ token_buffer,
+ qop_state)
+
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+gss_buffer_t message_buffer;
+gss_buffer_t token_buffer;
+int * qop_state;
+
+{
+ return (gss_verify_mic(minor_status, context_handle,
+ message_buffer, token_buffer,
+ (gss_qop_t *) qop_state));
+}
diff --git a/src/lib/gssapi/mechglue/g_wrap_aead.c b/src/lib/gssapi/mechglue/g_wrap_aead.c
new file mode 100644
index 000000000000..96cdf3ce6ab8
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_wrap_aead.c
@@ -0,0 +1,267 @@
+/* #pragma ident "@(#)g_seal.c 1.19 98/04/21 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_wrap_aead
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_wrap_aead_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (input_payload_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (output_message_buffer == GSS_C_NO_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+gssint_wrap_aead_iov_shim(gss_mechanism mech,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ gss_iov_buffer_desc iov[5];
+ OM_uint32 status;
+ size_t offset;
+ int i = 0, iov_count;
+
+ /* HEADER | SIGN_ONLY_DATA | DATA | PADDING | TRAILER */
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[i].buffer.value = NULL;
+ iov[i].buffer.length = 0;
+ i++;
+
+ if (input_assoc_buffer != GSS_C_NO_BUFFER) {
+ iov[i].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[i].buffer = *input_assoc_buffer;
+ i++;
+ }
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[i].buffer = *input_payload_buffer;
+ i++;
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_PADDING;
+ iov[i].buffer.value = NULL;
+ iov[i].buffer.length = 0;
+ i++;
+
+ iov[i].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[i].buffer.value = NULL;
+ iov[i].buffer.length = 0;
+ i++;
+
+ iov_count = i;
+
+ assert(mech->gss_wrap_iov_length);
+
+ status = mech->gss_wrap_iov_length(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ NULL, iov, iov_count);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ return status;
+ }
+
+ /* Format output token (does not include associated data) */
+ for (i = 0, output_message_buffer->length = 0; i < iov_count; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ continue;
+
+ output_message_buffer->length += iov[i].buffer.length;
+ }
+
+ output_message_buffer->value = gssalloc_malloc(output_message_buffer->length);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ i = 0, offset = 0;
+
+ /* HEADER */
+ iov[i].buffer.value = (unsigned char *)output_message_buffer->value + offset;
+ offset += iov[i].buffer.length;
+ i++;
+
+ /* SIGN_ONLY_DATA */
+ if (input_assoc_buffer != GSS_C_NO_BUFFER)
+ i++;
+
+ /* DATA */
+ iov[i].buffer.value = (unsigned char *)output_message_buffer->value + offset;
+ offset += iov[i].buffer.length;
+
+ memcpy(iov[i].buffer.value, input_payload_buffer->value, iov[i].buffer.length);
+ i++;
+
+ /* PADDING */
+ iov[i].buffer.value = (unsigned char *)output_message_buffer->value + offset;
+ offset += iov[i].buffer.length;
+ i++;
+
+ /* TRAILER */
+ iov[i].buffer.value = (unsigned char *)output_message_buffer->value + offset;
+ offset += iov[i].buffer.length;
+ i++;
+
+ assert(offset == output_message_buffer->length);
+
+ assert(mech->gss_wrap_iov);
+
+ status = mech->gss_wrap_iov(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE) {
+ OM_uint32 minor;
+
+ map_error(minor_status, mech);
+ gss_release_buffer(&minor, output_message_buffer);
+ }
+
+ return status;
+}
+
+OM_uint32
+gssint_wrap_aead (gss_mechanism mech,
+ OM_uint32 *minor_status,
+ gss_union_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ /* EXPORT DELETE START */
+ OM_uint32 status;
+
+ assert(ctx != NULL);
+ assert(mech != NULL);
+
+ if (mech->gss_wrap_aead) {
+ status = mech->gss_wrap_aead(minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag,
+ qop_req,
+ input_assoc_buffer,
+ input_payload_buffer,
+ conf_state,
+ output_message_buffer);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else if (mech->gss_wrap_iov && mech->gss_wrap_iov_length) {
+ status = gssint_wrap_aead_iov_shim(mech,
+ minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag,
+ qop_req,
+ input_assoc_buffer,
+ input_payload_buffer,
+ conf_state,
+ output_message_buffer);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ /* EXPORT DELETE END */
+
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_wrap_aead (minor_status,
+ context_handle,
+ conf_req_flag,
+ qop_req,
+ input_assoc_buffer,
+ input_payload_buffer,
+ conf_state,
+ output_message_buffer)
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+int conf_req_flag;
+gss_qop_t qop_req;
+gss_buffer_t input_assoc_buffer;
+gss_buffer_t input_payload_buffer;
+int * conf_state;
+gss_buffer_t output_message_buffer;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+ gss_union_ctx_id_t ctx;
+
+ status = val_wrap_aead_args(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ input_assoc_buffer, input_payload_buffer,
+ conf_state, output_message_buffer);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+ ctx = (gss_union_ctx_id_t)context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ return gssint_wrap_aead(mech, minor_status, ctx,
+ conf_req_flag, qop_req,
+ input_assoc_buffer, input_payload_buffer,
+ conf_state, output_message_buffer);
+}
diff --git a/src/lib/gssapi/mechglue/g_wrap_iov.c b/src/lib/gssapi/mechglue/g_wrap_iov.c
new file mode 100644
index 000000000000..40cd98fc91cd
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_wrap_iov.c
@@ -0,0 +1,261 @@
+/* #pragma ident "@(#)g_seal.c 1.19 98/04/21 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routine for gss_wrap_iov
+ */
+
+#include "mglueP.h"
+
+static OM_uint32
+val_wrap_iov_args(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (context_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_wrap_iov (minor_status,
+ context_handle,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count)
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+int conf_req_flag;
+gss_qop_t qop_req;
+int * conf_state;
+gss_iov_buffer_desc * iov;
+int iov_count;
+{
+ /* EXPORT DELETE START */
+
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_wrap_iov_args(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_wrap_iov) {
+ status = mech->gss_wrap_iov(
+ minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+ /* EXPORT DELETE END */
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_wrap_iov_length (minor_status,
+ context_handle,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count)
+OM_uint32 * minor_status;
+gss_ctx_id_t context_handle;
+int conf_req_flag;
+gss_qop_t qop_req;
+int * conf_state;
+gss_iov_buffer_desc * iov;
+int iov_count;
+{
+ /* EXPORT DELETE START */
+
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_wrap_iov_args(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * select the approprate underlying mechanism routine and
+ * call it.
+ */
+
+ ctx = (gss_union_ctx_id_t) context_handle;
+ mech = gssint_get_mechanism (ctx->mech_type);
+
+ if (mech) {
+ if (mech->gss_wrap_iov_length) {
+ status = mech->gss_wrap_iov_length(
+ minor_status,
+ ctx->internal_ctx_id,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ } else
+ status = GSS_S_UNAVAILABLE;
+
+ return(status);
+ }
+ /* EXPORT DELETE END */
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov, int iov_count)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+ iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ /* Select the approprate underlying mechanism routine and call it. */
+ ctx = (gss_union_ctx_id_t)context_handle;
+ mech = gssint_get_mechanism(ctx->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+ if (mech->gss_get_mic_iov == NULL)
+ return GSS_S_UNAVAILABLE;
+ status = mech->gss_get_mic_iov(minor_status, ctx->internal_ctx_id, qop_req,
+ iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 status;
+ gss_union_ctx_id_t ctx;
+ gss_mechanism mech;
+
+ status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+ iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ /* Select the approprate underlying mechanism routine and call it. */
+ ctx = (gss_union_ctx_id_t)context_handle;
+ mech = gssint_get_mechanism(ctx->mech_type);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+ if (mech->gss_get_mic_iov_length == NULL)
+ return GSS_S_UNAVAILABLE;
+ status = mech->gss_get_mic_iov_length(minor_status, ctx->internal_ctx_id,
+ qop_req, iov, iov_count);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ return status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_release_iov_buffer (minor_status,
+ iov,
+ iov_count)
+OM_uint32 * minor_status;
+gss_iov_buffer_desc * iov;
+int iov_count;
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ int i;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return GSS_S_COMPLETE;
+
+ for (i = 0; i < iov_count; i++) {
+ if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ status = gss_release_buffer(minor_status, &iov[i].buffer);
+ if (status != GSS_S_COMPLETE)
+ break;
+
+ iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+ }
+
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/gssd_pname_to_uid.c b/src/lib/gssapi/mechglue/gssd_pname_to_uid.c
new file mode 100644
index 000000000000..4caa751657b7
--- /dev/null
+++ b/src/lib/gssapi/mechglue/gssd_pname_to_uid.c
@@ -0,0 +1,226 @@
+/* #pragma ident "@(#)gssd_pname_to_uid.c 1.18 04/02/23 SMI" */
+/*
+ * Copyright (c) 2011, PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of PADL Software nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * glue routines that test the mech id either passed in to
+ * gss_init_sec_contex() or gss_accept_sec_context() or within the glue
+ * routine supported version of the security context and then call
+ * the appropriate underlying mechanism library procedure.
+ *
+ */
+
+#include "mglueP.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#endif
+
+static OM_uint32
+attr_localname(OM_uint32 *minor,
+ const gss_mechanism mech,
+ const gss_name_t mech_name,
+ gss_buffer_t localname)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE;
+ OM_uint32 tmpMinor;
+ int more = -1;
+ gss_buffer_desc value;
+ gss_buffer_desc display_value;
+ int authenticated = 0, complete = 0;
+
+ value.value = NULL;
+ display_value.value = NULL;
+ if (mech->gss_get_name_attribute == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ major = mech->gss_get_name_attribute(minor,
+ mech_name,
+ GSS_C_ATTR_LOCAL_LOGIN_USER,
+ &authenticated,
+ &complete,
+ &value,
+ &display_value,
+ &more);
+ if (GSS_ERROR(major)) {
+ map_error(minor, mech);
+ goto cleanup;
+ }
+
+ if (!authenticated)
+ major = GSS_S_UNAVAILABLE;
+ else {
+ localname->value = value.value;
+ localname->length = value.length;
+ value.value = NULL;
+ }
+
+cleanup:
+ if (display_value.value)
+ gss_release_buffer(&tmpMinor, &display_value);
+ if (value.value)
+ gss_release_buffer(&tmpMinor, &value);
+ return major;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_localname(OM_uint32 *minor,
+ const gss_name_t pname,
+ gss_const_OID mech_type,
+ gss_buffer_t localname)
+{
+ OM_uint32 major, tmpMinor;
+ gss_mechanism mech;
+ gss_union_name_t unionName;
+ gss_name_t mechName = GSS_C_NO_NAME, mechNameP;
+ gss_OID selected_mech = GSS_C_NO_OID, public_mech;
+
+ if (localname != GSS_C_NO_BUFFER) {
+ localname->length = 0;
+ localname->value = NULL;
+ }
+
+ if (minor == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor = 0;
+
+ if (pname == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (localname == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ unionName = (gss_union_name_t)pname;
+
+ if (mech_type != GSS_C_NO_OID) {
+ major = gssint_select_mech_type(minor, mech_type, &selected_mech);
+ if (major != GSS_S_COMPLETE)
+ return major;
+ mech = gssint_get_mechanism(selected_mech);
+ } else
+ mech = gssint_get_mechanism(unionName->mech_type);
+
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ /* may need to create a mechanism specific name */
+ if (unionName->mech_type == GSS_C_NO_OID ||
+ (unionName->mech_type != GSS_C_NO_OID &&
+ !g_OID_equal(unionName->mech_type, &mech->mech_type))) {
+ major = gssint_import_internal_name(minor, &mech->mech_type,
+ unionName, &mechName);
+ if (GSS_ERROR(major))
+ return major;
+
+ mechNameP = mechName;
+ } else
+ mechNameP = unionName->mech_name;
+
+ major = GSS_S_UNAVAILABLE;
+
+ if (mech->gss_localname != NULL) {
+ public_mech = gssint_get_public_oid(selected_mech);
+ major = mech->gss_localname(minor, mechNameP, public_mech, localname);
+ if (GSS_ERROR(major))
+ map_error(minor, mech);
+ }
+
+ if (GSS_ERROR(major))
+ major = attr_localname(minor, mech, mechNameP, localname);
+
+ if (mechName != GSS_C_NO_NAME)
+ gssint_release_internal_name(&tmpMinor, &mech->mech_type, &mechName);
+
+ return major;
+}
+
+#ifndef _WIN32
+OM_uint32 KRB5_CALLCONV
+gss_pname_to_uid(OM_uint32 *minor,
+ const gss_name_t name,
+ const gss_OID mech_type,
+ uid_t *uidOut)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE, tmpminor;
+#ifndef NO_PASSWORD
+ gss_buffer_desc localname;
+ char pwbuf[BUFSIZ];
+ char *localuser = NULL;
+ struct passwd *pwd = NULL;
+ struct passwd pw;
+ int code = 0;
+
+ localname.value = NULL;
+ major = gss_localname(minor, name, mech_type, &localname);
+ if (!GSS_ERROR(major) && localname.value) {
+ localuser = malloc(localname.length + 1);
+ if (localuser == NULL)
+ code = ENOMEM;
+ if (code == 0) {
+ memcpy(localuser, localname.value, localname.length);
+ localuser[localname.length] = '\0';
+ code = k5_getpwnam_r(localuser, &pw, pwbuf, sizeof(pwbuf), &pwd);
+ }
+ if ((code == 0) && pwd)
+ *uidOut = pwd->pw_uid;
+ else
+ major = GSS_S_FAILURE;
+ }
+ free(localuser);
+ if (localname.value)
+ gss_release_buffer(&tmpminor, &localname);
+#endif /*NO_PASSWORD*/
+ return major;
+}
+#endif /*_WIN32*/
diff --git a/src/lib/gssapi/mechglue/mechglue.h b/src/lib/gssapi/mechglue/mechglue.h
new file mode 100644
index 000000000000..85983694a258
--- /dev/null
+++ b/src/lib/gssapi/mechglue/mechglue.h
@@ -0,0 +1,42 @@
+/* #ident "@(#)mechglue.h 1.13 95/08/07 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS 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.
+ */
+
+/*
+ * This header contains the mechglue definitions.
+ */
+
+#ifndef _GSS_MECHGLUE_H
+#define _GSS_MECHGLUE_H
+
+#include <gssapi/gssapi.h>
+
+/********************************************************/
+/* GSSAPI Extension functions -- these functions aren't */
+/* in the GSSAPI, but they are provided in this library */
+
+#include <gssapi/gssapi_ext.h>
+
+void KRB5_CALLCONV gss_initialize(void);
+
+#endif /* _GSS_MECHGLUE_H */
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
new file mode 100644
index 000000000000..2b5145e079fe
--- /dev/null
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -0,0 +1,854 @@
+/* lib/gssapi/mechglue/mglueP.h */
+
+/*
+ * Copyright (c) 1995, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* This header contains the private mechglue definitions. */
+
+#ifndef _GSS_MECHGLUEP_H
+#define _GSS_MECHGLUEP_H
+
+#include "autoconf.h"
+#include "mechglue.h"
+#include "gssapiP_generic.h"
+
+#define g_OID_copy(o1, o2) \
+do { \
+ memcpy((o1)->elements, (o2)->elements, (o2)->length); \
+ (o1)->length = (o2)->length; \
+} while (0)
+
+/*
+ * Array of context IDs typed by mechanism OID
+ */
+typedef struct gss_union_ctx_id_struct {
+ struct gss_union_ctx_id_struct *loopback;
+ gss_OID mech_type;
+ gss_ctx_id_t internal_ctx_id;
+} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+
+/*
+ * Generic GSSAPI names. A name can either be a generic name, or a
+ * mechanism specific name....
+ */
+typedef struct gss_name_struct {
+ struct gss_name_struct *loopback;
+ gss_OID name_type;
+ gss_buffer_t external_name;
+ /*
+ * These last two fields are only filled in for mechanism
+ * names.
+ */
+ gss_OID mech_type;
+ gss_name_t mech_name;
+} gss_union_name_desc, *gss_union_name_t;
+
+/*
+ * Structure for holding list of mechanism-specific name types
+ */
+typedef struct gss_mech_spec_name_t {
+ gss_OID name_type;
+ gss_OID mech;
+ struct gss_mech_spec_name_t *next, *prev;
+} gss_mech_spec_name_desc, *gss_mech_spec_name;
+
+/*
+ * Set of Credentials typed on mechanism OID
+ */
+typedef struct gss_cred_id_struct {
+ struct gss_cred_id_struct *loopback;
+ int count;
+ gss_OID mechs_array;
+ gss_cred_id_t *cred_array;
+} gss_union_cred_desc, *gss_union_cred_t;
+
+/*
+ * Rudimentary pointer validation macro to check whether the
+ * "loopback" field of an opaque struct points back to itself. This
+ * field also catches some programming errors where an opaque pointer
+ * is passed to a function expecting the address of the opaque
+ * pointer.
+ */
+#define GSSINT_CHK_LOOP(p) (!((p) != NULL && (p)->loopback == (p)))
+
+/********************************************************/
+/* The Mechanism Dispatch Table -- a mechanism needs to */
+/* define one of these and provide a function to return */
+/* it to initialize the GSSAPI library */
+int gssint_mechglue_initialize_library(void);
+
+OM_uint32 gssint_get_mech_type_oid(gss_OID OID, gss_buffer_t token);
+
+/*
+ * This is the definition of the mechs_array struct, which is used to
+ * define the mechs array table. This table is used to indirectly
+ * access mechanism specific versions of the gssapi routines through
+ * the routines in the glue module (gssd_mech_glue.c)
+ *
+ * This contants all of the functions defined in gssapi.h except for
+ * gss_release_buffer() and gss_release_oid_set(), which I am
+ * assuming, for now, to be equal across mechanisms.
+ */
+
+typedef struct gss_config {
+ gss_OID_desc mech_type;
+ void * context;
+ OM_uint32 (KRB5_CALLCONV *gss_acquire_cred)
+ (
+ OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ int, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_release_cred)
+ (
+ OM_uint32*, /* minor_status */
+ gss_cred_id_t* /* cred_handle */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_init_sec_context)
+ (
+ OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32* /* time_rec */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_accept_sec_context)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t* /* delegated_cred_handle */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_process_context_token)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t /* token_buffer */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_delete_sec_context)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_buffer_t /* output_token */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_context_time)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ OM_uint32* /* time_rec */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_get_mic)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_verify_mic)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* token_buffer */
+ gss_qop_t* /* qop_state */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_wrap)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int*, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_unwrap)
+ (
+ OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int*, /* conf_state */
+ gss_qop_t* /* qop_state */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_display_status)
+ (
+ OM_uint32*, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32*, /* message_context */
+ gss_buffer_t /* status_string */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_indicate_mechs)
+ (
+ OM_uint32*, /* minor_status */
+ gss_OID_set* /* mech_set */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_compare_name)
+ (
+ OM_uint32*, /* minor_status */
+ gss_name_t, /* name1 */
+ gss_name_t, /* name2 */
+ int* /* name_equal */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_display_name)
+ (
+ OM_uint32*, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID* /* output_name_type */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_import_name)
+ (
+ OM_uint32*, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ gss_name_t* /* output_name */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_release_name)
+ (
+ OM_uint32*, /* minor_status */
+ gss_name_t* /* input_name */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ int *, /* cred_usage */
+ gss_OID_set * /* mechanisms */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_add_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_name_t, /* desired_name */
+ gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 * /* acceptor_time_rec */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_export_sec_context)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* interprocess_token */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_import_sec_context)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_cred_by_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t * /* cred_usage */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_names_for_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_context)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_name_t *, /* src_name */
+ gss_name_t *, /* targ_name */
+ OM_uint32 *, /* lifetime_rec */
+ gss_OID *, /* mech_type */
+ OM_uint32 *, /* ctx_flags */
+ int *, /* locally_initiated */
+ int * /* open */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_internal_release_oid)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_OID * /* OID */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_wrap_size_limit)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 * /* max_input_size */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_localname)
+ (
+ OM_uint32 *, /* minor */
+ const gss_name_t, /* name */
+ gss_const_OID, /* mech_type */
+ gss_buffer_t /* localname */
+ );
+ OM_uint32 (KRB5_CALLCONV *gssspi_authorize_localname)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* pname */
+ gss_const_buffer_t, /* local user */
+ gss_const_OID /* local nametype */
+ /* */);
+ OM_uint32 (KRB5_CALLCONV *gss_export_name)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+ /* */);
+ OM_uint32 (KRB5_CALLCONV *gss_duplicate_name)
+ (
+ OM_uint32*, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_name_t * /* output_name */
+ /* */);
+ OM_uint32 (KRB5_CALLCONV *gss_store_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* input_cred */
+ gss_cred_usage_t, /* cred_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t * /* cred_usage_stored */
+ /* */);
+
+
+ /* GGF extensions */
+
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_sec_context_by_oid)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ const gss_OID, /* OID */
+ gss_buffer_set_t * /* data_set */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_cred_by_oid)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* cred_handle */
+ const gss_OID, /* OID */
+ gss_buffer_set_t * /* data_set */
+ );
+ OM_uint32 (KRB5_CALLCONV *gss_set_sec_context_option)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ const gss_OID, /* OID */
+ const gss_buffer_t /* value */
+ );
+ OM_uint32 (KRB5_CALLCONV *gssspi_set_cred_option)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t *, /* cred_handle */
+ const gss_OID, /* OID */
+ const gss_buffer_t /* value */
+ );
+ OM_uint32 (KRB5_CALLCONV *gssspi_mech_invoke)
+ (
+ OM_uint32*, /* minor_status */
+ const gss_OID, /* mech OID */
+ const gss_OID, /* OID */
+ gss_buffer_t /* value */
+ );
+
+ /* AEAD extensions */
+ OM_uint32 (KRB5_CALLCONV *gss_wrap_aead)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_assoc_buffer */
+ gss_buffer_t, /* input_payload_buffer */
+ int *, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_unwrap_aead)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* input_assoc_buffer */
+ gss_buffer_t, /* output_payload_buffer */
+ int *, /* conf_state */
+ gss_qop_t * /* qop_state */
+ /* */);
+
+ /* SSPI extensions */
+ OM_uint32 (KRB5_CALLCONV *gss_wrap_iov)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_unwrap_iov)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int *, /* conf_state */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_wrap_iov_length)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag*/
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_complete_auth_token)
+ (
+ OM_uint32*, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ gss_buffer_t /* input_message_buffer */
+ );
+
+ /* New for 1.8 */
+
+ OM_uint32 (KRB5_CALLCONV *gss_acquire_cred_impersonate_name)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_add_cred_impersonate_name)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 * /* acceptor_time_rec */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_display_name_ext)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_OID, /* display_as_name_type */
+ gss_buffer_t /* display_name */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_name)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int *, /* name_is_MN */
+ gss_OID *, /* MN_mech */
+ gss_buffer_set_t * /* attrs */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_get_name_attribute)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t, /* attr */
+ int *, /* authenticated */
+ int *, /* complete */
+ gss_buffer_t, /* value */
+ gss_buffer_t, /* display_value */
+ int * /* more */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_set_name_attribute)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int, /* complete */
+ gss_buffer_t, /* attr */
+ gss_buffer_t /* value */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_delete_name_attribute)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t /* attr */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_export_name_composite)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t /* exp_composite_name */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_map_name_to_any)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ int, /* authenticated */
+ gss_buffer_t, /* type_id */
+ gss_any_t * /* output */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_release_any_name_mapping)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* name */
+ gss_buffer_t, /* type_id */
+ gss_any_t * /* input */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_pseudo_random)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context */
+ int, /* prf_key */
+ const gss_buffer_t, /* prf_in */
+ ssize_t, /* desired_output_len */
+ gss_buffer_t /* prf_out */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_set_neg_mechs)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ const gss_OID_set /* mech_set */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_saslname_for_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_OID, /* desired_mech */
+ gss_buffer_t, /* sasl_mech_name */
+ gss_buffer_t, /* mech_name */
+ gss_buffer_t /* mech_description */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_mech_for_saslname)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_buffer_t, /* sasl_mech_name */
+ gss_OID * /* mech_type */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_inquire_attrs_for_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_const_OID, /* mech */
+ gss_OID_set *, /* mech_attrs */
+ gss_OID_set * /* known_mech_attrs */
+ /* */);
+
+ /* Credential store extensions */
+
+ OM_uint32 (KRB5_CALLCONV *gss_acquire_cred_from)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_store_cred_into)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_cred_usage_t, /* input_usage */
+ gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t * /* cred_usage_stored */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gssspi_acquire_cred_with_password)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ const gss_buffer_t, /* password */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ int, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_export_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_buffer_t /* token */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gss_import_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* token */
+ gss_cred_id_t * /* cred_handle */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gssspi_import_sec_context_by_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* desired_mech */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gssspi_import_name_by_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mech_type */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ gss_name_t* /* output_name */
+ /* */);
+
+ OM_uint32 (KRB5_CALLCONV *gssspi_import_cred_by_mech)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mech_type */
+ gss_buffer_t, /* token */
+ gss_cred_id_t * /* cred_handle */
+ /* */);
+
+ /* get_mic_iov extensions, added in 1.12 */
+
+ OM_uint32 (KRB5_CALLCONV *gss_get_mic_iov)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ );
+
+ OM_uint32 (KRB5_CALLCONV *gss_verify_mic_iov)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ );
+
+ OM_uint32 (KRB5_CALLCONV *gss_get_mic_iov_length)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+ );
+
+} *gss_mechanism;
+
+/*
+ * In the user space we use a wrapper structure to encompass the
+ * mechanism entry points. The wrapper contain the mechanism
+ * entry points and other data which is only relevant to the gss-api
+ * layer. In the kernel we use only the gss_config strucutre because
+ * the kernal does not cantain any of the extra gss-api specific data.
+ */
+typedef struct gss_mech_config {
+ char *kmodName; /* kernel module name */
+ char *uLibName; /* user library name */
+ char *mechNameStr; /* mechanism string name */
+ char *optionStr; /* optional mech parameters */
+ void *dl_handle; /* RTLD object handle for the mech */
+ gss_OID mech_type; /* mechanism oid */
+ gss_mechanism mech; /* mechanism initialization struct */
+ int priority; /* mechanism preference order */
+ int freeMech; /* free mech table */
+ int is_interposer; /* interposer mechanism flag */
+ gss_OID int_mech_type; /* points to the interposer OID */
+ gss_mechanism int_mech; /* points to the interposer mech */
+ struct gss_mech_config *next; /* next element in the list */
+} *gss_mech_info;
+
+/********************************************************/
+/* Internal mechglue routines */
+
+#if 0
+int gssint_mechglue_init(void);
+void gssint_mechglue_fini(void);
+#endif
+
+OM_uint32 gssint_select_mech_type(OM_uint32 *minor, gss_const_OID in_oid,
+ gss_OID *selected_oid);
+gss_OID gssint_get_public_oid(gss_const_OID internal_oid);
+OM_uint32 gssint_make_public_oid_set(OM_uint32 *minor_status, gss_OID oids,
+ int count, gss_OID_set *public_set);
+gss_mechanism gssint_get_mechanism (gss_const_OID);
+OM_uint32 gssint_get_mech_type (gss_OID, gss_buffer_t);
+char *gssint_get_kmodName(const gss_OID);
+char *gssint_get_modOptions(const gss_OID);
+OM_uint32 gssint_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
+ gss_name_t *);
+OM_uint32 gssint_export_internal_name(OM_uint32 *, const gss_OID,
+ const gss_name_t, gss_buffer_t);
+OM_uint32 gssint_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
+ gss_buffer_t, gss_OID *);
+OM_uint32 gssint_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
+OM_uint32 gssint_delete_internal_sec_context (OM_uint32 *, gss_OID,
+ gss_ctx_id_t *, gss_buffer_t);
+#ifdef _GSS_STATIC_LINK
+int gssint_register_mechinfo(gss_mech_info template);
+#endif
+
+OM_uint32 gssint_convert_name_to_union_name
+ (OM_uint32 *, /* minor_status */
+ gss_mechanism, /* mech */
+ gss_name_t, /* internal_name */
+ gss_name_t * /* external_name */
+ );
+gss_cred_id_t gssint_get_mechanism_cred
+ (gss_union_cred_t, /* union_cred */
+ gss_OID /* mech_type */
+ );
+
+OM_uint32 gssint_create_copy_buffer(
+ const gss_buffer_t, /* src buffer */
+ gss_buffer_t *, /* destination buffer */
+ int /* NULL terminate buffer ? */
+);
+
+OM_uint32 gssint_copy_oid_set(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_set_desc * const, /* oid set */
+ gss_OID_set * /* new oid set */
+);
+
+gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
+
+OM_uint32 gss_add_mech_name_type
+ (OM_uint32 *, /* minor_status */
+ gss_OID, /* name_type */
+ gss_OID /* mech */
+ );
+
+/*
+ * Sun extensions to GSS-API v2
+ */
+
+int
+gssint_get_der_length(
+ unsigned char **, /* buf */
+ unsigned int, /* buf_len */
+ unsigned int * /* bytes */
+);
+
+unsigned int
+gssint_der_length_size(unsigned int /* len */);
+
+int
+gssint_put_der_length(
+ unsigned int, /* length */
+ unsigned char **, /* buf */
+ unsigned int /* max_len */
+);
+
+OM_uint32
+gssint_wrap_aead (gss_mechanism, /* mech */
+ OM_uint32 *, /* minor_status */
+ gss_union_ctx_id_t, /* ctx */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req_flag */
+ gss_buffer_t, /* input_assoc_buffer */
+ gss_buffer_t, /* input_payload_buffer */
+ int *, /* conf_state */
+ gss_buffer_t); /* output_message_buffer */
+OM_uint32
+gssint_unwrap_aead (gss_mechanism, /* mech */
+ OM_uint32 *, /* minor_status */
+ gss_union_ctx_id_t, /* ctx */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* input_assoc_buffer */
+ gss_buffer_t, /* output_payload_buffer */
+ int *, /* conf_state */
+ gss_qop_t *); /* qop_state */
+
+
+/* Use this to map an error code that was returned from a mech
+ operation; the mech will be asked to produce the associated error
+ messages.
+
+ Remember that if the minor status code cannot be returned to the
+ caller (e.g., if it's stuffed in an automatic variable and then
+ ignored), then we don't care about producing a mapping. */
+#define map_error(MINORP, MECH) \
+ (*(MINORP) = gssint_mecherrmap_map(*(MINORP), &(MECH)->mech_type))
+#define map_error_oid(MINORP, MECHOID) \
+ (*(MINORP) = gssint_mecherrmap_map(*(MINORP), (MECHOID)))
+
+/* Use this to map an errno value or com_err error code being
+ generated within the mechglue code (e.g., by calling generic oid
+ ops). Any errno or com_err values produced by mech operations
+ should be processed with map_error. This means they'll be stored
+ separately even if the mech uses com_err, because we can't assume
+ that it will use com_err. */
+#define map_errcode(MINORP) \
+ (*(MINORP) = gssint_mecherrmap_map_errcode(*(MINORP)))
+
+#endif /* _GSS_MECHGLUEP_H */
diff --git a/src/lib/gssapi/spnego/Makefile.in b/src/lib/gssapi/spnego/Makefile.in
new file mode 100644
index 000000000000..c21ea230ca2a
--- /dev/null
+++ b/src/lib/gssapi/spnego/Makefile.in
@@ -0,0 +1,24 @@
+mydir=lib$(S)gssapi$(S)spnego
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+DEFINES=-D_GSS_STATIC_LINK=1
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=spnego
+##DOS##OBJFILE = ..\$(OUTPRE)spnego.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+SRCS = $(srcdir)/spnego_mech.c
+
+OBJS = $(OUTPRE)spnego_mech.$(OBJEXT)
+
+STLIBOBJS = spnego_mech.o
+
+all-unix: all-libobjs
+
+##DOS##LIBOBJS = $(OBJS)
+
+clean-unix:: clean-libobjs
+
+@libobj_frag@
diff --git a/src/lib/gssapi/spnego/deps b/src/lib/gssapi/spnego/deps
new file mode 100644
index 000000000000..feb409e732d5
--- /dev/null
+++ b/src/lib/gssapi/spnego/deps
@@ -0,0 +1,18 @@
+#
+# Generated makefile dependencies follow.
+#
+spnego_mech.so spnego_mech.po $(OUTPRE)spnego_mech.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../mechglue/mechglue.h $(srcdir)/../mechglue/mglueP.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_spnego.h spnego_mech.c
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
new file mode 100644
index 000000000000..84c63fc17d2a
--- /dev/null
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -0,0 +1,664 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _GSSAPIP_SPNEGO_H_
+#define _GSSAPIP_SPNEGO_H_
+
+/* #pragma ident "@(#)gssapiP_spnego.h 1.3 03/09/18 SMI" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gssapi/gssapi.h>
+
+#define SEC_CONTEXT_TOKEN 1
+#define SPNEGO_SIZE_OF_INT 4
+
+#define ACCEPT_COMPLETE 0
+#define ACCEPT_INCOMPLETE 1
+#define REJECT 2
+#define REQUEST_MIC 3
+#define ACCEPT_DEFECTIVE_TOKEN 0xffffffffUL
+
+/*
+ * constants for der encoding/decoding routines.
+ */
+
+#define MECH_OID 0x06
+#define OCTET_STRING 0x04
+#define CONTEXT 0xa0
+#define SEQUENCE 0x30
+#define SEQUENCE_OF 0x30
+#define BIT_STRING 0x03
+#define BIT_STRING_LENGTH 0x02
+#define BIT_STRING_PADDING 0x01
+#define ENUMERATED 0x0a
+#define ENUMERATION_LENGTH 1
+#define HEADER_ID 0x60
+#define GENERAL_STRING 0x1b
+
+/*
+ * SPNEGO specific error codes (minor status codes)
+ */
+#define ERR_SPNEGO_NO_MECHS_AVAILABLE 0x20000001
+#define ERR_SPNEGO_NO_CREDS_ACQUIRED 0x20000002
+#define ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR 0x20000003
+#define ERR_SPNEGO_NEGOTIATION_FAILED 0x20000004
+#define ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR 0x20000005
+
+/*
+ * send_token_flag is used to indicate in later steps what type
+ * of token, if any should be sent or processed.
+ * NO_TOKEN_SEND = no token should be sent
+ * INIT_TOKEN_SEND = initial token will be sent
+ * CONT_TOKEN_SEND = continuing tokens to be sent
+ * CHECK_MIC = no token to be sent, but have a MIC to check.
+ * ERROR_TOKEN_SEND = error token from peer needs to be sent.
+ */
+
+typedef enum {NO_TOKEN_SEND, INIT_TOKEN_SEND, CONT_TOKEN_SEND,
+ CHECK_MIC, ERROR_TOKEN_SEND} send_token_flag;
+
+/*
+ * The Mech OID:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ * mechanism(5) spnego(2) }
+ */
+
+#define SPNEGO_OID_LENGTH 6
+#define SPNEGO_OID "\053\006\001\005\005\002"
+
+typedef void *spnego_token_t;
+
+/* spnego name structure for internal representation. */
+typedef struct {
+ gss_OID type;
+ gss_buffer_t buffer;
+ gss_OID mech_type;
+ gss_name_t mech_name;
+} spnego_name_desc, *spnego_name_t;
+
+/* Structure for credential */
+typedef struct {
+ gss_cred_id_t mcred; /* mechglue union of obtainable creds */
+ gss_OID_set neg_mechs; /* app-specified list of allowable mechs */
+ int no_ask_integ; /* do not request integ from mechs */
+} spnego_gss_cred_id_rec, *spnego_gss_cred_id_t;
+
+/* Structure for context handle */
+typedef struct {
+ OM_uint32 magic_num;
+ gss_buffer_desc DER_mechTypes;
+ gss_OID_set mech_set;
+ gss_OID internal_mech; /* alias into mech_set->elements */
+ gss_ctx_id_t ctx_handle;
+ int mic_reqd;
+ int mic_sent;
+ int mic_rcvd;
+ int firstpass;
+ int mech_complete;
+ int nego_done;
+ int initiate;
+ int opened;
+ OM_uint32 ctx_flags;
+ gss_name_t internal_name;
+ gss_OID actual_mech;
+} spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t;
+
+/*
+ * The magic number must be less than a standard pagesize
+ * to avoid a possible collision with a real address.
+ */
+#define SPNEGO_MAGIC_ID 0x00000fed
+
+/* SPNEGO oid declarations */
+extern const gss_OID_desc * const gss_mech_spnego;
+extern const gss_OID_set_desc * const gss_mech_set_spnego;
+
+#if defined(DEBUG) && defined(HAVE_SYSLOG_H)
+#include <syslog.h>
+#define dsyslog(a) syslog(LOG_DEBUG, a)
+#else
+#define dsyslog(a)
+#define SPNEGO_STATIC
+#endif /* DEBUG */
+
+/*
+ * declarations of internal name mechanism functions
+ */
+
+OM_uint32 KRB5_CALLCONV spnego_gss_acquire_cred
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_release_cred
+(
+ OM_uint32 *, /* minor_status */
+ /* CSTYLED */
+ gss_cred_id_t * /* cred_handle */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_init_sec_context
+(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t *, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID *, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 * /* time_rec */
+);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV spnego_gss_accept_sec_context
+(
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_name_t *, /* src_name */
+ gss_OID *, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 *, /* time_rec */
+ /* CSTYLED */
+ gss_cred_id_t * /* delegated_cred_handle */
+);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV spnego_gss_compare_name
+(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* name1 */
+ const gss_name_t, /* name2 */
+ int * /* name_equal */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_display_name
+(
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID * /* output_name_type */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_display_status
+(
+ OM_uint32 *, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32 *, /* message_context */
+ gss_buffer_t /* status_string */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_import_name
+(
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ /* CSTYLED */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_release_name
+(
+ OM_uint32 *, /* minor_status */
+ /* CSTYLED */
+ gss_name_t * /* input_name */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_duplicate_name
+(
+ OM_uint32 *, /* minor_status */
+ /* CSTYLED */
+ const gss_name_t, /* input_name */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_inquire_cred
+(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ int *, /* cred_usage */
+ gss_OID_set * /* mechanisms */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_inquire_names_for_mech
+(
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_unwrap
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_wrap
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_process_context_token
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_delete_sec_context
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_context_time
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec
+);
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV spnego_gss_export_sec_context
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_import_sec_context
+(
+ OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle
+);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV spnego_gss_inquire_context
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *opened
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_wrap_size_limit
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_get_mic
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_verify_mic
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t msg_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_sec_context_by_oid
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_cred_by_oid
+(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_cred_option
+(
+ OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_sec_context_option
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value
+);
+
+#ifdef _GSS_STATIC_LINK
+int gss_spnegoint_lib_init(void);
+void gss_spnegoint_lib_fini(void);
+#else
+gss_mechanism KRB5_CALLCONV gss_mech_initialize(void);
+#endif /* _GSS_STATIC_LINK */
+
+OM_uint32 KRB5_CALLCONV spnego_gss_wrap_aead
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_unwrap_aead
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_wrap_iov
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_unwrap_iov
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV spnego_gss_wrap_iov_length
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_complete_auth_token
+(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_display_name_ext
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_name
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_name_attribute
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_name_attribute
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_delete_name_attribute
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_export_name_composite
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_map_name_to_any
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_release_any_name_mapping
+(
+ OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_pseudo_random
+(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_neg_mechs
+(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_list
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_mech_for_saslname
+(
+ OM_uint32 *minor_status,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_saslname_for_mech
+(
+ OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_attrs_for_mech
+(
+ OM_uint32 *minor_status,
+ gss_const_OID mech,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_from
+(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_export_cred(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ gss_buffer_t token
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_import_cred(
+ OM_uint32 *minor_status,
+ gss_buffer_t token,
+ gss_cred_id_t *cred_handle
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSSAPIP_SPNEGO_H_ */
diff --git a/src/lib/gssapi/spnego/mech_spnego.exports b/src/lib/gssapi/spnego/mech_spnego.exports
new file mode 100644
index 000000000000..9d570e5c058e
--- /dev/null
+++ b/src/lib/gssapi/spnego/mech_spnego.exports
@@ -0,0 +1 @@
+gss_mech_initialize
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
new file mode 100644
index 000000000000..9d6027ce8058
--- /dev/null
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -0,0 +1,4355 @@
+/*
+ * Copyright (C) 2006,2008 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * A module that implements the spnego security mechanism.
+ * It is used to negotiate the security mechanism between
+ * peers using the GSS-API. SPNEGO is specified in RFC 4178.
+ *
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * 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.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
+/* #pragma ident "@(#)spnego_mech.c 1.7 04/09/28 SMI" */
+
+#include <k5-int.h>
+#include <krb5.h>
+#include <mglueP.h>
+#include "gssapiP_spnego.h"
+#include <gssapi_err_generic.h>
+
+
+#undef g_token_size
+#undef g_verify_token_header
+#undef g_make_token_header
+
+#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)
+typedef const gss_OID_desc *gss_OID_const;
+
+/* der routines defined in libgss */
+extern unsigned int gssint_der_length_size(unsigned int);
+extern int gssint_get_der_length(unsigned char **, unsigned int,
+ unsigned int*);
+extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int);
+
+
+/* private routines for spnego_mechanism */
+static spnego_token_t make_spnego_token(const char *);
+static gss_buffer_desc make_err_msg(const char *);
+static int g_token_size(gss_OID_const, unsigned int);
+static int g_make_token_header(gss_OID_const, unsigned int,
+ unsigned char **, unsigned int);
+static int g_verify_token_header(gss_OID_const, unsigned int *,
+ unsigned char **,
+ int, unsigned int);
+static int g_verify_neg_token_init(unsigned char **, unsigned int);
+static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);
+static gss_buffer_t get_input_token(unsigned char **, unsigned int);
+static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);
+static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
+static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t, gss_cred_usage_t,
+ gss_const_key_value_set_t,
+ gss_cred_id_t *, gss_OID_set *,
+ OM_uint32 *);
+static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
+ gss_cred_usage_t, gss_OID_set *);
+static void release_spnego_ctx(spnego_gss_ctx_id_t *);
+static spnego_gss_ctx_id_t create_spnego_ctx(int);
+static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);
+static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);
+static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);
+static int put_negResult(unsigned char **, OM_uint32, unsigned int);
+
+static OM_uint32
+process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, send_token_flag *,
+ spnego_gss_ctx_id_t *);
+static OM_uint32
+init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
+ gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_cont(OM_uint32 *, spnego_gss_ctx_id_t, gss_buffer_t,
+ gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
+ gss_OID, gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
+ gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+ gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
+ OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+acc_ctx_new(OM_uint32 *, gss_buffer_t, spnego_gss_cred_id_t, gss_buffer_t *,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *,
+ spnego_gss_ctx_id_t *);
+static OM_uint32
+acc_ctx_cont(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t, gss_buffer_t *,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
+ gss_buffer_t, gss_OID *, gss_buffer_t,
+ OM_uint32 *, OM_uint32 *, gss_cred_id_t *,
+ OM_uint32 *, send_token_flag *);
+
+static gss_OID
+negotiate_mech(gss_OID_set, gss_OID_set, OM_uint32 *);
+static int
+g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *);
+
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t,
+ int,
+ gss_buffer_t,
+ OM_uint32, gss_buffer_t, send_token_flag,
+ gss_buffer_t);
+static int
+make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
+ gss_buffer_t, send_token_flag,
+ gss_buffer_t);
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *, gss_buffer_t, gss_buffer_t,
+ gss_OID_set *, OM_uint32 *, gss_buffer_t *,
+ gss_buffer_t *);
+static OM_uint32
+get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
+ OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);
+
+static int
+is_kerb_mech(gss_OID oid);
+
+/* SPNEGO oid structure */
+static const gss_OID_desc spnego_oids[] = {
+ {SPNEGO_OID_LENGTH, SPNEGO_OID},
+};
+
+const gss_OID_desc * const gss_mech_spnego = spnego_oids+0;
+static const gss_OID_set_desc spnego_oidsets[] = {
+ {1, (gss_OID) spnego_oids+0},
+};
+const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
+
+static int make_NegHints(OM_uint32 *, gss_buffer_t *);
+static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
+static OM_uint32
+acc_ctx_hints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *, OM_uint32 *,
+ send_token_flag *, spnego_gss_ctx_id_t *);
+
+/*
+ * The Mech OID for SPNEGO:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ * mechanism(5) spnego(2) }
+ */
+static struct gss_config spnego_mechanism =
+{
+ {SPNEGO_OID_LENGTH, SPNEGO_OID},
+ NULL,
+ spnego_gss_acquire_cred,
+ spnego_gss_release_cred,
+ spnego_gss_init_sec_context,
+#ifndef LEAN_CLIENT
+ spnego_gss_accept_sec_context,
+#else
+ NULL,
+#endif /* LEAN_CLIENT */
+ NULL, /* gss_process_context_token */
+ spnego_gss_delete_sec_context, /* gss_delete_sec_context */
+ spnego_gss_context_time, /* gss_context_time */
+ spnego_gss_get_mic, /* gss_get_mic */
+ spnego_gss_verify_mic, /* gss_verify_mic */
+ spnego_gss_wrap, /* gss_wrap */
+ spnego_gss_unwrap, /* gss_unwrap */
+ spnego_gss_display_status,
+ NULL, /* gss_indicate_mechs */
+ spnego_gss_compare_name,
+ spnego_gss_display_name,
+ spnego_gss_import_name,
+ spnego_gss_release_name,
+ spnego_gss_inquire_cred, /* gss_inquire_cred */
+ NULL, /* gss_add_cred */
+#ifndef LEAN_CLIENT
+ spnego_gss_export_sec_context, /* gss_export_sec_context */
+ spnego_gss_import_sec_context, /* gss_import_sec_context */
+#else
+ NULL, /* gss_export_sec_context */
+ NULL, /* gss_import_sec_context */
+#endif /* LEAN_CLIENT */
+ NULL, /* gss_inquire_cred_by_mech */
+ spnego_gss_inquire_names_for_mech,
+ spnego_gss_inquire_context, /* gss_inquire_context */
+ NULL, /* gss_internal_release_oid */
+ spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */
+ NULL, /* gssd_pname_to_uid */
+ NULL, /* gss_userok */
+ NULL, /* gss_export_name */
+ spnego_gss_duplicate_name, /* gss_duplicate_name */
+ NULL, /* gss_store_cred */
+ spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
+ spnego_gss_inquire_cred_by_oid, /* gss_inquire_cred_by_oid */
+ spnego_gss_set_sec_context_option, /* gss_set_sec_context_option */
+ spnego_gss_set_cred_option, /* gssspi_set_cred_option */
+ NULL, /* gssspi_mech_invoke */
+ spnego_gss_wrap_aead,
+ spnego_gss_unwrap_aead,
+ spnego_gss_wrap_iov,
+ spnego_gss_unwrap_iov,
+ spnego_gss_wrap_iov_length,
+ spnego_gss_complete_auth_token,
+ spnego_gss_acquire_cred_impersonate_name,
+ NULL, /* gss_add_cred_impersonate_name */
+ spnego_gss_display_name_ext,
+ spnego_gss_inquire_name,
+ spnego_gss_get_name_attribute,
+ spnego_gss_set_name_attribute,
+ spnego_gss_delete_name_attribute,
+ spnego_gss_export_name_composite,
+ spnego_gss_map_name_to_any,
+ spnego_gss_release_any_name_mapping,
+ spnego_gss_pseudo_random,
+ spnego_gss_set_neg_mechs,
+ spnego_gss_inquire_saslname_for_mech,
+ spnego_gss_inquire_mech_for_saslname,
+ spnego_gss_inquire_attrs_for_mech,
+ spnego_gss_acquire_cred_from,
+ NULL, /* gss_store_cred_into */
+ spnego_gss_acquire_cred_with_password,
+ spnego_gss_export_cred,
+ spnego_gss_import_cred,
+ NULL, /* gssspi_import_sec_context_by_mech */
+ NULL, /* gssspi_import_name_by_mech */
+ NULL, /* gssspi_import_cred_by_mech */
+ spnego_gss_get_mic_iov,
+ spnego_gss_verify_mic_iov,
+ spnego_gss_get_mic_iov_length
+};
+
+#ifdef _GSS_STATIC_LINK
+#include "mglueP.h"
+
+static int gss_spnegomechglue_init(void)
+{
+ struct gss_mech_config mech_spnego;
+
+ memset(&mech_spnego, 0, sizeof(mech_spnego));
+ mech_spnego.mech = &spnego_mechanism;
+ mech_spnego.mechNameStr = "spnego";
+ mech_spnego.mech_type = GSS_C_NO_OID;
+
+ return gssint_register_mechinfo(&mech_spnego);
+}
+#else
+gss_mechanism KRB5_CALLCONV
+gss_mech_initialize(void)
+{
+ return (&spnego_mechanism);
+}
+
+MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
+MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
+int gss_krb5int_lib_init(void);
+#endif /* _GSS_STATIC_LINK */
+
+int gss_spnegoint_lib_init(void)
+{
+ int err;
+
+ err = k5_key_register(K5_KEY_GSS_SPNEGO_STATUS, NULL);
+ if (err)
+ return err;
+
+#ifdef _GSS_STATIC_LINK
+ return gss_spnegomechglue_init();
+#else
+ return 0;
+#endif
+}
+
+void gss_spnegoint_lib_fini(void)
+{
+}
+
+static OM_uint32
+create_spnego_cred(OM_uint32 *minor_status, gss_cred_id_t mcred,
+ spnego_gss_cred_id_t *cred_out)
+{
+ spnego_gss_cred_id_t spcred;
+
+ *cred_out = NULL;
+ spcred = calloc(1, sizeof(spnego_gss_cred_id_rec));
+ if (spcred == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ spcred->mcred = mcred;
+ *cred_out = spcred;
+ return GSS_S_COMPLETE;
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred(OM_uint32 *minor_status,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return spnego_gss_acquire_cred_from(minor_status, desired_name, time_req,
+ desired_mechs, cred_usage, NULL,
+ output_cred_handle, actual_mechs,
+ time_rec);
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_from(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status, tmpmin;
+ gss_OID_set amechs;
+ gss_cred_id_t mcred = NULL;
+ spnego_gss_cred_id_t spcred = NULL;
+ dsyslog("Entering spnego_gss_acquire_cred\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ /* We will obtain a mechglue credential and wrap it in a
+ * spnego_gss_cred_id_rec structure. Allocate the wrapper. */
+ status = create_spnego_cred(minor_status, mcred, &spcred);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ /*
+ * Always use get_available_mechs to collect a list of
+ * mechs for which creds are available.
+ */
+ status = get_available_mechs(minor_status, desired_name,
+ cred_usage, cred_store, &mcred,
+ &amechs, time_rec);
+
+ if (actual_mechs && amechs != GSS_C_NULL_OID_SET) {
+ (void) gssint_copy_oid_set(&tmpmin, amechs, actual_mechs);
+ }
+ (void) gss_release_oid_set(&tmpmin, &amechs);
+
+ if (status == GSS_S_COMPLETE) {
+ spcred->mcred = mcred;
+ *output_cred_handle = (gss_cred_id_t)spcred;
+ } else {
+ free(spcred);
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ }
+
+ dsyslog("Leaving spnego_gss_acquire_cred\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_release_cred(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle)
+{
+ spnego_gss_cred_id_t spcred = NULL;
+
+ dsyslog("Entering spnego_gss_release_cred\n");
+
+ if (minor_status == NULL || cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_COMPLETE);
+
+ spcred = (spnego_gss_cred_id_t)*cred_handle;
+ *cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_release_oid_set(minor_status, &spcred->neg_mechs);
+ gss_release_cred(minor_status, &spcred->mcred);
+ free(spcred);
+
+ dsyslog("Leaving spnego_gss_release_cred\n");
+ return (GSS_S_COMPLETE);
+}
+
+static spnego_gss_ctx_id_t
+create_spnego_ctx(int initiate)
+{
+ spnego_gss_ctx_id_t spnego_ctx = NULL;
+ spnego_ctx = (spnego_gss_ctx_id_t)
+ malloc(sizeof (spnego_gss_ctx_id_rec));
+
+ if (spnego_ctx == NULL) {
+ return (NULL);
+ }
+
+ spnego_ctx->magic_num = SPNEGO_MAGIC_ID;
+ spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
+ spnego_ctx->mech_set = NULL;
+ spnego_ctx->internal_mech = NULL;
+ spnego_ctx->DER_mechTypes.length = 0;
+ spnego_ctx->DER_mechTypes.value = NULL;
+ spnego_ctx->mic_reqd = 0;
+ spnego_ctx->mic_sent = 0;
+ spnego_ctx->mic_rcvd = 0;
+ spnego_ctx->mech_complete = 0;
+ spnego_ctx->nego_done = 0;
+ spnego_ctx->opened = 0;
+ spnego_ctx->initiate = initiate;
+ spnego_ctx->internal_name = GSS_C_NO_NAME;
+ spnego_ctx->actual_mech = GSS_C_NO_OID;
+
+ return (spnego_ctx);
+}
+
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) samba(7165)
+ * gssntlmssp(655) controls(1) spnego_req_mechlistMIC(2) */
+static const gss_OID_desc spnego_req_mechlistMIC_oid =
+ { 11, "\x2B\x06\x01\x04\x01\xB7\x7D\x85\x0F\x01\x02" };
+
+/*
+ * Return nonzero if the mechanism has reason to believe that a mechlistMIC
+ * exchange will be required. Microsoft servers erroneously require SPNEGO
+ * mechlistMIC if they see an internal MIC within an NTLMSSP Authenticate
+ * message, even if NTLMSSP was the preferred mechanism.
+ */
+static int
+mech_requires_mechlistMIC(spnego_gss_ctx_id_t sc)
+{
+ OM_uint32 major, minor;
+ gss_ctx_id_t ctx = sc->ctx_handle;
+ gss_OID oid = (gss_OID)&spnego_req_mechlistMIC_oid;
+ gss_buffer_set_t bufs;
+ int result;
+
+ major = gss_inquire_sec_context_by_oid(&minor, ctx, oid, &bufs);
+ if (major != GSS_S_COMPLETE)
+ return 0;
+
+ /* Report true if the mech returns a single buffer containing a single
+ * byte with value 1. */
+ result = (bufs != NULL && bufs->count == 1 &&
+ bufs->elements[0].length == 1 &&
+ memcmp(bufs->elements[0].value, "\1", 1) == 0);
+ (void) gss_release_buffer_set(&minor, &bufs);
+ return result;
+}
+
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) Microsoft(311)
+ * security(2) mechanisms(2) NTLM(10) */
+static const gss_OID_desc gss_mech_ntlmssp_oid =
+ { 10, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" };
+
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) samba(7165)
+ * gssntlmssp(655) controls(1) ntlmssp_reset_crypto(3) */
+static const gss_OID_desc ntlmssp_reset_crypto_oid =
+ { 11, "\x2B\x06\x01\x04\x01\xB7\x7D\x85\x0F\x01\x03" };
+
+/*
+ * MS-SPNG section 3.3.5.1 warns that the NTLM mechanism requires special
+ * handling of the crypto state to interop with Windows. If the mechanism for
+ * sc is SPNEGO, invoke a mechanism-specific operation on the context to reset
+ * the RC4 state after producing or verifying a MIC. Ignore a result of
+ * GSS_S_UNAVAILABLE for compatibility with older versions of the mechanism
+ * that do not support this functionality.
+ */
+static OM_uint32
+ntlmssp_reset_crypto_state(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ OM_uint32 verify)
+{
+ OM_uint32 major, minor;
+ gss_buffer_desc value;
+
+ if (!g_OID_equal(sc->internal_mech, &gss_mech_ntlmssp_oid))
+ return GSS_S_COMPLETE;
+
+ value.length = sizeof(verify);
+ value.value = &verify;
+ major = gss_set_sec_context_option(&minor, &sc->ctx_handle,
+ (gss_OID)&ntlmssp_reset_crypto_oid,
+ &value);
+ if (major == GSS_S_UNAVAILABLE)
+ return GSS_S_COMPLETE;
+ *minor_status = minor;
+ return major;
+}
+
+/*
+ * Both initiator and acceptor call here to verify and/or create mechListMIC,
+ * and to consistency-check the MIC state. handle_mic is invoked only if the
+ * negotiated mech has completed and supports MICs.
+ */
+static OM_uint32
+handle_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+ int send_mechtok, spnego_gss_ctx_id_t sc,
+ gss_buffer_t *mic_out,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+
+ ret = GSS_S_FAILURE;
+ *mic_out = GSS_C_NO_BUFFER;
+ if (mic_in != GSS_C_NO_BUFFER) {
+ if (sc->mic_rcvd) {
+ /* Reject MIC if we've already received a MIC. */
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ } else if (sc->mic_reqd && !send_mechtok) {
+ /*
+ * If the peer sends the final mechanism token, it
+ * must send the MIC with that token if the
+ * negotiation requires MICs.
+ */
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ret = process_mic(minor_status, mic_in, sc, mic_out,
+ negState, tokflag);
+ if (ret != GSS_S_COMPLETE) {
+ return ret;
+ }
+ if (sc->mic_reqd) {
+ assert(sc->mic_sent || sc->mic_rcvd);
+ }
+ if (sc->mic_sent && sc->mic_rcvd) {
+ ret = GSS_S_COMPLETE;
+ *negState = ACCEPT_COMPLETE;
+ if (*mic_out == GSS_C_NO_BUFFER) {
+ /*
+ * We sent a MIC on the previous pass; we
+ * shouldn't be sending a mechanism token.
+ */
+ assert(!send_mechtok);
+ *tokflag = NO_TOKEN_SEND;
+ } else {
+ *tokflag = CONT_TOKEN_SEND;
+ }
+ } else if (sc->mic_reqd) {
+ *negState = ACCEPT_INCOMPLETE;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else if (*negState == ACCEPT_COMPLETE) {
+ ret = GSS_S_COMPLETE;
+ } else {
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ return ret;
+}
+
+/*
+ * Perform the actual verification and/or generation of mechListMIC.
+ */
+static OM_uint32
+process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+ spnego_gss_ctx_id_t sc, gss_buffer_t *mic_out,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+ gss_qop_t qop_state;
+ gss_buffer_desc tmpmic = GSS_C_EMPTY_BUFFER;
+
+ ret = GSS_S_FAILURE;
+ if (mic_in != GSS_C_NO_BUFFER) {
+ ret = gss_verify_mic(minor_status, sc->ctx_handle,
+ &sc->DER_mechTypes,
+ mic_in, &qop_state);
+ if (ret == GSS_S_COMPLETE)
+ ret = ntlmssp_reset_crypto_state(minor_status, sc, 1);
+ if (ret != GSS_S_COMPLETE) {
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return ret;
+ }
+ /* If we got a MIC, we must send a MIC. */
+ sc->mic_reqd = 1;
+ sc->mic_rcvd = 1;
+ }
+ if (sc->mic_reqd && !sc->mic_sent) {
+ ret = gss_get_mic(minor_status, sc->ctx_handle,
+ GSS_C_QOP_DEFAULT,
+ &sc->DER_mechTypes,
+ &tmpmic);
+ if (ret == GSS_S_COMPLETE)
+ ret = ntlmssp_reset_crypto_state(minor_status, sc, 0);
+ if (ret != GSS_S_COMPLETE) {
+ gss_release_buffer(&tmpmin, &tmpmic);
+ *tokflag = NO_TOKEN_SEND;
+ return ret;
+ }
+ *mic_out = malloc(sizeof(gss_buffer_desc));
+ if (*mic_out == GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, &tmpmic);
+ *tokflag = NO_TOKEN_SEND;
+ return GSS_S_FAILURE;
+ }
+ **mic_out = tmpmic;
+ sc->mic_sent = 1;
+ }
+ return GSS_S_COMPLETE;
+}
+
+/* Create a new SPNEGO context handle for the initial call to
+ * spnego_gss_init_sec_context(). */
+static OM_uint32
+init_ctx_new(OM_uint32 *minor_status,
+ spnego_gss_cred_id_t spcred,
+ send_token_flag *tokflag,
+ spnego_gss_ctx_id_t *sc_out)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = NULL;
+
+ *sc_out = NULL;
+
+ sc = create_spnego_ctx(1);
+ if (sc == NULL)
+ return GSS_S_FAILURE;
+
+ /* determine negotiation mech set */
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_INITIATE,
+ &sc->mech_set);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ /* Set an initial internal mech to make the first context token. */
+ sc->internal_mech = &sc->mech_set->elements[0];
+
+ if (put_mech_set(sc->mech_set, &sc->DER_mechTypes) < 0) {
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ sc->ctx_handle = GSS_C_NO_CONTEXT;
+ *sc_out = sc;
+ sc = NULL;
+ *tokflag = INIT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+
+cleanup:
+ release_spnego_ctx(&sc);
+ return ret;
+}
+
+/*
+ * Called by second and later calls to spnego_gss_init_sec_context()
+ * to decode reply and update state.
+ */
+static OM_uint32
+init_ctx_cont(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ gss_buffer_t buf, gss_buffer_t *responseToken,
+ gss_buffer_t *mechListMIC, OM_uint32 *negState,
+ send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin, acc_negState;
+ unsigned char *ptr;
+ gss_OID supportedMech = GSS_C_NO_OID;
+
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+
+ ptr = buf->value;
+ ret = get_negTokenResp(minor_status, ptr, buf->length,
+ &acc_negState, &supportedMech,
+ responseToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ if (acc_negState == REJECT) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ map_errcode(minor_status);
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ /*
+ * nego_done is false for the first call to init_ctx_cont()
+ */
+ if (!sc->nego_done) {
+ ret = init_ctx_nego(minor_status, sc,
+ acc_negState,
+ supportedMech, responseToken,
+ mechListMIC,
+ negState, tokflag);
+ } else if ((!sc->mech_complete && *responseToken == GSS_C_NO_BUFFER) ||
+ (sc->mech_complete && *responseToken != GSS_C_NO_BUFFER)) {
+ /* Missing or spurious token from acceptor. */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ } else if (!sc->mech_complete ||
+ (sc->mic_reqd &&
+ (sc->ctx_flags & GSS_C_INTEG_FLAG))) {
+ /* Not obviously done; we may decide we're done later in
+ * init_ctx_call_init or handle_mic. */
+ *negState = ACCEPT_INCOMPLETE;
+ *tokflag = CONT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else {
+ /* mech finished on last pass and no MIC required, so done. */
+ *negState = ACCEPT_COMPLETE;
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_COMPLETE;
+ }
+cleanup:
+ if (supportedMech != GSS_C_NO_OID)
+ generic_gss_release_oid(&tmpmin, &supportedMech);
+ return ret;
+}
+
+/*
+ * Consistency checking and mechanism negotiation handling for second
+ * call of spnego_gss_init_sec_context(). Call init_ctx_reselect() to
+ * update internal state if acceptor has counter-proposed.
+ */
+static OM_uint32
+init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ OM_uint32 acc_negState, gss_OID supportedMech,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+
+ /*
+ * According to RFC 4178, both supportedMech and negState must be
+ * present in the first acceptor token. However, some Java
+ * implementations include only a responseToken in the first
+ * NegTokenResp. In this case we can use sc->internal_mech as the
+ * negotiated mechanism. (We do not currently look at acc_negState
+ * when continuing with the optimistic mechanism.)
+ */
+ if (supportedMech == GSS_C_NO_OID)
+ supportedMech = sc->internal_mech;
+
+ /*
+ * If the mechanism we sent is not the mechanism returned from
+ * the server, we need to handle the server's counter
+ * proposal. There is a bug in SAMBA servers that always send
+ * the old Kerberos mech OID, even though we sent the new one.
+ * So we will treat all the Kerberos mech OIDS as the same.
+ */
+ if (!(is_kerb_mech(supportedMech) &&
+ is_kerb_mech(sc->internal_mech)) &&
+ !g_OID_equal(supportedMech, sc->internal_mech)) {
+ ret = init_ctx_reselect(minor_status, sc,
+ acc_negState, supportedMech,
+ responseToken, mechListMIC,
+ negState, tokflag);
+
+ } else if (*responseToken == GSS_C_NO_BUFFER) {
+ if (sc->mech_complete) {
+ /*
+ * Mech completed on first call to its
+ * init_sec_context(). Acceptor sends no mech
+ * token.
+ */
+ *negState = ACCEPT_COMPLETE;
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_COMPLETE;
+ } else {
+ /*
+ * Reject missing mech token when optimistic
+ * mech selected.
+ */
+ *minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR;
+ map_errcode(minor_status);
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ }
+ } else if ((*responseToken)->length == 0 && sc->mech_complete) {
+ /* Handle old IIS servers returning empty token instead of
+ * null tokens in the non-mutual auth case. */
+ *negState = ACCEPT_COMPLETE;
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_COMPLETE;
+ } else if (sc->mech_complete) {
+ /* Reject spurious mech token. */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ *negState = ACCEPT_INCOMPLETE;
+ *tokflag = CONT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ sc->nego_done = 1;
+ return ret;
+}
+
+/*
+ * Handle acceptor's counter-proposal of an alternative mechanism.
+ */
+static OM_uint32
+init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ OM_uint32 acc_negState, gss_OID supportedMech,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 tmpmin;
+ size_t i;
+
+ gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+ GSS_C_NO_BUFFER);
+
+ /* Find supportedMech in sc->mech_set. */
+ for (i = 0; i < sc->mech_set->count; i++) {
+ if (g_OID_equal(supportedMech, &sc->mech_set->elements[i]))
+ break;
+ }
+ if (i == sc->mech_set->count)
+ return GSS_S_DEFECTIVE_TOKEN;
+ sc->internal_mech = &sc->mech_set->elements[i];
+
+ /*
+ * A server conforming to RFC4178 MUST set REQUEST_MIC here, but
+ * Windows Server 2003 and earlier implement (roughly) RFC2478 instead,
+ * and send ACCEPT_INCOMPLETE. Tolerate that only if we are falling
+ * back to NTLMSSP.
+ */
+ if (acc_negState == ACCEPT_INCOMPLETE) {
+ if (!g_OID_equal(supportedMech, &gss_mech_ntlmssp_oid))
+ return GSS_S_DEFECTIVE_TOKEN;
+ } else if (acc_negState != REQUEST_MIC) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ sc->mech_complete = 0;
+ sc->mic_reqd = (acc_negState == REQUEST_MIC);
+ *negState = acc_negState;
+ *tokflag = CONT_TOKEN_SEND;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+/*
+ * Wrap call to mechanism gss_init_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+init_ctx_call_init(OM_uint32 *minor_status,
+ spnego_gss_ctx_id_t sc,
+ spnego_gss_cred_id_t spcred,
+ gss_name_t target_name,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_buffer_t mechtok_in,
+ gss_OID *actual_mech,
+ gss_buffer_t mechtok_out,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ OM_uint32 *negState,
+ send_token_flag *send_token)
+{
+ OM_uint32 ret, tmpret, tmpmin, mech_req_flags;
+ gss_cred_id_t mcred;
+
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
+
+ mech_req_flags = req_flags;
+ if (spcred == NULL || !spcred->no_ask_integ)
+ mech_req_flags |= GSS_C_INTEG_FLAG;
+
+ ret = gss_init_sec_context(minor_status,
+ mcred,
+ &sc->ctx_handle,
+ target_name,
+ sc->internal_mech,
+ mech_req_flags,
+ time_req,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ mechtok_in,
+ &sc->actual_mech,
+ mechtok_out,
+ &sc->ctx_flags,
+ time_rec);
+ if (ret == GSS_S_COMPLETE) {
+ sc->mech_complete = 1;
+ if (ret_flags != NULL)
+ *ret_flags = sc->ctx_flags;
+ /*
+ * Microsoft SPNEGO implementations expect an even number of
+ * token exchanges. So if we're sending a final token, ask for
+ * a zero-length token back from the server. Also ask for a
+ * token back if this is the first token or if a MIC exchange
+ * is required.
+ */
+ if (*send_token == CONT_TOKEN_SEND &&
+ mechtok_out->length == 0 &&
+ (!sc->mic_reqd ||
+ !(sc->ctx_flags & GSS_C_INTEG_FLAG))) {
+ /* The exchange is complete. */
+ *negState = ACCEPT_COMPLETE;
+ ret = GSS_S_COMPLETE;
+ *send_token = NO_TOKEN_SEND;
+ } else {
+ /* Ask for one more hop. */
+ *negState = ACCEPT_INCOMPLETE;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ return ret;
+ }
+
+ if (ret == GSS_S_CONTINUE_NEEDED)
+ return ret;
+
+ if (*send_token != INIT_TOKEN_SEND) {
+ *send_token = ERROR_TOKEN_SEND;
+ *negState = REJECT;
+ return ret;
+ }
+
+ /*
+ * Since this is the first token, we can fall back to later mechanisms
+ * in the list. Since the mechanism list is expected to be short, we
+ * can do this with recursion. If all mechanisms produce errors, the
+ * caller should get the error from the first mech in the list.
+ */
+ gssalloc_free(sc->mech_set->elements->elements);
+ memmove(sc->mech_set->elements, sc->mech_set->elements + 1,
+ --sc->mech_set->count * sizeof(*sc->mech_set->elements));
+ if (sc->mech_set->count == 0)
+ goto fail;
+ gss_release_buffer(&tmpmin, &sc->DER_mechTypes);
+ if (put_mech_set(sc->mech_set, &sc->DER_mechTypes) < 0)
+ goto fail;
+ tmpret = init_ctx_call_init(&tmpmin, sc, spcred, target_name,
+ req_flags, time_req, mechtok_in,
+ actual_mech, mechtok_out, ret_flags,
+ time_rec, negState, send_token);
+ if (HARD_ERROR(tmpret))
+ goto fail;
+ *minor_status = tmpmin;
+ return tmpret;
+
+fail:
+ /* Don't output token on error from first call. */
+ *send_token = NO_TOKEN_SEND;
+ *negState = REJECT;
+ return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_init_sec_context(
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ send_token_flag send_token = NO_TOKEN_SEND;
+ OM_uint32 tmpmin, ret, negState;
+ gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
+ gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+ spnego_gss_cred_id_t spcred = NULL;
+ spnego_gss_ctx_id_t spnego_ctx = NULL;
+
+ dsyslog("Entering init_sec_context\n");
+
+ mechtok_in = mechListMIC_out = mechListMIC_in = GSS_C_NO_BUFFER;
+ negState = REJECT;
+
+ /*
+ * This function works in three steps:
+ *
+ * 1. Perform mechanism negotiation.
+ * 2. Invoke the negotiated or optimistic mech's gss_init_sec_context
+ * function and examine the results.
+ * 3. Process or generate MICs if necessary.
+ *
+ * The three steps share responsibility for determining when the
+ * exchange is complete. If the selected mech completed in a previous
+ * call and no MIC exchange is expected, then step 1 will decide. If
+ * the selected mech completes in this call and no MIC exchange is
+ * expected, then step 2 will decide. If a MIC exchange is expected,
+ * then step 3 will decide. If an error occurs in any step, the
+ * exchange will be aborted, possibly with an error token.
+ *
+ * negState determines the state of the negotiation, and is
+ * communicated to the acceptor if a continuing token is sent.
+ * send_token is used to indicate what type of token, if any, should be
+ * generated.
+ */
+
+ /* Validate arguments. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+ if (minor_status == NULL ||
+ output_token == GSS_C_NO_BUFFER ||
+ context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (actual_mech != NULL)
+ *actual_mech = GSS_C_NO_OID;
+
+ /* Step 1: perform mechanism negotiation. */
+ spcred = (spnego_gss_cred_id_t)claimant_cred_handle;
+ spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
+ if (spnego_ctx == NULL) {
+ ret = init_ctx_new(minor_status, spcred, &send_token,
+ &spnego_ctx);
+ if (ret != GSS_S_CONTINUE_NEEDED) {
+ goto cleanup;
+ }
+ *context_handle = (gss_ctx_id_t)spnego_ctx;
+ } else {
+ ret = init_ctx_cont(minor_status, spnego_ctx,
+ input_token, &mechtok_in,
+ &mechListMIC_in, &negState, &send_token);
+ if (HARD_ERROR(ret)) {
+ goto cleanup;
+ }
+ }
+
+ /* Step 2: invoke the selected or optimistic mechanism's
+ * gss_init_sec_context function, if it didn't complete previously. */
+ if (!spnego_ctx->mech_complete) {
+ ret = init_ctx_call_init(
+ minor_status, spnego_ctx, spcred,
+ target_name, req_flags,
+ time_req, mechtok_in,
+ actual_mech, &mechtok_out,
+ ret_flags, time_rec,
+ &negState, &send_token);
+
+ /* Give the mechanism a chance to force a mechlistMIC. */
+ if (!HARD_ERROR(ret) && mech_requires_mechlistMIC(spnego_ctx))
+ spnego_ctx->mic_reqd = 1;
+ }
+
+ /* Step 3: process or generate the MIC, if the negotiated mech is
+ * complete and supports MICs. */
+ if (!HARD_ERROR(ret) && spnego_ctx->mech_complete &&
+ (spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+ ret = handle_mic(minor_status,
+ mechListMIC_in,
+ (mechtok_out.length != 0),
+ spnego_ctx, &mechListMIC_out,
+ &negState, &send_token);
+ }
+cleanup:
+ if (send_token == INIT_TOKEN_SEND) {
+ if (make_spnego_tokenInit_msg(spnego_ctx,
+ 0,
+ mechListMIC_out,
+ req_flags,
+ &mechtok_out, send_token,
+ output_token) < 0) {
+ ret = GSS_S_FAILURE;
+ }
+ } else if (send_token != NO_TOKEN_SEND) {
+ if (make_spnego_tokenTarg_msg(negState, GSS_C_NO_OID,
+ &mechtok_out, mechListMIC_out,
+ send_token,
+ output_token) < 0) {
+ ret = GSS_S_FAILURE;
+ }
+ }
+ gss_release_buffer(&tmpmin, &mechtok_out);
+ if (ret == GSS_S_COMPLETE) {
+ spnego_ctx->opened = 1;
+ if (actual_mech != NULL)
+ *actual_mech = spnego_ctx->actual_mech;
+ if (ret_flags != NULL)
+ *ret_flags = spnego_ctx->ctx_flags;
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ if (spnego_ctx != NULL) {
+ gss_delete_sec_context(&tmpmin,
+ &spnego_ctx->ctx_handle,
+ GSS_C_NO_BUFFER);
+ release_spnego_ctx(&spnego_ctx);
+ }
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ if (mechtok_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechtok_in);
+ free(mechtok_in);
+ }
+ if (mechListMIC_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechListMIC_in);
+ free(mechListMIC_in);
+ }
+ if (mechListMIC_out != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechListMIC_out);
+ free(mechListMIC_out);
+ }
+ return ret;
+} /* init_sec_context */
+
+/* We don't want to import KRB5 headers here */
+static const gss_OID_desc gss_mech_krb5_oid =
+ { 9, "\052\206\110\206\367\022\001\002\002" };
+static const gss_OID_desc gss_mech_krb5_wrong_oid =
+ { 9, "\052\206\110\202\367\022\001\002\002" };
+
+/*
+ * verify that the input token length is not 0. If it is, just return.
+ * If the token length is greater than 0, der encode as a sequence
+ * and place in buf_out, advancing buf_out.
+ */
+
+static int
+put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token,
+ unsigned int buflen)
+{
+ int ret;
+
+ /* if token length is 0, we do not want to send */
+ if (input_token->length == 0)
+ return (0);
+
+ if (input_token->length > buflen)
+ return (-1);
+
+ *(*buf_out)++ = SEQUENCE;
+ if ((ret = gssint_put_der_length(input_token->length, buf_out,
+ input_token->length)))
+ return (ret);
+ TWRITE_STR(*buf_out, input_token->value, input_token->length);
+ return (0);
+}
+
+/*
+ * NegHints ::= SEQUENCE {
+ * hintName [0] GeneralString OPTIONAL,
+ * hintAddress [1] OCTET STRING OPTIONAL
+ * }
+ */
+
+#define HOST_PREFIX "host@"
+#define HOST_PREFIX_LEN (sizeof(HOST_PREFIX) - 1)
+
+/* Encode the dummy hintname string (as specified in [MS-SPNG]) into a
+ * DER-encoded [0] tagged GeneralString, and place the result in *outbuf. */
+static int
+make_NegHints(OM_uint32 *minor_status, gss_buffer_t *outbuf)
+{
+ OM_uint32 major_status;
+ unsigned int tlen = 0;
+ unsigned int hintNameSize = 0;
+ unsigned char *ptr;
+ unsigned char *t;
+ const char *hintname = "not_defined_in_RFC4178@please_ignore";
+ const size_t hintname_len = strlen(hintname);
+
+ *outbuf = GSS_C_NO_BUFFER;
+ major_status = GSS_S_FAILURE;
+
+ /* Length of DER encoded GeneralString */
+ tlen = 1 + gssint_der_length_size(hintname_len) + hintname_len;
+ hintNameSize = tlen;
+
+ /* Length of DER encoded hintName */
+ tlen += 1 + gssint_der_length_size(hintNameSize);
+
+ t = gssalloc_malloc(tlen);
+ if (t == NULL) {
+ *minor_status = ENOMEM;
+ goto errout;
+ }
+
+ ptr = t;
+
+ *ptr++ = CONTEXT | 0x00; /* hintName identifier */
+ if (gssint_put_der_length(hintNameSize,
+ &ptr, tlen - (int)(ptr-t)))
+ goto errout;
+
+ *ptr++ = GENERAL_STRING;
+ if (gssint_put_der_length(hintname_len, &ptr, tlen - (int)(ptr-t)))
+ goto errout;
+
+ memcpy(ptr, hintname, hintname_len);
+ ptr += hintname_len;
+
+ *outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc));
+ if (*outbuf == NULL) {
+ *minor_status = ENOMEM;
+ goto errout;
+ }
+ (*outbuf)->value = (void *)t;
+ (*outbuf)->length = ptr - t;
+
+ t = NULL; /* don't free */
+
+ *minor_status = 0;
+ major_status = GSS_S_COMPLETE;
+
+errout:
+ if (t != NULL) {
+ free(t);
+ }
+
+ return (major_status);
+}
+
+/*
+ * Create a new SPNEGO context handle for the initial call to
+ * spnego_gss_accept_sec_context() when the request is empty. For empty
+ * requests, we implement the Microsoft NegHints extension to SPNEGO for
+ * compatibility with some versions of Samba. See:
+ * http://msdn.microsoft.com/en-us/library/cc247039(PROT.10).aspx
+ */
+static OM_uint32
+acc_ctx_hints(OM_uint32 *minor_status,
+ spnego_gss_cred_id_t spcred,
+ gss_buffer_t *mechListMIC,
+ OM_uint32 *negState,
+ send_token_flag *return_token,
+ spnego_gss_ctx_id_t *sc_out)
+{
+ OM_uint32 tmpmin, ret;
+ gss_OID_set supported_mechSet;
+ spnego_gss_ctx_id_t sc = NULL;
+
+ *mechListMIC = GSS_C_NO_BUFFER;
+ supported_mechSet = GSS_C_NO_OID_SET;
+ *return_token = NO_TOKEN_SEND;
+ *negState = REJECT;
+ *minor_status = 0;
+ *sc_out = NULL;
+
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_ACCEPT,
+ &supported_mechSet);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ ret = make_NegHints(minor_status, mechListMIC);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ sc = create_spnego_ctx(0);
+ if (sc == NULL) {
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ if (put_mech_set(supported_mechSet, &sc->DER_mechTypes) < 0) {
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ sc->internal_mech = GSS_C_NO_OID;
+
+ *negState = ACCEPT_INCOMPLETE;
+ *return_token = INIT_TOKEN_SEND;
+ sc->firstpass = 1;
+ *sc_out = sc;
+ sc = NULL;
+ ret = GSS_S_COMPLETE;
+
+cleanup:
+ release_spnego_ctx(&sc);
+ gss_release_oid_set(&tmpmin, &supported_mechSet);
+
+ return ret;
+}
+
+/*
+ * Create a new SPNEGO context handle for the initial call to
+ * spnego_gss_accept_sec_context(). Set negState to REJECT if the token is
+ * defective, else ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether
+ * the initiator's preferred mechanism is supported.
+ */
+static OM_uint32
+acc_ctx_new(OM_uint32 *minor_status,
+ gss_buffer_t buf,
+ spnego_gss_cred_id_t spcred,
+ gss_buffer_t *mechToken,
+ gss_buffer_t *mechListMIC,
+ OM_uint32 *negState,
+ send_token_flag *return_token,
+ spnego_gss_ctx_id_t *sc_out)
+{
+ OM_uint32 tmpmin, ret, req_flags;
+ gss_OID_set supported_mechSet, mechTypes;
+ gss_buffer_desc der_mechTypes;
+ gss_OID mech_wanted;
+ spnego_gss_ctx_id_t sc = NULL;
+
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ der_mechTypes.length = 0;
+ der_mechTypes.value = NULL;
+ *mechToken = *mechListMIC = GSS_C_NO_BUFFER;
+ supported_mechSet = mechTypes = GSS_C_NO_OID_SET;
+ *return_token = ERROR_TOKEN_SEND;
+ *negState = REJECT;
+ *minor_status = 0;
+
+ ret = get_negTokenInit(minor_status, buf, &der_mechTypes,
+ &mechTypes, &req_flags,
+ mechToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE) {
+ goto cleanup;
+ }
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_ACCEPT,
+ &supported_mechSet);
+ if (ret != GSS_S_COMPLETE) {
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
+ }
+ /*
+ * Select the best match between the list of mechs
+ * that the initiator requested and the list that
+ * the acceptor will support.
+ */
+ mech_wanted = negotiate_mech(supported_mechSet, mechTypes, negState);
+ if (*negState == REJECT) {
+ ret = GSS_S_BAD_MECH;
+ goto cleanup;
+ }
+ sc = create_spnego_ctx(0);
+ if (sc == NULL) {
+ ret = GSS_S_FAILURE;
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
+ }
+ sc->mech_set = mechTypes;
+ mechTypes = GSS_C_NO_OID_SET;
+ sc->internal_mech = mech_wanted;
+ sc->DER_mechTypes = der_mechTypes;
+ der_mechTypes.length = 0;
+ der_mechTypes.value = NULL;
+
+ if (*negState == REQUEST_MIC)
+ sc->mic_reqd = 1;
+
+ *return_token = INIT_TOKEN_SEND;
+ sc->firstpass = 1;
+ *sc_out = sc;
+ ret = GSS_S_COMPLETE;
+cleanup:
+ gss_release_oid_set(&tmpmin, &mechTypes);
+ gss_release_oid_set(&tmpmin, &supported_mechSet);
+ if (der_mechTypes.length != 0)
+ gss_release_buffer(&tmpmin, &der_mechTypes);
+
+ return ret;
+}
+
+static OM_uint32
+acc_ctx_cont(OM_uint32 *minstat,
+ gss_buffer_t buf,
+ spnego_gss_ctx_id_t sc,
+ gss_buffer_t *responseToken,
+ gss_buffer_t *mechListMIC,
+ OM_uint32 *negState,
+ send_token_flag *return_token)
+{
+ OM_uint32 ret, tmpmin;
+ gss_OID supportedMech;
+ unsigned int len;
+ unsigned char *ptr, *bufstart;
+
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ *negState = REJECT;
+ *minstat = 0;
+ supportedMech = GSS_C_NO_OID;
+ *return_token = ERROR_TOKEN_SEND;
+ *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+
+ ptr = bufstart = buf->value;
+#define REMAIN (buf->length - (ptr - bufstart))
+ if (REMAIN == 0 || REMAIN > INT_MAX)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /*
+ * Attempt to work with old Sun SPNEGO.
+ */
+ if (*ptr == HEADER_ID) {
+ ret = g_verify_token_header(gss_mech_spnego,
+ &len, &ptr, 0, REMAIN);
+ if (ret) {
+ *minstat = ret;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ }
+ if (*ptr != (CONTEXT | 0x01)) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ret = get_negTokenResp(minstat, ptr, REMAIN,
+ negState, &supportedMech,
+ responseToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ if (*responseToken == GSS_C_NO_BUFFER &&
+ *mechListMIC == GSS_C_NO_BUFFER) {
+
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ if (supportedMech != GSS_C_NO_OID) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ sc->firstpass = 0;
+ *negState = ACCEPT_INCOMPLETE;
+ *return_token = CONT_TOKEN_SEND;
+cleanup:
+ if (supportedMech != GSS_C_NO_OID) {
+ generic_gss_release_oid(&tmpmin, &supportedMech);
+ }
+ return ret;
+#undef REMAIN
+}
+
+/*
+ * Verify that mech OID is either exactly the same as the negotiated
+ * mech OID, or is a mech OID supported by the negotiated mech. MS
+ * implementations can list a most preferred mech using an incorrect
+ * krb5 OID while emitting a krb5 initiator mech token having the
+ * correct krb5 mech OID.
+ */
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *minor_status,
+ spnego_gss_ctx_id_t sc, gss_OID mechoid,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+ gss_mechanism mech = NULL;
+ gss_OID_set mech_set = GSS_C_NO_OID_SET;
+ int present = 0;
+
+ if (g_OID_equal(sc->internal_mech, mechoid))
+ return GSS_S_COMPLETE;
+
+ mech = gssint_get_mechanism(sc->internal_mech);
+ if (mech == NULL || mech->gss_indicate_mechs == NULL) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ map_errcode(minor_status);
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_BAD_MECH;
+ }
+ ret = mech->gss_indicate_mechs(minor_status, &mech_set);
+ if (ret != GSS_S_COMPLETE) {
+ *tokflag = NO_TOKEN_SEND;
+ map_error(minor_status, mech);
+ goto cleanup;
+ }
+ ret = gss_test_oid_set_member(minor_status, mechoid,
+ mech_set, &present);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ if (!present) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ map_errcode(minor_status);
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ ret = GSS_S_BAD_MECH;
+ }
+cleanup:
+ gss_release_oid_set(&tmpmin, &mech_set);
+ return ret;
+}
+#ifndef LEAN_CLIENT
+/*
+ * Wrap call to gss_accept_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ spnego_gss_cred_id_t spcred, gss_buffer_t mechtok_in,
+ gss_OID *mech_type, gss_buffer_t mechtok_out,
+ OM_uint32 *ret_flags, OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+ gss_OID_desc mechoid;
+ gss_cred_id_t mcred;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT) {
+ /*
+ * mechoid is an alias; don't free it.
+ */
+ ret = gssint_get_mech_type(&mechoid, mechtok_in);
+ if (ret != GSS_S_COMPLETE) {
+ *tokflag = NO_TOKEN_SEND;
+ return ret;
+ }
+ ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid,
+ negState, tokflag);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+ }
+
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
+ ret = gss_accept_sec_context(minor_status,
+ &sc->ctx_handle,
+ mcred,
+ mechtok_in,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &sc->internal_name,
+ mech_type,
+ mechtok_out,
+ &sc->ctx_flags,
+ time_rec,
+ delegated_cred_handle);
+ if (ret == GSS_S_COMPLETE) {
+#ifdef MS_BUG_TEST
+ /*
+ * Force MIC to be not required even if we previously
+ * requested a MIC.
+ */
+ char *envstr = getenv("MS_FORCE_NO_MIC");
+
+ if (envstr != NULL && strcmp(envstr, "1") == 0 &&
+ !(sc->ctx_flags & GSS_C_MUTUAL_FLAG) &&
+ sc->mic_reqd) {
+
+ sc->mic_reqd = 0;
+ }
+#endif
+ sc->mech_complete = 1;
+ if (ret_flags != NULL)
+ *ret_flags = sc->ctx_flags;
+
+ if (!sc->mic_reqd ||
+ !(sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+ /* No MIC exchange required, so we're done. */
+ *negState = ACCEPT_COMPLETE;
+ ret = GSS_S_COMPLETE;
+ } else {
+ /* handle_mic will decide if we're done. */
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ }
+ return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_accept_sec_context(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 ret, tmpmin, negState;
+ send_token_flag return_token;
+ gss_buffer_t mechtok_in, mic_in, mic_out;
+ gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+ spnego_gss_ctx_id_t sc = NULL;
+ spnego_gss_cred_id_t spcred = NULL;
+ int sendTokenInit = 0, tmpret;
+
+ mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER;
+
+ /*
+ * This function works in three steps:
+ *
+ * 1. Perform mechanism negotiation.
+ * 2. Invoke the negotiated mech's gss_accept_sec_context function
+ * and examine the results.
+ * 3. Process or generate MICs if necessary.
+ *
+ * Step one determines whether the negotiation requires a MIC exchange,
+ * while steps two and three share responsibility for determining when
+ * the exchange is complete. If the selected mech completes in this
+ * call and no MIC exchange is expected, then step 2 will decide. If a
+ * MIC exchange is expected, then step 3 will decide. If an error
+ * occurs in any step, the exchange will be aborted, possibly with an
+ * error token.
+ *
+ * negState determines the state of the negotiation, and is
+ * communicated to the acceptor if a continuing token is sent.
+ * return_token is used to indicate what type of token, if any, should
+ * be generated.
+ */
+
+ /* Validate arguments. */
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (minor_status == NULL ||
+ output_token == GSS_C_NO_BUFFER ||
+ context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (input_token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ /* Step 1: Perform mechanism negotiation. */
+ sc = (spnego_gss_ctx_id_t)*context_handle;
+ spcred = (spnego_gss_cred_id_t)verifier_cred_handle;
+ if (sc == NULL && input_token->length == 0) {
+ /* Process a request for NegHints. */
+ ret = acc_ctx_hints(minor_status, spcred, &mic_out, &negState,
+ &return_token, &sc);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ *context_handle = (gss_ctx_id_t)sc;
+ sendTokenInit = 1;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else if (sc == NULL || sc->internal_mech == GSS_C_NO_OID) {
+ if (sc != NULL) {
+ /* Discard the context from the NegHints request. */
+ release_spnego_ctx(&sc);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ /* Process an initial token; can set negState to
+ * REQUEST_MIC. */
+ ret = acc_ctx_new(minor_status, input_token, spcred,
+ &mechtok_in, &mic_in, &negState,
+ &return_token, &sc);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ *context_handle = (gss_ctx_id_t)sc;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else {
+ /* Process a response token. Can set negState to
+ * ACCEPT_INCOMPLETE. */
+ ret = acc_ctx_cont(minor_status, input_token, sc, &mechtok_in,
+ &mic_in, &negState, &return_token);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+
+ /* Step 2: invoke the negotiated mechanism's gss_accept_sec_context
+ * function. */
+ /*
+ * Handle mechtok_in and mic_in only if they are
+ * present in input_token. If neither is present, whether
+ * this is an error depends on whether this is the first
+ * round-trip. RET is set to a default value according to
+ * whether it is the first round-trip.
+ */
+ if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
+ ret = acc_ctx_call_acc(minor_status, sc, spcred,
+ mechtok_in, mech_type, &mechtok_out,
+ ret_flags, time_rec,
+ delegated_cred_handle,
+ &negState, &return_token);
+ }
+
+ /* Step 3: process or generate the MIC, if the negotiated mech is
+ * complete and supports MICs. */
+ if (!HARD_ERROR(ret) && sc->mech_complete &&
+ (sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+ ret = handle_mic(minor_status, mic_in,
+ (mechtok_out.length != 0),
+ sc, &mic_out,
+ &negState, &return_token);
+ }
+cleanup:
+ if (return_token == INIT_TOKEN_SEND && sendTokenInit) {
+ assert(sc != NULL);
+ tmpret = make_spnego_tokenInit_msg(sc, 1, mic_out, 0,
+ GSS_C_NO_BUFFER,
+ return_token, output_token);
+ if (tmpret < 0)
+ ret = GSS_S_FAILURE;
+ } else if (return_token != NO_TOKEN_SEND &&
+ return_token != CHECK_MIC) {
+ tmpret = make_spnego_tokenTarg_msg(negState,
+ sc ? sc->internal_mech :
+ GSS_C_NO_OID,
+ &mechtok_out, mic_out,
+ return_token,
+ output_token);
+ if (tmpret < 0)
+ ret = GSS_S_FAILURE;
+ }
+ if (ret == GSS_S_COMPLETE) {
+ sc->opened = 1;
+ if (sc->internal_name != GSS_C_NO_NAME &&
+ src_name != NULL) {
+ *src_name = sc->internal_name;
+ sc->internal_name = GSS_C_NO_NAME;
+ }
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ if (sc != NULL) {
+ gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+ GSS_C_NO_BUFFER);
+ release_spnego_ctx(&sc);
+ }
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ gss_release_buffer(&tmpmin, &mechtok_out);
+ if (mechtok_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechtok_in);
+ free(mechtok_in);
+ }
+ if (mic_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mic_in);
+ free(mic_in);
+ }
+ if (mic_out != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mic_out);
+ free(mic_out);
+ }
+ return ret;
+}
+#endif /* LEAN_CLIENT */
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_display_status(
+ OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ int status_type,
+ gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
+{
+ OM_uint32 maj = GSS_S_COMPLETE;
+ int ret;
+
+ dsyslog("Entering display_status\n");
+
+ *message_context = 0;
+ switch (status_value) {
+ case ERR_SPNEGO_NO_MECHS_AVAILABLE:
+ /* CSTYLED */
+ *status_string = make_err_msg(_("SPNEGO cannot find "
+ "mechanisms to negotiate"));
+ break;
+ case ERR_SPNEGO_NO_CREDS_ACQUIRED:
+ /* CSTYLED */
+ *status_string = make_err_msg(_("SPNEGO failed to acquire "
+ "creds"));
+ break;
+ case ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR:
+ /* CSTYLED */
+ *status_string = make_err_msg(_("SPNEGO acceptor did not "
+ "select a mechanism"));
+ break;
+ case ERR_SPNEGO_NEGOTIATION_FAILED:
+ /* CSTYLED */
+ *status_string = make_err_msg(_("SPNEGO failed to negotiate a "
+ "mechanism"));
+ break;
+ case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR:
+ /* CSTYLED */
+ *status_string = make_err_msg(_("SPNEGO acceptor did not "
+ "return a valid token"));
+ break;
+ default:
+ /* Not one of our minor codes; might be from a mech. Call back
+ * to gss_display_status, but first check for recursion. */
+ if (k5_getspecific(K5_KEY_GSS_SPNEGO_STATUS) != NULL) {
+ /* Perhaps we returned a com_err code like ENOMEM. */
+ const char *err = error_message(status_value);
+ *status_string = make_err_msg(err);
+ break;
+ }
+ /* Set a non-null pointer value; doesn't matter which one. */
+ ret = k5_setspecific(K5_KEY_GSS_SPNEGO_STATUS, &ret);
+ if (ret != 0) {
+ *minor_status = ret;
+ maj = GSS_S_FAILURE;
+ break;
+ }
+ maj = gss_display_status(minor_status, status_value,
+ status_type, mech_type,
+ message_context, status_string);
+ /* This is unlikely to fail; not much we can do if it does. */
+ (void)k5_setspecific(K5_KEY_GSS_SPNEGO_STATUS, NULL);
+ break;
+ }
+
+ dsyslog("Leaving display_status\n");
+ return maj;
+}
+
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_import_name(
+ OM_uint32 *minor_status,
+ gss_buffer_t input_name_buffer,
+ gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering import_name\n");
+
+ status = gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name);
+
+ dsyslog("Leaving import_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_release_name(
+ OM_uint32 *minor_status,
+ gss_name_t *input_name)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering release_name\n");
+
+ status = gss_release_name(minor_status, input_name);
+
+ dsyslog("Leaving release_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_duplicate_name(
+ OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ gss_name_t *output_name)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering duplicate_name\n");
+
+ status = gss_duplicate_name(minor_status, input_name, output_name);
+
+ dsyslog("Leaving duplicate_name\n");
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_cred(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ gss_name_t *name,
+ OM_uint32 *lifetime,
+ int *cred_usage,
+ gss_OID_set *mechanisms)
+{
+ OM_uint32 status;
+ spnego_gss_cred_id_t spcred = NULL;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+ OM_uint32 tmp_minor_status;
+ OM_uint32 initiator_lifetime, acceptor_lifetime;
+
+ dsyslog("Entering inquire_cred\n");
+
+ /*
+ * To avoid infinite recursion, if GSS_C_NO_CREDENTIAL is
+ * supplied we call gss_inquire_cred_by_mech() on the
+ * first non-SPNEGO mechanism.
+ */
+ spcred = (spnego_gss_cred_id_t)cred_handle;
+ if (spcred == NULL) {
+ status = get_available_mechs(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_BOTH,
+ GSS_C_NO_CRED_STORE,
+ &creds,
+ mechanisms, NULL);
+ if (status != GSS_S_COMPLETE) {
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if ((*mechanisms)->count == 0) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ gss_release_oid_set(&tmp_minor_status, mechanisms);
+ dsyslog("Leaving inquire_cred\n");
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+
+ assert((*mechanisms)->elements != NULL);
+
+ status = gss_inquire_cred_by_mech(minor_status,
+ creds,
+ &(*mechanisms)->elements[0],
+ name,
+ &initiator_lifetime,
+ &acceptor_lifetime,
+ cred_usage);
+ if (status != GSS_S_COMPLETE) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if (lifetime != NULL)
+ *lifetime = (*cred_usage == GSS_C_ACCEPT) ?
+ acceptor_lifetime : initiator_lifetime;
+
+ gss_release_cred(&tmp_minor_status, &creds);
+ } else {
+ status = gss_inquire_cred(minor_status, spcred->mcred,
+ name, lifetime,
+ cred_usage, mechanisms);
+ }
+
+ dsyslog("Leaving inquire_cred\n");
+
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_compare_name(
+ OM_uint32 *minor_status,
+ const gss_name_t name1,
+ const gss_name_t name2,
+ int *name_equal)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ dsyslog("Entering compare_name\n");
+
+ status = gss_compare_name(minor_status, name1, name2, name_equal);
+
+ dsyslog("Leaving compare_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_display_name(
+ OM_uint32 *minor_status,
+ gss_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ dsyslog("Entering display_name\n");
+
+ status = gss_display_name(minor_status, input_name,
+ output_name_buffer, output_name_type);
+
+ dsyslog("Leaving display_name\n");
+ return (status);
+}
+
+
+/*ARGSUSED*/
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_names_for_mech(
+ OM_uint32 *minor_status,
+ gss_OID mechanism,
+ gss_OID_set *name_types)
+{
+ OM_uint32 major, minor;
+
+ dsyslog("Entering inquire_names_for_mech\n");
+ /*
+ * We only know how to handle our own mechanism.
+ */
+ if ((mechanism != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_spnego, mechanism)) {
+ *minor_status = 0;
+ return (GSS_S_FAILURE);
+ }
+
+ major = gss_create_empty_oid_set(minor_status, name_types);
+ if (major == GSS_S_COMPLETE) {
+ /* Now add our members. */
+ if (((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_USER_NAME,
+ name_types)) == GSS_S_COMPLETE) &&
+ ((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_MACHINE_UID_NAME,
+ name_types)) == GSS_S_COMPLETE) &&
+ ((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_STRING_UID_NAME,
+ name_types)) == GSS_S_COMPLETE)) {
+ major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
+ name_types);
+ }
+
+ if (major != GSS_S_COMPLETE)
+ (void) gss_release_oid_set(&minor, name_types);
+ }
+
+ dsyslog("Leaving inquire_names_for_mech\n");
+ return (major);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_unwrap(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_unwrap(minor_status,
+ sc->ctx_handle,
+ input_message_buffer,
+ output_message_buffer,
+ conf_state,
+ qop_state);
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_wrap(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_wrap(minor_status,
+ sc->ctx_handle,
+ conf_req_flag,
+ qop_req,
+ input_message_buffer,
+ conf_state,
+ output_message_buffer);
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_process_context_token(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ /* SPNEGO doesn't have its own context tokens. */
+ if (!sc->opened)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ ret = gss_process_context_token(minor_status,
+ sc->ctx_handle,
+ token_buffer);
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_delete_sec_context(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ OM_uint32 ret = GSS_S_COMPLETE;
+ spnego_gss_ctx_id_t *ctx =
+ (spnego_gss_ctx_id_t *)context_handle;
+
+ *minor_status = 0;
+
+ if (context_handle == NULL)
+ return (GSS_S_FAILURE);
+
+ if (*ctx == NULL)
+ return (GSS_S_COMPLETE);
+
+ (void) gss_delete_sec_context(minor_status, &(*ctx)->ctx_handle,
+ output_token);
+ (void) release_spnego_ctx(ctx);
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_context_time(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_context_time(minor_status,
+ sc->ctx_handle,
+ time_rec);
+ return (ret);
+}
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+spnego_gss_export_sec_context(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = *(spnego_gss_ctx_id_t *)context_handle;
+
+ /* We don't currently support exporting partially established
+ * contexts. */
+ if (!sc->opened)
+ return GSS_S_UNAVAILABLE;
+
+ ret = gss_export_sec_context(minor_status,
+ &sc->ctx_handle,
+ interprocess_token);
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT) {
+ release_spnego_ctx(&sc);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_import_sec_context(
+ OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 ret, tmpmin;
+ gss_ctx_id_t mctx;
+ spnego_gss_ctx_id_t sc;
+ int initiate, opened;
+
+ ret = gss_import_sec_context(minor_status, interprocess_token, &mctx);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+
+ ret = gss_inquire_context(&tmpmin, mctx, NULL, NULL, NULL, NULL, NULL,
+ &initiate, &opened);
+ if (ret != GSS_S_COMPLETE || !opened) {
+ /* We don't currently support importing partially established
+ * contexts. */
+ (void) gss_delete_sec_context(&tmpmin, &mctx, GSS_C_NO_BUFFER);
+ return GSS_S_FAILURE;
+ }
+
+ sc = create_spnego_ctx(initiate);
+ if (sc == NULL) {
+ (void) gss_delete_sec_context(&tmpmin, &mctx, GSS_C_NO_BUFFER);
+ return GSS_S_FAILURE;
+ }
+ sc->ctx_handle = mctx;
+ sc->opened = 1;
+ *context_handle = (gss_ctx_id_t)sc;
+ return GSS_S_COMPLETE;
+}
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_context(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *opened)
+{
+ OM_uint32 ret = GSS_S_COMPLETE;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (targ_name != NULL)
+ *targ_name = GSS_C_NO_NAME;
+ if (lifetime_rec != NULL)
+ *lifetime_rec = 0;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_spnego;
+ if (ctx_flags != NULL)
+ *ctx_flags = 0;
+ if (locally_initiated != NULL)
+ *locally_initiated = sc->initiate;
+ if (opened != NULL)
+ *opened = sc->opened;
+
+ if (sc->ctx_handle != GSS_C_NO_CONTEXT) {
+ ret = gss_inquire_context(minor_status, sc->ctx_handle,
+ src_name, targ_name, lifetime_rec,
+ mech_type, ctx_flags, NULL, NULL);
+ }
+
+ if (!sc->opened) {
+ /*
+ * We are still doing SPNEGO negotiation, so report SPNEGO as
+ * the OID. After negotiation is complete we will report the
+ * underlying mechanism OID.
+ */
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_spnego;
+
+ /*
+ * Remove flags we don't support with partially-established
+ * contexts. (Change this to keep GSS_C_TRANS_FLAG if we add
+ * support for exporting partial SPNEGO contexts.)
+ */
+ if (ctx_flags != NULL) {
+ *ctx_flags &= ~GSS_C_PROT_READY_FLAG;
+ *ctx_flags &= ~GSS_C_TRANS_FLAG;
+ }
+ }
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_wrap_size_limit(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_wrap_size_limit(minor_status,
+ sc->ctx_handle,
+ conf_req_flag,
+ qop_req,
+ req_output_size,
+ max_input_size);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_get_mic(minor_status,
+ sc->ctx_handle,
+ qop_req,
+ message_buffer,
+ message_token);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t msg_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_verify_mic(minor_status,
+ sc->ctx_handle,
+ msg_buffer,
+ token_buffer,
+ qop_state);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_sec_context_by_oid(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ /* There are no SPNEGO-specific OIDs for this function. */
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_UNAVAILABLE);
+
+ ret = gss_inquire_sec_context_by_oid(minor_status,
+ sc->ctx_handle,
+ desired_object,
+ data_set);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_cred_by_oid(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 ret;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+ gss_cred_id_t mcred;
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
+ ret = gss_inquire_cred_by_oid(minor_status,
+ mcred,
+ desired_object,
+ data_set);
+ return (ret);
+}
+
+/* This is the same OID as KRB5_NO_CI_FLAGS_X_OID. */
+#define NO_CI_FLAGS_X_OID_LENGTH 6
+#define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d"
+static const gss_OID_desc no_ci_flags_oid[] = {
+ {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+};
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_cred_option(
+ OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 ret;
+ OM_uint32 tmp_minor_status;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)*cred_handle;
+ gss_cred_id_t mcred;
+
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
+ ret = gss_set_cred_option(minor_status,
+ &mcred,
+ desired_object,
+ value);
+ if (ret == GSS_S_COMPLETE && spcred == NULL) {
+ /*
+ * If the mechanism allocated a new credential handle, then
+ * we need to wrap it up in an SPNEGO credential handle.
+ */
+
+ ret = create_spnego_cred(minor_status, mcred, &spcred);
+ if (ret != GSS_S_COMPLETE) {
+ gss_release_cred(&tmp_minor_status, &mcred);
+ return (ret);
+ }
+ *cred_handle = (gss_cred_id_t)spcred;
+ }
+
+ if (ret != GSS_S_COMPLETE)
+ return (ret);
+
+ /* Recognize KRB5_NO_CI_FLAGS_X_OID and avoid asking for integrity. */
+ if (g_OID_equal(desired_object, no_ci_flags_oid))
+ spcred->no_ask_integ = 1;
+
+ return (GSS_S_COMPLETE);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_sec_context_option(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)*context_handle;
+
+ /* There are no SPNEGO-specific OIDs for this function, and we cannot
+ * construct an empty SPNEGO context with it. */
+ if (sc == NULL || sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_UNAVAILABLE);
+
+ ret = gss_set_sec_context_option(minor_status,
+ &sc->ctx_handle,
+ desired_object,
+ value);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_wrap_aead(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t input_payload_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_wrap_aead(minor_status,
+ sc->ctx_handle,
+ conf_req_flag,
+ qop_req,
+ input_assoc_buffer,
+ input_payload_buffer,
+ conf_state,
+ output_message_buffer);
+
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_unwrap_aead(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t input_assoc_buffer,
+ gss_buffer_t output_payload_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_unwrap_aead(minor_status,
+ sc->ctx_handle,
+ input_message_buffer,
+ input_assoc_buffer,
+ output_payload_buffer,
+ conf_state,
+ qop_state);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_wrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_wrap_iov(minor_status,
+ sc->ctx_handle,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_unwrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_unwrap_iov(minor_status,
+ sc->ctx_handle,
+ conf_state,
+ qop_state,
+ iov,
+ iov_count);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_wrap_iov_length(minor_status,
+ sc->ctx_handle,
+ conf_req_flag,
+ qop_req,
+ conf_state,
+ iov,
+ iov_count);
+ return (ret);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_complete_auth_token(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_UNAVAILABLE);
+
+ ret = gss_complete_auth_token(minor_status,
+ sc->ctx_handle,
+ input_message_buffer);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status, tmpmin;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+ spnego_gss_cred_id_t imp_spcred = NULL, out_spcred = NULL;
+ gss_cred_id_t imp_mcred, out_mcred = GSS_C_NO_CREDENTIAL;
+
+ dsyslog("Entering spnego_gss_acquire_cred_impersonate_name\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ imp_spcred = (spnego_gss_cred_id_t)impersonator_cred_handle;
+ imp_mcred = imp_spcred ? imp_spcred->mcred : GSS_C_NO_CREDENTIAL;
+ status = gss_inquire_cred(minor_status, imp_mcred, NULL, NULL,
+ NULL, &amechs);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ status = gss_acquire_cred_impersonate_name(minor_status, imp_mcred,
+ desired_name, time_req,
+ amechs, cred_usage,
+ &out_mcred, actual_mechs,
+ time_rec);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ status = create_spnego_cred(minor_status, out_mcred, &out_spcred);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ out_mcred = GSS_C_NO_CREDENTIAL;
+ *output_cred_handle = (gss_cred_id_t)out_spcred;
+
+cleanup:
+ (void) gss_release_oid_set(&tmpmin, &amechs);
+ (void) gss_release_cred(&tmpmin, &out_mcred);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_impersonate_name\n");
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status, tmpmin;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+ gss_cred_id_t mcred = NULL;
+ spnego_gss_cred_id_t spcred = NULL;
+
+ dsyslog("Entering spnego_gss_acquire_cred_with_password\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ status = get_available_mechs(minor_status, desired_name,
+ cred_usage, GSS_C_NO_CRED_STORE,
+ NULL, &amechs, NULL);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ status = gss_acquire_cred_with_password(minor_status, desired_name,
+ password, time_req, amechs,
+ cred_usage, &mcred,
+ actual_mechs, time_rec);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ status = create_spnego_cred(minor_status, mcred, &spcred);
+ if (status != GSS_S_COMPLETE)
+ goto cleanup;
+
+ mcred = GSS_C_NO_CREDENTIAL;
+ *output_cred_handle = (gss_cred_id_t)spcred;
+
+cleanup:
+
+ (void) gss_release_oid_set(&tmpmin, &amechs);
+ (void) gss_release_cred(&tmpmin, &mcred);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_with_password\n");
+ return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_display_name_ext(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name)
+{
+ OM_uint32 ret;
+ ret = gss_display_name_ext(minor_status,
+ name,
+ display_as_name_type,
+ display_name);
+ return (ret);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ OM_uint32 ret;
+ ret = gss_inquire_name(minor_status,
+ name,
+ name_is_MN,
+ MN_mech,
+ attrs);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ OM_uint32 ret;
+ ret = gss_get_name_attribute(minor_status,
+ name,
+ attr,
+ authenticated,
+ complete,
+ value,
+ display_value,
+ more);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ OM_uint32 ret;
+ ret = gss_set_name_attribute(minor_status,
+ name,
+ complete,
+ attr,
+ value);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ OM_uint32 ret;
+ ret = gss_delete_name_attribute(minor_status,
+ name,
+ attr);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name)
+{
+ OM_uint32 ret;
+ ret = gss_export_name_composite(minor_status,
+ name,
+ exp_composite_name);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ OM_uint32 ret;
+ ret = gss_map_name_to_any(minor_status,
+ name,
+ authenticated,
+ type_id,
+ output);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ OM_uint32 ret;
+ ret = gss_release_any_name_mapping(minor_status,
+ name,
+ type_id,
+ input);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_pseudo_random(OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out)
+{
+ OM_uint32 ret;
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ ret = gss_pseudo_random(minor_status,
+ sc->ctx_handle,
+ prf_key,
+ prf_in,
+ desired_output_len,
+ prf_out);
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_set_neg_mechs(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_list)
+{
+ OM_uint32 ret;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+
+ /* Store mech_list in spcred for use in negotiation logic. */
+ gss_release_oid_set(minor_status, &spcred->neg_mechs);
+ ret = generic_gss_copy_oid_set(minor_status, mech_list,
+ &spcred->neg_mechs);
+ return (ret);
+}
+
+#define SPNEGO_SASL_NAME "SPNEGO"
+#define SPNEGO_SASL_NAME_LEN (sizeof(SPNEGO_SASL_NAME) - 1)
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type)
+{
+ if (sasl_mech_name->length == SPNEGO_SASL_NAME_LEN &&
+ memcmp(sasl_mech_name->value, SPNEGO_SASL_NAME,
+ SPNEGO_SASL_NAME_LEN) == 0) {
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_spnego;
+ return (GSS_S_COMPLETE);
+ }
+
+ return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description)
+{
+ *minor_status = 0;
+
+ if (!g_OID_equal(desired_mech, gss_mech_spnego))
+ return (GSS_S_BAD_MECH);
+
+ if (!g_make_string_buffer(SPNEGO_SASL_NAME, sasl_mech_name) ||
+ !g_make_string_buffer("spnego", mech_name) ||
+ !g_make_string_buffer("Simple and Protected GSS-API "
+ "Negotiation Mechanism", mech_description))
+ goto fail;
+
+ return (GSS_S_COMPLETE);
+
+fail:
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
+ gss_const_OID mech,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs)
+{
+ OM_uint32 major, tmpMinor;
+
+ /* known_mech_attrs is handled by mechglue */
+ *minor_status = 0;
+
+ if (mech_attrs == NULL)
+ return (GSS_S_COMPLETE);
+
+ major = gss_create_empty_oid_set(minor_status, mech_attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+#define MA_SUPPORTED(ma) do { \
+ major = gss_add_oid_set_member(minor_status, \
+ (gss_OID)ma, mech_attrs); \
+ if (GSS_ERROR(major)) \
+ goto cleanup; \
+ } while (0)
+
+ MA_SUPPORTED(GSS_C_MA_MECH_NEGO);
+ MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_oid_set(&tmpMinor, mech_attrs);
+
+ return (major);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_export_cred(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ gss_buffer_t token)
+{
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+
+ return (gss_export_cred(minor_status, spcred->mcred, token));
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_import_cred(OM_uint32 *minor_status,
+ gss_buffer_t token,
+ gss_cred_id_t *cred_handle)
+{
+ OM_uint32 ret;
+ spnego_gss_cred_id_t spcred;
+ gss_cred_id_t mcred;
+
+ ret = gss_import_cred(minor_status, token, &mcred);
+ if (GSS_ERROR(ret))
+ return (ret);
+
+ ret = create_spnego_cred(minor_status, mcred, &spcred);
+ if (GSS_ERROR(ret))
+ return (ret);
+
+ *cred_handle = (gss_cred_id_t)spcred;
+ return (ret);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ return gss_get_mic_iov(minor_status, sc->ctx_handle, qop_req, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ return gss_verify_mic_iov(minor_status, sc->ctx_handle, qop_state, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ spnego_gss_ctx_id_t sc = (spnego_gss_ctx_id_t)context_handle;
+
+ if (sc->ctx_handle == GSS_C_NO_CONTEXT)
+ return (GSS_S_NO_CONTEXT);
+
+ return gss_get_mic_iov_length(minor_status, sc->ctx_handle, qop_req, iov,
+ iov_count);
+}
+
+/*
+ * We will release everything but the ctx_handle so that it
+ * can be passed back to init/accept context. This routine should
+ * not be called until after the ctx_handle memory is assigned to
+ * the supplied context handle from init/accept context.
+ */
+static void
+release_spnego_ctx(spnego_gss_ctx_id_t *ctx)
+{
+ spnego_gss_ctx_id_t context;
+ OM_uint32 minor_stat;
+ context = *ctx;
+
+ if (context != NULL) {
+ (void) gss_release_buffer(&minor_stat,
+ &context->DER_mechTypes);
+
+ (void) gss_release_oid_set(&minor_stat, &context->mech_set);
+
+ (void) gss_release_name(&minor_stat, &context->internal_name);
+
+ free(context);
+ *ctx = NULL;
+ }
+}
+
+/*
+ * Can't use gss_indicate_mechs by itself to get available mechs for
+ * SPNEGO because it will also return the SPNEGO mech and we do not
+ * want to consider SPNEGO as an available security mech for
+ * negotiation. For this reason, get_available_mechs will return
+ * all available, non-deprecated mechs except SPNEGO.
+ *
+ * If a ptr to a creds list is given, this function will attempt
+ * to acquire creds for the creds given and trim the list of
+ * returned mechanisms to only those for which creds are valid.
+ *
+ */
+static OM_uint32
+get_available_mechs(OM_uint32 *minor_status,
+ gss_name_t name, gss_cred_usage_t usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *creds, gss_OID_set *rmechs, OM_uint32 *time_rec)
+{
+ unsigned int i;
+ int found = 0;
+ OM_uint32 major_status = GSS_S_COMPLETE, tmpmin;
+ gss_OID_set mechs, goodmechs;
+ gss_OID_set_desc except_attrs;
+ gss_OID_desc attr_oids[2];
+
+ attr_oids[0] = *GSS_C_MA_DEPRECATED;
+ attr_oids[1] = *GSS_C_MA_NOT_DFLT_MECH;
+ except_attrs.count = 2;
+ except_attrs.elements = attr_oids;
+ major_status = gss_indicate_mechs_by_attrs(minor_status,
+ GSS_C_NO_OID_SET,
+ &except_attrs,
+ GSS_C_NO_OID_SET, &mechs);
+
+ if (major_status != GSS_S_COMPLETE) {
+ return (major_status);
+ }
+
+ major_status = gss_create_empty_oid_set(minor_status, rmechs);
+
+ if (major_status != GSS_S_COMPLETE) {
+ (void) gss_release_oid_set(minor_status, &mechs);
+ return (major_status);
+ }
+
+ for (i = 0; i < mechs->count && major_status == GSS_S_COMPLETE; i++) {
+ if ((mechs->elements[i].length
+ != spnego_mechanism.mech_type.length) ||
+ memcmp(mechs->elements[i].elements,
+ spnego_mechanism.mech_type.elements,
+ spnego_mechanism.mech_type.length)) {
+
+ major_status = gss_add_oid_set_member(minor_status,
+ &mechs->elements[i],
+ rmechs);
+ if (major_status == GSS_S_COMPLETE)
+ found++;
+ }
+ }
+
+ /*
+ * If the caller wanted a list of creds returned,
+ * trim the list of mechanisms down to only those
+ * for which the creds are valid.
+ */
+ if (found > 0 && major_status == GSS_S_COMPLETE && creds != NULL) {
+ major_status = gss_acquire_cred_from(minor_status, name,
+ GSS_C_INDEFINITE,
+ *rmechs, usage,
+ cred_store, creds,
+ &goodmechs, time_rec);
+
+ /*
+ * Drop the old list in favor of the new
+ * "trimmed" list.
+ */
+ (void) gss_release_oid_set(&tmpmin, rmechs);
+ if (major_status == GSS_S_COMPLETE) {
+ (void) gssint_copy_oid_set(&tmpmin,
+ goodmechs, rmechs);
+ (void) gss_release_oid_set(&tmpmin, &goodmechs);
+ }
+ }
+
+ (void) gss_release_oid_set(&tmpmin, &mechs);
+ if (found == 0 || major_status != GSS_S_COMPLETE) {
+ *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
+ map_errcode(minor_status);
+ if (major_status == GSS_S_COMPLETE)
+ major_status = GSS_S_FAILURE;
+ }
+
+ return (major_status);
+}
+
+/*
+ * Return a list of mechanisms we are willing to negotiate for a credential,
+ * taking into account the mech set provided with gss_set_neg_mechs if it
+ * exists.
+ */
+static OM_uint32
+get_negotiable_mechs(OM_uint32 *minor_status, spnego_gss_cred_id_t spcred,
+ gss_cred_usage_t usage, gss_OID_set *rmechs)
+{
+ OM_uint32 ret, tmpmin;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL, *credptr;
+ gss_OID_set cred_mechs = GSS_C_NULL_OID_SET;
+ gss_OID_set intersect_mechs = GSS_C_NULL_OID_SET;
+ unsigned int i;
+ int present;
+
+ if (spcred == NULL) {
+ /*
+ * The default credentials were supplied. Return a list of all
+ * available mechs except SPNEGO. When initiating, trim this
+ * list to mechs we can acquire credentials for.
+ */
+ credptr = (usage == GSS_C_INITIATE) ? &creds : NULL;
+ ret = get_available_mechs(minor_status, GSS_C_NO_NAME, usage,
+ GSS_C_NO_CRED_STORE, credptr,
+ rmechs, NULL);
+ gss_release_cred(&tmpmin, &creds);
+ return (ret);
+ }
+
+ /* Get the list of mechs in the mechglue cred. */
+ ret = gss_inquire_cred(minor_status, spcred->mcred, NULL, NULL, NULL,
+ &cred_mechs);
+ if (ret != GSS_S_COMPLETE)
+ return (ret);
+
+ if (spcred->neg_mechs == GSS_C_NULL_OID_SET) {
+ /* gss_set_neg_mechs was never called; return cred_mechs. */
+ *rmechs = cred_mechs;
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+ }
+
+ /* Compute the intersection of cred_mechs and spcred->neg_mechs,
+ * preserving the order in spcred->neg_mechs. */
+ ret = gss_create_empty_oid_set(minor_status, &intersect_mechs);
+ if (ret != GSS_S_COMPLETE) {
+ gss_release_oid_set(&tmpmin, &cred_mechs);
+ return (ret);
+ }
+
+ for (i = 0; i < spcred->neg_mechs->count; i++) {
+ gss_test_oid_set_member(&tmpmin,
+ &spcred->neg_mechs->elements[i],
+ cred_mechs, &present);
+ if (!present)
+ continue;
+ ret = gss_add_oid_set_member(minor_status,
+ &spcred->neg_mechs->elements[i],
+ &intersect_mechs);
+ if (ret != GSS_S_COMPLETE)
+ break;
+ }
+
+ gss_release_oid_set(&tmpmin, &cred_mechs);
+ if (intersect_mechs->count == 0 || ret != GSS_S_COMPLETE) {
+ gss_release_oid_set(&tmpmin, &intersect_mechs);
+ *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
+ map_errcode(minor_status);
+ return (GSS_S_FAILURE);
+ }
+
+ *rmechs = intersect_mechs;
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
+
+/* following are token creation and reading routines */
+
+/*
+ * If buff_in is not pointing to a MECH_OID, then return NULL and do not
+ * advance the buffer, otherwise, decode the mech_oid from the buffer and
+ * place in gss_OID.
+ */
+static gss_OID
+get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
+{
+ OM_uint32 status;
+ gss_OID_desc toid;
+ gss_OID mech_out = NULL;
+ unsigned char *start, *end;
+
+ if (length < 1 || **buff_in != MECH_OID)
+ return (NULL);
+
+ start = *buff_in;
+ end = start + length;
+
+ (*buff_in)++;
+ toid.length = *(*buff_in)++;
+
+ if ((*buff_in + toid.length) > end)
+ return (NULL);
+
+ toid.elements = *buff_in;
+ *buff_in += toid.length;
+
+ status = generic_gss_copy_oid(minor_status, &toid, &mech_out);
+
+ if (status != GSS_S_COMPLETE) {
+ map_errcode(minor_status);
+ mech_out = NULL;
+ }
+
+ return (mech_out);
+}
+
+/*
+ * der encode the given mechanism oid into buf_out, advancing the
+ * buffer pointer.
+ */
+
+static int
+put_mech_oid(unsigned char **buf_out, gss_OID_const mech, unsigned int buflen)
+{
+ if (buflen < mech->length + 2)
+ return (-1);
+ *(*buf_out)++ = MECH_OID;
+ *(*buf_out)++ = (unsigned char) mech->length;
+ memcpy(*buf_out, mech->elements, mech->length);
+ *buf_out += mech->length;
+ return (0);
+}
+
+/*
+ * verify that buff_in points to an octet string, if it does not,
+ * return NULL and don't advance the pointer. If it is an octet string
+ * decode buff_in into a gss_buffer_t and return it, advancing the
+ * buffer pointer.
+ */
+static gss_buffer_t
+get_input_token(unsigned char **buff_in, unsigned int buff_length)
+{
+ gss_buffer_t input_token;
+ unsigned int len;
+
+ if (g_get_tag_and_length(buff_in, OCTET_STRING, buff_length, &len) < 0)
+ return (NULL);
+
+ input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+ if (input_token == NULL)
+ return (NULL);
+
+ input_token->length = len;
+ if (input_token->length > 0) {
+ input_token->value = gssalloc_malloc(input_token->length);
+ if (input_token->value == NULL) {
+ free(input_token);
+ return (NULL);
+ }
+
+ memcpy(input_token->value, *buff_in, input_token->length);
+ } else {
+ input_token->value = NULL;
+ }
+ *buff_in += input_token->length;
+ return (input_token);
+}
+
+/*
+ * verify that the input token length is not 0. If it is, just return.
+ * If the token length is greater than 0, der encode as an octet string
+ * and place in buf_out, advancing buf_out.
+ */
+
+static int
+put_input_token(unsigned char **buf_out, gss_buffer_t input_token,
+ unsigned int buflen)
+{
+ int ret;
+
+ /* if token length is 0, we do not want to send */
+ if (input_token->length == 0)
+ return (0);
+
+ if (input_token->length > buflen)
+ return (-1);
+
+ *(*buf_out)++ = OCTET_STRING;
+ if ((ret = gssint_put_der_length(input_token->length, buf_out,
+ input_token->length)))
+ return (ret);
+ TWRITE_STR(*buf_out, input_token->value, input_token->length);
+ return (0);
+}
+
+/*
+ * verify that buff_in points to a sequence of der encoding. The mech
+ * set is the only sequence of encoded object in the token, so if it is
+ * a sequence of encoding, decode the mechset into a gss_OID_set and
+ * return it, advancing the buffer pointer.
+ */
+static gss_OID_set
+get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
+ unsigned int buff_length)
+{
+ gss_OID_set returned_mechSet;
+ OM_uint32 major_status;
+ int length;
+ unsigned int bytes;
+ OM_uint32 set_length;
+ unsigned char *start;
+ int i;
+
+ if (**buff_in != SEQUENCE_OF)
+ return (NULL);
+
+ start = *buff_in;
+ (*buff_in)++;
+
+ length = gssint_get_der_length(buff_in, buff_length, &bytes);
+ if (length < 0 || buff_length - bytes < (unsigned int)length)
+ return NULL;
+
+ major_status = gss_create_empty_oid_set(minor_status,
+ &returned_mechSet);
+ if (major_status != GSS_S_COMPLETE)
+ return (NULL);
+
+ for (set_length = 0, i = 0; set_length < (unsigned int)length; i++) {
+ gss_OID_desc *temp = get_mech_oid(minor_status, buff_in,
+ buff_length - (*buff_in - start));
+ if (temp == NULL)
+ break;
+
+ major_status = gss_add_oid_set_member(minor_status,
+ temp, &returned_mechSet);
+ if (major_status == GSS_S_COMPLETE) {
+ set_length += returned_mechSet->elements[i].length +2;
+ if (generic_gss_release_oid(minor_status, &temp))
+ map_errcode(minor_status);
+ }
+ }
+
+ return (returned_mechSet);
+}
+
+/*
+ * Encode mechSet into buf.
+ */
+static int
+put_mech_set(gss_OID_set mechSet, gss_buffer_t buf)
+{
+ unsigned char *ptr;
+ unsigned int i;
+ unsigned int tlen, ilen;
+
+ tlen = ilen = 0;
+ for (i = 0; i < mechSet->count; i++) {
+ /*
+ * 0x06 [DER LEN] [OID]
+ */
+ ilen += 1 +
+ gssint_der_length_size(mechSet->elements[i].length) +
+ mechSet->elements[i].length;
+ }
+ /*
+ * 0x30 [DER LEN]
+ */
+ tlen = 1 + gssint_der_length_size(ilen) + ilen;
+ ptr = gssalloc_malloc(tlen);
+ if (ptr == NULL)
+ return -1;
+
+ buf->value = ptr;
+ buf->length = tlen;
+#define REMAIN (buf->length - ((unsigned char *)buf->value - ptr))
+
+ *ptr++ = SEQUENCE_OF;
+ if (gssint_put_der_length(ilen, &ptr, REMAIN) < 0)
+ return -1;
+ for (i = 0; i < mechSet->count; i++) {
+ if (put_mech_oid(&ptr, &mechSet->elements[i], REMAIN) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+#undef REMAIN
+}
+
+/*
+ * Verify that buff_in is pointing to a BIT_STRING with the correct
+ * length and padding for the req_flags. If it is, decode req_flags
+ * and return them, otherwise, return NULL.
+ */
+static OM_uint32
+get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
+ OM_uint32 *req_flags)
+{
+ unsigned int len;
+
+ if (**buff_in != (CONTEXT | 0x01))
+ return (0);
+
+ if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
+ bodysize, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING_LENGTH)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING_PADDING)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *req_flags = (OM_uint32) (*(*buff_in)++ >> 1);
+ return (0);
+}
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *minor_status,
+ gss_buffer_t buf,
+ gss_buffer_t der_mechSet,
+ gss_OID_set *mechSet,
+ OM_uint32 *req_flags,
+ gss_buffer_t *mechtok,
+ gss_buffer_t *mechListMIC)
+{
+ OM_uint32 err;
+ unsigned char *ptr, *bufstart;
+ unsigned int len;
+ gss_buffer_desc tmpbuf;
+
+ *minor_status = 0;
+ der_mechSet->length = 0;
+ der_mechSet->value = NULL;
+ *mechSet = GSS_C_NO_OID_SET;
+ *req_flags = 0;
+ *mechtok = *mechListMIC = GSS_C_NO_BUFFER;
+
+ ptr = bufstart = buf->value;
+ if ((buf->length - (ptr - bufstart)) > INT_MAX)
+ return GSS_S_FAILURE;
+#define REMAIN (buf->length - (ptr - bufstart))
+
+ err = g_verify_token_header(gss_mech_spnego,
+ &len, &ptr, 0, REMAIN);
+ if (err) {
+ *minor_status = err;
+ map_errcode(minor_status);
+ return GSS_S_FAILURE;
+ }
+ *minor_status = g_verify_neg_token_init(&ptr, REMAIN);
+ if (*minor_status) {
+ map_errcode(minor_status);
+ return GSS_S_FAILURE;
+ }
+
+ /* alias into input_token */
+ tmpbuf.value = ptr;
+ tmpbuf.length = REMAIN;
+ *mechSet = get_mech_set(minor_status, &ptr, REMAIN);
+ if (*mechSet == NULL)
+ return GSS_S_FAILURE;
+
+ tmpbuf.length = ptr - (unsigned char *)tmpbuf.value;
+ der_mechSet->value = gssalloc_malloc(tmpbuf.length);
+ if (der_mechSet->value == NULL)
+ return GSS_S_FAILURE;
+ memcpy(der_mechSet->value, tmpbuf.value, tmpbuf.length);
+ der_mechSet->length = tmpbuf.length;
+
+ err = get_req_flags(&ptr, REMAIN, req_flags);
+ if (err != GSS_S_COMPLETE) {
+ return err;
+ }
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
+ REMAIN, &len) >= 0) {
+ *mechtok = get_input_token(&ptr, len);
+ if (*mechtok == GSS_C_NO_BUFFER) {
+ return GSS_S_FAILURE;
+ }
+ }
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
+ REMAIN, &len) >= 0) {
+ *mechListMIC = get_input_token(&ptr, len);
+ if (*mechListMIC == GSS_C_NO_BUFFER) {
+ return GSS_S_FAILURE;
+ }
+ }
+ return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+static OM_uint32
+get_negTokenResp(OM_uint32 *minor_status,
+ unsigned char *buf, unsigned int buflen,
+ OM_uint32 *negState,
+ gss_OID *supportedMech,
+ gss_buffer_t *responseToken,
+ gss_buffer_t *mechListMIC)
+{
+ unsigned char *ptr, *bufstart;
+ unsigned int len;
+ int tmplen;
+ unsigned int tag, bytes;
+
+ *negState = ACCEPT_DEFECTIVE_TOKEN;
+ *supportedMech = GSS_C_NO_OID;
+ *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+ ptr = bufstart = buf;
+#define REMAIN (buflen - (ptr - bufstart))
+
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x01), REMAIN, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ if (*ptr++ == SEQUENCE) {
+ tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+
+ if (tag == CONTEXT) {
+ tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (g_get_tag_and_length(&ptr, ENUMERATED,
+ REMAIN, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (len != ENUMERATION_LENGTH)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ return GSS_S_DEFECTIVE_TOKEN;
+ *negState = *ptr++;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x01)) {
+ tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *supportedMech = get_mech_oid(minor_status, &ptr, REMAIN);
+ if (*supportedMech == GSS_C_NO_OID)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x02)) {
+ tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *responseToken = get_input_token(&ptr, REMAIN);
+ if (*responseToken == GSS_C_NO_BUFFER)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x03)) {
+ tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (tmplen < 0 || REMAIN < (unsigned int)tmplen)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *mechListMIC = get_input_token(&ptr, REMAIN);
+ if (*mechListMIC == GSS_C_NO_BUFFER)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /* Handle Windows 2000 duplicate response token */
+ if (*responseToken &&
+ ((*responseToken)->length == (*mechListMIC)->length) &&
+ !memcmp((*responseToken)->value, (*mechListMIC)->value,
+ (*responseToken)->length)) {
+ OM_uint32 tmpmin;
+
+ gss_release_buffer(&tmpmin, *mechListMIC);
+ free(*mechListMIC);
+ *mechListMIC = NULL;
+ }
+ }
+ return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+/*
+ * der encode the passed negResults as an ENUMERATED type and
+ * place it in buf_out, advancing the buffer.
+ */
+
+static int
+put_negResult(unsigned char **buf_out, OM_uint32 negResult,
+ unsigned int buflen)
+{
+ if (buflen < 3)
+ return (-1);
+ *(*buf_out)++ = ENUMERATED;
+ *(*buf_out)++ = ENUMERATION_LENGTH;
+ *(*buf_out)++ = (unsigned char) negResult;
+ return (0);
+}
+
+/*
+ * This routine compares the recieved mechset to the mechset that
+ * this server can support. It looks sequentially through the mechset
+ * and the first one that matches what the server can support is
+ * chosen as the negotiated mechanism. If one is found, negResult
+ * is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if
+ * it's not the first mech, otherwise we return NULL and negResult
+ * is set to REJECT. The returned pointer is an alias into
+ * received->elements and should not be freed.
+ *
+ * NOTE: There is currently no way to specify a preference order of
+ * mechanisms supported by the acceptor.
+ */
+static gss_OID
+negotiate_mech(gss_OID_set supported, gss_OID_set received,
+ OM_uint32 *negResult)
+{
+ size_t i, j;
+
+ for (i = 0; i < received->count; i++) {
+ gss_OID mech_oid = &received->elements[i];
+
+ /* Accept wrong mechanism OID from MS clients */
+ if (g_OID_equal(mech_oid, &gss_mech_krb5_wrong_oid))
+ mech_oid = (gss_OID)&gss_mech_krb5_oid;
+
+ for (j = 0; j < supported->count; j++) {
+ if (g_OID_equal(mech_oid, &supported->elements[j])) {
+ *negResult = (i == 0) ? ACCEPT_INCOMPLETE :
+ REQUEST_MIC;
+ return &received->elements[i];
+ }
+ }
+ }
+ *negResult = REJECT;
+ return (NULL);
+}
+
+/*
+ * the next two routines make a token buffer suitable for
+ * spnego_gss_display_status. These currently take the string
+ * in name and place it in the token. Eventually, if
+ * spnego_gss_display_status returns valid error messages,
+ * these routines will be changes to return the error string.
+ */
+static spnego_token_t
+make_spnego_token(const char *name)
+{
+ return (spnego_token_t)strdup(name);
+}
+
+static gss_buffer_desc
+make_err_msg(const char *name)
+{
+ gss_buffer_desc buffer;
+
+ if (name == NULL) {
+ buffer.length = 0;
+ buffer.value = NULL;
+ } else {
+ buffer.length = strlen(name)+1;
+ buffer.value = make_spnego_token(name);
+ }
+
+ return (buffer);
+}
+
+/*
+ * Create the client side spnego token passed back to gss_init_sec_context
+ * and eventually up to the application program and over to the server.
+ *
+ * Use DER rules, definite length method per RFC 2478
+ */
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
+ int negHintsCompat,
+ gss_buffer_t mechListMIC, OM_uint32 req_flags,
+ gss_buffer_t data, send_token_flag sendtoken,
+ gss_buffer_t outbuf)
+{
+ int ret = 0;
+ unsigned int tlen, dataLen = 0;
+ unsigned int negTokenInitSize = 0;
+ unsigned int negTokenInitSeqSize = 0;
+ unsigned int negTokenInitContSize = 0;
+ unsigned int rspTokenSize = 0;
+ unsigned int mechListTokenSize = 0;
+ unsigned int micTokenSize = 0;
+ unsigned char *t;
+ unsigned char *ptr;
+
+ if (outbuf == GSS_C_NO_BUFFER)
+ return (-1);
+
+ outbuf->length = 0;
+ outbuf->value = NULL;
+
+ /* calculate the data length */
+
+ /*
+ * 0xa0 [DER LEN] [mechTypes]
+ */
+ mechListTokenSize = 1 +
+ gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
+ spnego_ctx->DER_mechTypes.length;
+ dataLen += mechListTokenSize;
+
+ /*
+ * If a token from gss_init_sec_context exists,
+ * add the length of the token + the ASN.1 overhead
+ */
+ if (data != NULL) {
+ /*
+ * Encoded in final output as:
+ * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
+ * -----s--------|--------s2----------
+ */
+ rspTokenSize = 1 +
+ gssint_der_length_size(data->length) +
+ data->length;
+ dataLen += 1 + gssint_der_length_size(rspTokenSize) +
+ rspTokenSize;
+ }
+
+ if (mechListMIC) {
+ /*
+ * Encoded in final output as:
+ * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
+ * --s-- -----tlen------------
+ */
+ micTokenSize = 1 +
+ gssint_der_length_size(mechListMIC->length) +
+ mechListMIC->length;
+ dataLen += 1 +
+ gssint_der_length_size(micTokenSize) +
+ micTokenSize;
+ }
+
+ /*
+ * Add size of DER encoding
+ * [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
+ * 0x30 [DER_LEN] [data]
+ *
+ */
+ negTokenInitContSize = dataLen;
+ negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
+ dataLen = negTokenInitSeqSize;
+
+ /*
+ * negTokenInitSize indicates the bytes needed to
+ * hold the ASN.1 encoding of the entire NegTokenInit
+ * SEQUENCE.
+ * 0xa0 [DER_LEN] + data
+ *
+ */
+ negTokenInitSize = 1 +
+ gssint_der_length_size(negTokenInitSeqSize) +
+ negTokenInitSeqSize;
+
+ tlen = g_token_size(gss_mech_spnego, negTokenInitSize);
+
+ t = (unsigned char *) gssalloc_malloc(tlen);
+
+ if (t == NULL) {
+ return (-1);
+ }
+
+ ptr = t;
+
+ /* create the message */
+ if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
+ &ptr, tlen)))
+ goto errout;
+
+ *ptr++ = CONTEXT; /* NegotiationToken identifier */
+ if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
+ goto errout;
+
+ *ptr++ = SEQUENCE;
+ if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
+ tlen - (int)(ptr-t))))
+ goto errout;
+
+ *ptr++ = CONTEXT | 0x00; /* MechTypeList identifier */
+ if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
+ &ptr, tlen - (int)(ptr-t))))
+ goto errout;
+
+ /* We already encoded the MechSetList */
+ (void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
+ spnego_ctx->DER_mechTypes.length);
+
+ ptr += spnego_ctx->DER_mechTypes.length;
+
+ if (data != NULL) {
+ *ptr++ = CONTEXT | 0x02;
+ if ((ret = gssint_put_der_length(rspTokenSize,
+ &ptr, tlen - (int)(ptr - t))))
+ goto errout;
+
+ if ((ret = put_input_token(&ptr, data,
+ tlen - (int)(ptr - t))))
+ goto errout;
+ }
+
+ if (mechListMIC != GSS_C_NO_BUFFER) {
+ *ptr++ = CONTEXT | 0x03;
+ if ((ret = gssint_put_der_length(micTokenSize,
+ &ptr, tlen - (int)(ptr - t))))
+ goto errout;
+
+ if (negHintsCompat) {
+ ret = put_neg_hints(&ptr, mechListMIC,
+ tlen - (int)(ptr - t));
+ if (ret)
+ goto errout;
+ } else if ((ret = put_input_token(&ptr, mechListMIC,
+ tlen - (int)(ptr - t))))
+ goto errout;
+ }
+
+errout:
+ if (ret != 0) {
+ if (t)
+ free(t);
+ t = NULL;
+ tlen = 0;
+ }
+ outbuf->length = tlen;
+ outbuf->value = (void *) t;
+
+ return (ret);
+}
+
+/*
+ * create the server side spnego token passed back to
+ * gss_accept_sec_context and eventually up to the application program
+ * and over to the client.
+ */
+static int
+make_spnego_tokenTarg_msg(OM_uint32 status, gss_OID mech_wanted,
+ gss_buffer_t data, gss_buffer_t mechListMIC,
+ send_token_flag sendtoken,
+ gss_buffer_t outbuf)
+{
+ unsigned int tlen = 0;
+ unsigned int ret = 0;
+ unsigned int NegTokenTargSize = 0;
+ unsigned int NegTokenSize = 0;
+ unsigned int rspTokenSize = 0;
+ unsigned int micTokenSize = 0;
+ unsigned int dataLen = 0;
+ unsigned char *t;
+ unsigned char *ptr;
+
+ if (outbuf == GSS_C_NO_BUFFER)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if (sendtoken == INIT_TOKEN_SEND && mech_wanted == GSS_C_NO_OID)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ outbuf->length = 0;
+ outbuf->value = NULL;
+
+ /*
+ * ASN.1 encoding of the negResult
+ * ENUMERATED type is 3 bytes
+ * ENUMERATED TAG, Length, Value,
+ * Plus 2 bytes for the CONTEXT id and length.
+ */
+ dataLen = 5;
+
+ /*
+ * calculate data length
+ *
+ * If this is the initial token, include length of
+ * mech_type and the negotiation result fields.
+ */
+ if (sendtoken == INIT_TOKEN_SEND) {
+ int mechlistTokenSize;
+ /*
+ * 1 byte for the CONTEXT ID(0xa0),
+ * 1 byte for the OID ID(0x06)
+ * 1 byte for OID Length field
+ * Plus the rest... (OID Length, OID value)
+ */
+ mechlistTokenSize = 3 + mech_wanted->length +
+ gssint_der_length_size(mech_wanted->length);
+
+ dataLen += mechlistTokenSize;
+ }
+ if (data != NULL && data->length > 0) {
+ /* Length of the inner token */
+ rspTokenSize = 1 + gssint_der_length_size(data->length) +
+ data->length;
+
+ dataLen += rspTokenSize;
+
+ /* Length of the outer token */
+ dataLen += 1 + gssint_der_length_size(rspTokenSize);
+ }
+ if (mechListMIC != NULL) {
+
+ /* Length of the inner token */
+ micTokenSize = 1 + gssint_der_length_size(mechListMIC->length) +
+ mechListMIC->length;
+
+ dataLen += micTokenSize;
+
+ /* Length of the outer token */
+ dataLen += 1 + gssint_der_length_size(micTokenSize);
+ }
+ /*
+ * Add size of DER encoded:
+ * NegTokenTarg [ SEQUENCE ] of
+ * NegResult[0] ENUMERATED {
+ * accept_completed(0),
+ * accept_incomplete(1),
+ * reject(2) }
+ * supportedMech [1] MechType OPTIONAL,
+ * responseToken [2] OCTET STRING OPTIONAL,
+ * mechListMIC [3] OCTET STRING OPTIONAL
+ *
+ * size = data->length + MechListMic + SupportedMech len +
+ * Result Length + ASN.1 overhead
+ */
+ NegTokenTargSize = dataLen;
+ dataLen += 1 + gssint_der_length_size(NegTokenTargSize);
+
+ /*
+ * NegotiationToken [ CHOICE ]{
+ * negTokenInit [0] NegTokenInit,
+ * negTokenTarg [1] NegTokenTarg }
+ */
+ NegTokenSize = dataLen;
+ dataLen += 1 + gssint_der_length_size(NegTokenSize);
+
+ tlen = dataLen;
+ t = (unsigned char *) gssalloc_malloc(tlen);
+
+ if (t == NULL) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+
+ ptr = t;
+
+ /*
+ * Indicate that we are sending CHOICE 1
+ * (NegTokenTarg)
+ */
+ *ptr++ = CONTEXT | 0x01;
+ if (gssint_put_der_length(NegTokenSize, &ptr, dataLen) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ *ptr++ = SEQUENCE;
+ if (gssint_put_der_length(NegTokenTargSize, &ptr,
+ tlen - (int)(ptr-t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+
+ /*
+ * First field of the NegTokenTarg SEQUENCE
+ * is the ENUMERATED NegResult.
+ */
+ *ptr++ = CONTEXT;
+ if (gssint_put_der_length(3, &ptr,
+ tlen - (int)(ptr-t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_negResult(&ptr, status, tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (sendtoken == INIT_TOKEN_SEND) {
+ /*
+ * Next, is the Supported MechType
+ */
+ *ptr++ = CONTEXT | 0x01;
+ if (gssint_put_der_length(mech_wanted->length + 2,
+ &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_mech_oid(&ptr, mech_wanted,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ if (data != NULL && data->length > 0) {
+ *ptr++ = CONTEXT | 0x02;
+ if (gssint_put_der_length(rspTokenSize, &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_input_token(&ptr, data,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ if (mechListMIC != NULL) {
+ *ptr++ = CONTEXT | 0x03;
+ if (gssint_put_der_length(micTokenSize, &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_input_token(&ptr, mechListMIC,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ ret = GSS_S_COMPLETE;
+errout:
+ if (ret != GSS_S_COMPLETE) {
+ if (t)
+ free(t);
+ } else {
+ outbuf->length = ptr - t;
+ outbuf->value = (void *) t;
+ }
+
+ return (ret);
+}
+
+/* determine size of token */
+static int
+g_token_size(gss_OID_const mech, unsigned int body_size)
+{
+ int hdrsize;
+
+ /*
+ * Initialize the header size to the
+ * MECH_OID byte + the bytes needed to indicate the
+ * length of the OID + the OID itself.
+ *
+ * 0x06 [MECHLENFIELD] MECHDATA
+ */
+ hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+ /*
+ * Now add the bytes needed for the initial header
+ * token bytes:
+ * 0x60 + [DER_LEN] + HDRSIZE
+ */
+ hdrsize += 1 + gssint_der_length_size(body_size + hdrsize);
+
+ return (hdrsize + body_size);
+}
+
+/*
+ * generate token header.
+ *
+ * Use DER Definite Length method per RFC2478
+ * Use of indefinite length encoding will not be compatible
+ * with Microsoft or others that actually follow the spec.
+ */
+static int
+g_make_token_header(gss_OID_const mech,
+ unsigned int body_size,
+ unsigned char **buf,
+ unsigned int totallen)
+{
+ int ret = 0;
+ unsigned int hdrsize;
+ unsigned char *p = *buf;
+
+ hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+ *(*buf)++ = HEADER_ID;
+ if ((ret = gssint_put_der_length(hdrsize + body_size, buf, totallen)))
+ return (ret);
+
+ *(*buf)++ = MECH_OID;
+ if ((ret = gssint_put_der_length(mech->length, buf,
+ totallen - (int)(p - *buf))))
+ return (ret);
+ TWRITE_STR(*buf, mech->elements, mech->length);
+ return (0);
+}
+
+/*
+ * NOTE: This checks that the length returned by
+ * gssint_get_der_length() is not greater than the number of octets
+ * remaining, even though gssint_get_der_length() already checks, in
+ * theory.
+ */
+static int
+g_get_tag_and_length(unsigned char **buf, int tag,
+ unsigned int buflen, unsigned int *outlen)
+{
+ unsigned char *ptr = *buf;
+ int ret = -1; /* pessimists, assume failure ! */
+ unsigned int encoded_len;
+ int tmplen = 0;
+
+ *outlen = 0;
+ if (buflen > 1 && *ptr == tag) {
+ ptr++;
+ tmplen = gssint_get_der_length(&ptr, buflen - 1,
+ &encoded_len);
+ if (tmplen < 0) {
+ ret = -1;
+ } else if ((unsigned int)tmplen > buflen - (ptr - *buf)) {
+ ret = -1;
+ } else
+ ret = 0;
+ }
+ *outlen = tmplen;
+ *buf = ptr;
+ return (ret);
+}
+
+static int
+g_verify_neg_token_init(unsigned char **buf_in, unsigned int cur_size)
+{
+ unsigned char *buf = *buf_in;
+ unsigned char *endptr = buf + cur_size;
+ int seqsize;
+ int ret = 0;
+ unsigned int bytes;
+
+ /*
+ * Verify this is a NegotiationToken type token
+ * - check for a0(context specific identifier)
+ * - get length and verify that enoughd ata exists
+ */
+ if (g_get_tag_and_length(&buf, CONTEXT, cur_size, &bytes) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ cur_size = bytes; /* should indicate bytes remaining */
+
+ /*
+ * Verify the next piece, it should identify this as
+ * a strucure of type NegTokenInit.
+ */
+ if (*buf++ == SEQUENCE) {
+ if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+ /*
+ * Make sure we have the entire buffer as described
+ */
+ if (seqsize > endptr - buf)
+ return (G_BAD_TOK_HEADER);
+ } else {
+ return (G_BAD_TOK_HEADER);
+ }
+
+ cur_size = seqsize; /* should indicate bytes remaining */
+
+ /*
+ * Verify that the first blob is a sequence of mechTypes
+ */
+ if (*buf++ == CONTEXT) {
+ if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+ /*
+ * Make sure we have the entire buffer as described
+ */
+ if (seqsize > endptr - buf)
+ return (G_BAD_TOK_HEADER);
+ } else {
+ return (G_BAD_TOK_HEADER);
+ }
+
+ /*
+ * At this point, *buf should be at the beginning of the
+ * DER encoded list of mech types that are to be negotiated.
+ */
+ *buf_in = buf;
+
+ return (ret);
+
+}
+
+/* verify token header. */
+static int
+g_verify_token_header(gss_OID_const mech,
+ unsigned int *body_size,
+ unsigned char **buf_in,
+ int tok_type,
+ unsigned int toksize)
+{
+ unsigned char *buf = *buf_in;
+ int seqsize;
+ gss_OID_desc toid;
+ int ret = 0;
+ unsigned int bytes;
+
+ if (toksize-- < 1)
+ return (G_BAD_TOK_HEADER);
+
+ if (*buf++ != HEADER_ID)
+ return (G_BAD_TOK_HEADER);
+
+ if ((seqsize = gssint_get_der_length(&buf, toksize, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ if ((seqsize + bytes) != toksize)
+ return (G_BAD_TOK_HEADER);
+
+ if (toksize-- < 1)
+ return (G_BAD_TOK_HEADER);
+
+
+ if (*buf++ != MECH_OID)
+ return (G_BAD_TOK_HEADER);
+
+ if (toksize-- < 1)
+ return (G_BAD_TOK_HEADER);
+
+ toid.length = *buf++;
+
+ if (toksize < toid.length)
+ return (G_BAD_TOK_HEADER);
+ else
+ toksize -= toid.length;
+
+ toid.elements = buf;
+ buf += toid.length;
+
+ if (!g_OID_equal(&toid, mech))
+ ret = G_WRONG_MECH;
+
+ /*
+ * G_WRONG_MECH is not returned immediately because it's more important
+ * to return G_BAD_TOK_HEADER if the token header is in fact bad
+ */
+ if (toksize < 2)
+ return (G_BAD_TOK_HEADER);
+ else
+ toksize -= 2;
+
+ if (!ret) {
+ *buf_in = buf;
+ *body_size = toksize;
+ }
+
+ return (ret);
+}
+
+/*
+ * Return non-zero if the oid is one of the kerberos mech oids,
+ * otherwise return zero.
+ *
+ * N.B. There are 3 oids that represent the kerberos mech:
+ * RFC-specified GSS_MECH_KRB5_OID,
+ * Old pre-RFC GSS_MECH_KRB5_OLD_OID,
+ * Incorrect MS GSS_MECH_KRB5_WRONG_OID
+ */
+
+static int
+is_kerb_mech(gss_OID oid)
+{
+ int answer = 0;
+ OM_uint32 minor;
+ extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
+
+ (void) gss_test_oid_set_member(&minor,
+ oid, (gss_OID_set)gss_mech_set_krb5_both, &answer);
+
+ return (answer);
+}