+++ /dev/null
-From d491bc19b59fd9d6d9a46fffef1ed82ddec2503d Mon Sep 17 00:00:00 2001
-From: Pete Fotheringham <pete.fotheringham@codethink.co.uk>
-Date: Thu, 29 Dec 2011 10:05:50 +0000
-Subject: [PATCH] Move moonshot files up
-
----
- Makefile.am | 4 +
- acinclude.m4 | 364 ++++++++++
- autogen.sh | 16 +
- build-aux/compile | 144 ++++
- configure.ac | 92 +++
- libeap | 1 +
- m4/minuso.m4 | 35 +
- mech_eap.spec.in | 62 ++
- mech_eap/.gitignore | 32 +
- mech_eap/AUTHORS | 6 +
- mech_eap/COPYING | 3 +
- mech_eap/LICENSE | 31 +
- mech_eap/Makefile.am | 189 ++++++
- mech_eap/NOTES | 9 +
- mech_eap/README | 147 ++++
- mech_eap/README.samba4 | 52 ++
- mech_eap/TODO | 6 +
- mech_eap/accept_sec_context.c | 1072 +++++++++++++++++++++++++++++
- mech_eap/acquire_cred.c | 52 ++
- mech_eap/acquire_cred_with_password.c | 67 ++
- mech_eap/add_cred.c | 87 +++
- mech_eap/add_cred_with_password.c | 93 +++
- mech_eap/authdata_plugin.h | 331 +++++++++
- mech_eap/authorize_localname.c | 54 ++
- mech_eap/canonicalize_name.c | 64 ++
- mech_eap/compare_name.c | 46 ++
- mech_eap/context_time.c | 69 ++
- mech_eap/delete_name_attribute.c | 60 ++
- mech_eap/delete_sec_context.c | 81 +++
- mech_eap/dictionary.ukerna | 20 +
- mech_eap/display_name.c | 48 ++
- mech_eap/display_name_ext.c | 51 ++
- mech_eap/display_status.c | 203 ++++++
- mech_eap/duplicate_name.c | 60 ++
- mech_eap/eap_mech.c | 219 ++++++
- mech_eap/exchange_meta_data.c | 82 +++
- mech_eap/export_name.c | 60 ++
- mech_eap/export_name_composite.c | 62 ++
- mech_eap/export_sec_context.c | 246 +++++++
- mech_eap/get_mic.c | 89 +++
- mech_eap/get_name_attribute.c | 67 ++
- mech_eap/gssapiP_eap.h | 410 +++++++++++
- mech_eap/gssapi_eap.h | 90 +++
- mech_eap/gsseap_err.et | 162 +++++
- mech_eap/import_name.c | 47 ++
- mech_eap/import_sec_context.c | 374 ++++++++++
- mech_eap/indicate_mechs.c | 44 ++
- mech_eap/init_sec_context.c | 1097 ++++++++++++++++++++++++++++++
- mech_eap/inquire_attrs_for_mech.c | 137 ++++
- mech_eap/inquire_context.c | 116 ++++
- mech_eap/inquire_cred.c | 61 ++
- mech_eap/inquire_cred_by_mech.c | 76 +++
- mech_eap/inquire_cred_by_oid.c | 83 +++
- mech_eap/inquire_mech_for_saslname.c | 84 +++
- mech_eap/inquire_mechs_for_name.c | 69 ++
- mech_eap/inquire_name.c | 75 ++
- mech_eap/inquire_names_for_mech.c | 77 +++
- mech_eap/inquire_saslname_for_mech.c | 51 ++
- mech_eap/inquire_sec_context_by_oid.c | 248 +++++++
- mech_eap/install-sh | 520 ++++++++++++++
- mech_eap/map_name_to_any.c | 58 ++
- mech_eap/mech | 8 +
- mech_eap/mech_eap-noacceptor.exports | 55 ++
- mech_eap/mech_eap.exports | 63 ++
- mech_eap/mech_invoke.c | 44 ++
- mech_eap/process_context_token.c | 71 ++
- mech_eap/pseudo_random.c | 195 ++++++
- mech_eap/query_mechanism_info.c | 67 ++
- mech_eap/query_meta_data.c | 116 ++++
- mech_eap/radius_ad.exports | 1 +
- mech_eap/radsec.conf | 12 +
- mech_eap/radsec_err.et | 38 +
- mech_eap/release_any_name_mapping.c | 59 ++
- mech_eap/release_cred.c | 44 ++
- mech_eap/release_name.c | 44 ++
- mech_eap/release_oid.c | 44 ++
- mech_eap/set_cred_option.c | 208 ++++++
- mech_eap/set_name_attribute.c | 60 ++
- mech_eap/set_sec_context_option.c | 87 +++
- mech_eap/store_cred.c | 83 +++
- mech_eap/unwrap.c | 85 +++
- mech_eap/unwrap_iov.c | 572 ++++++++++++++++
- mech_eap/util.h | 1032 ++++++++++++++++++++++++++++
- mech_eap/util_adshim.c | 242 +++++++
- mech_eap/util_attr.cpp | 1191 ++++++++++++++++++++++++++++++++
- mech_eap/util_attr.h | 389 +++++++++++
- mech_eap/util_base64.c | 161 +++++
- mech_eap/util_base64.h | 58 ++
- mech_eap/util_buffer.c | 103 +++
- mech_eap/util_cksum.c | 242 +++++++
- mech_eap/util_context.c | 377 +++++++++++
- mech_eap/util_cred.c | 756 +++++++++++++++++++++
- mech_eap/util_crypt.c | 397 +++++++++++
- mech_eap/util_json.cpp | 513 ++++++++++++++
- mech_eap/util_json.h | 182 +++++
- mech_eap/util_krb.c | 632 +++++++++++++++++
- mech_eap/util_lucid.c | 183 +++++
- mech_eap/util_mech.c | 380 +++++++++++
- mech_eap/util_moonshot.c | 238 +++++++
- mech_eap/util_name.c | 789 ++++++++++++++++++++++
- mech_eap/util_oid.c | 206 ++++++
- mech_eap/util_ordering.c | 302 +++++++++
- mech_eap/util_radius.cpp | 899 +++++++++++++++++++++++++
- mech_eap/util_radius.h | 183 +++++
- mech_eap/util_reauth.c | 1196 +++++++++++++++++++++++++++++++++
- mech_eap/util_reauth.h | 151 +++++
- mech_eap/util_saml.cpp | 775 +++++++++++++++++++++
- mech_eap/util_saml.h | 176 +++++
- mech_eap/util_shib.cpp | 555 +++++++++++++++
- mech_eap/util_shib.h | 122 ++++
- mech_eap/util_sm.c | 372 ++++++++++
- mech_eap/util_tld.c | 167 +++++
- mech_eap/util_token.c | 493 ++++++++++++++
- mech_eap/verify_mic.c | 71 ++
- mech_eap/wrap.c | 137 ++++
- mech_eap/wrap_iov.c | 379 +++++++++++
- mech_eap/wrap_iov_length.c | 234 +++++++
- mech_eap/wrap_size_limit.c | 97 +++
- 118 files changed, 24691 insertions(+), 0 deletions(-)
- create mode 100644 Makefile.am
- create mode 100644 acinclude.m4
- create mode 100755 autogen.sh
- create mode 100755 build-aux/compile
- create mode 100644 configure.ac
- create mode 160000 libeap
- create mode 100644 m4/minuso.m4
- create mode 100644 mech_eap.spec.in
- create mode 100644 mech_eap/.gitignore
- create mode 100644 mech_eap/AUTHORS
- create mode 100644 mech_eap/COPYING
- create mode 100644 mech_eap/LICENSE
- create mode 100644 mech_eap/Makefile.am
- create mode 100644 mech_eap/NEWS
- create mode 100644 mech_eap/NOTES
- create mode 100644 mech_eap/README
- create mode 100644 mech_eap/README.samba4
- create mode 100644 mech_eap/TODO
- create mode 100644 mech_eap/accept_sec_context.c
- create mode 100644 mech_eap/acquire_cred.c
- create mode 100644 mech_eap/acquire_cred_with_password.c
- create mode 100644 mech_eap/add_cred.c
- create mode 100644 mech_eap/add_cred_with_password.c
- create mode 100644 mech_eap/authdata_plugin.h
- create mode 100644 mech_eap/authorize_localname.c
- create mode 100644 mech_eap/canonicalize_name.c
- create mode 100644 mech_eap/compare_name.c
- create mode 100644 mech_eap/context_time.c
- create mode 100644 mech_eap/delete_name_attribute.c
- create mode 100644 mech_eap/delete_sec_context.c
- create mode 100644 mech_eap/dictionary.ukerna
- create mode 100644 mech_eap/display_name.c
- create mode 100644 mech_eap/display_name_ext.c
- create mode 100644 mech_eap/display_status.c
- create mode 100644 mech_eap/duplicate_name.c
- create mode 100644 mech_eap/eap_mech.c
- create mode 100644 mech_eap/exchange_meta_data.c
- create mode 100644 mech_eap/export_name.c
- create mode 100644 mech_eap/export_name_composite.c
- create mode 100644 mech_eap/export_sec_context.c
- create mode 100644 mech_eap/get_mic.c
- create mode 100644 mech_eap/get_name_attribute.c
- create mode 100644 mech_eap/gssapiP_eap.h
- create mode 100644 mech_eap/gssapi_eap.h
- create mode 100644 mech_eap/gsseap_err.et
- create mode 100644 mech_eap/import_name.c
- create mode 100644 mech_eap/import_sec_context.c
- create mode 100644 mech_eap/indicate_mechs.c
- create mode 100644 mech_eap/init_sec_context.c
- create mode 100644 mech_eap/inquire_attrs_for_mech.c
- create mode 100644 mech_eap/inquire_context.c
- create mode 100644 mech_eap/inquire_cred.c
- create mode 100644 mech_eap/inquire_cred_by_mech.c
- create mode 100644 mech_eap/inquire_cred_by_oid.c
- create mode 100644 mech_eap/inquire_mech_for_saslname.c
- create mode 100644 mech_eap/inquire_mechs_for_name.c
- create mode 100644 mech_eap/inquire_name.c
- create mode 100644 mech_eap/inquire_names_for_mech.c
- create mode 100644 mech_eap/inquire_saslname_for_mech.c
- create mode 100644 mech_eap/inquire_sec_context_by_oid.c
- create mode 100755 mech_eap/install-sh
- create mode 100644 mech_eap/map_name_to_any.c
- create mode 100644 mech_eap/mech
- create mode 100644 mech_eap/mech_eap-noacceptor.exports
- create mode 100644 mech_eap/mech_eap.exports
- create mode 100644 mech_eap/mech_invoke.c
- create mode 100644 mech_eap/process_context_token.c
- create mode 100644 mech_eap/pseudo_random.c
- create mode 100644 mech_eap/query_mechanism_info.c
- create mode 100644 mech_eap/query_meta_data.c
- create mode 100644 mech_eap/radius_ad.exports
- create mode 100644 mech_eap/radsec.conf
- create mode 100644 mech_eap/radsec_err.et
- create mode 100644 mech_eap/release_any_name_mapping.c
- create mode 100644 mech_eap/release_cred.c
- create mode 100644 mech_eap/release_name.c
- create mode 100644 mech_eap/release_oid.c
- create mode 100644 mech_eap/set_cred_option.c
- create mode 100644 mech_eap/set_name_attribute.c
- create mode 100644 mech_eap/set_sec_context_option.c
- create mode 100644 mech_eap/store_cred.c
- create mode 100644 mech_eap/unwrap.c
- create mode 100644 mech_eap/unwrap_iov.c
- create mode 100644 mech_eap/util.h
- create mode 100644 mech_eap/util_adshim.c
- create mode 100644 mech_eap/util_attr.cpp
- create mode 100644 mech_eap/util_attr.h
- create mode 100644 mech_eap/util_base64.c
- create mode 100644 mech_eap/util_base64.h
- create mode 100644 mech_eap/util_buffer.c
- create mode 100644 mech_eap/util_cksum.c
- create mode 100644 mech_eap/util_context.c
- create mode 100644 mech_eap/util_cred.c
- create mode 100644 mech_eap/util_crypt.c
- create mode 100644 mech_eap/util_json.cpp
- create mode 100644 mech_eap/util_json.h
- create mode 100644 mech_eap/util_krb.c
- create mode 100644 mech_eap/util_lucid.c
- create mode 100644 mech_eap/util_mech.c
- create mode 100644 mech_eap/util_moonshot.c
- create mode 100644 mech_eap/util_name.c
- create mode 100644 mech_eap/util_oid.c
- create mode 100644 mech_eap/util_ordering.c
- create mode 100644 mech_eap/util_radius.cpp
- create mode 100644 mech_eap/util_radius.h
- create mode 100644 mech_eap/util_reauth.c
- create mode 100644 mech_eap/util_reauth.h
- create mode 100644 mech_eap/util_saml.cpp
- create mode 100644 mech_eap/util_saml.h
- create mode 100644 mech_eap/util_shib.cpp
- create mode 100644 mech_eap/util_shib.h
- create mode 100644 mech_eap/util_sm.c
- create mode 100644 mech_eap/util_tld.c
- create mode 100644 mech_eap/util_token.c
- create mode 100644 mech_eap/verify_mic.c
- create mode 100644 mech_eap/wrap.c
- create mode 100644 mech_eap/wrap_iov.c
- create mode 100644 mech_eap/wrap_iov_length.c
- create mode 100644 mech_eap/wrap_size_limit.c
-
-diff --git a/Makefile.am b/Makefile.am
-new file mode 100644
-index 0000000..0165219
---- /dev/null
-+++ b/Makefile.am
-@@ -0,0 +1,4 @@
-+AUTOMAKE_OPTIONS = foreign
-+ACLOCAL_AMFLAGS = -I m4
-+SUBDIRS = libeap mech_eap
-+EXTRA_DIST = mech_eap.spec
-diff --git a/acinclude.m4 b/acinclude.m4
-new file mode 100644
-index 0000000..6f43261
---- /dev/null
-+++ b/acinclude.m4
-@@ -0,0 +1,364 @@
-+dnl Based on the one from the Boinc project by Reinhard
-+
-+AC_DEFUN([AX_CHECK_WINDOWS],
-+[AC_MSG_CHECKING(for windows)
-+target_windows="no"
-+AC_CHECK_HEADER(windows.h,[target_windows="yes"],[target_windows="no"])
-+AC_MSG_RESULT($target_windows)
-+AM_CONDITIONAL(TARGET_WINDOWS,test "x$target_windows" = "xyes")
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_KRB5],
-+[AC_MSG_CHECKING(for GSS-API and Kerberos implementation)
-+KRB5_DIR=
-+found_krb5="no"
-+AC_ARG_WITH(krb5,
-+ AC_HELP_STRING([--with-krb5],
-+ [Use krb5 (in specified installation directory)]),
-+ [check_krb5_dir="$withval"],
-+ [check_krb5_dir=])
-+for dir in $check_krb5_dir $prefix /usr/local /usr ; do
-+ krb5dir="$dir"
-+ if test -x "$dir/bin/krb5-config"; then
-+ found_krb5="yes";
-+ if test "x$target_windows" = "xyes"; then
-+ KRB5_CFLAGS=-I"$check_krb5_dir/include";
-+ KRB5_LDFLAGS="-L$check_krb5_dir/lib/";
-+ KRB5_LIBS="-lkrb5_32 -lgssapi32";
-+ COMPILE_ET="$check_krb5_dir/bin/compile_et";
-+ AC_MSG_RESULT([yes])
-+ else
-+ KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
-+ KRB5_LDFLAGS="-L$dir/lib";
-+ KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`
-+AC_MSG_RESULT([yes])
-+ AC_PATH_PROG(COMPILE_ET, [compile_et], [compile_et], [$dir/bin$PATH_SEPARATOr])
-+ fi
-+ break;
-+ fi
-+done
-+if test x_$found_krb5 != x_yes; then
-+ AC_MSG_RESULT($found_krb5)
-+ AC_MSG_ERROR([
-+----------------------------------------------------------------------
-+ Cannot find GSS-API/Kerberos libraries.
-+
-+ Please install MIT or Heimdal or specify installation directory with
-+ --with-krb5=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "Kerberos found in $krb5dir\n";
-+ AC_SUBST(KRB5_CFLAGS)
-+ AC_SUBST(KRB5_LDFLAGS)
-+ AC_SUBST(KRB5_LIBS)
-+ AC_SUBST(COMPILE_ET)
-+ AC_CHECK_LIB(krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS")
-+ AC_CHECK_LIB(krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS")
-+ AC_CHECK_LIB(krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS")
-+ AC_CHECK_LIB(krb5, heimdal_version, [AC_DEFINE_UNQUOTED([HAVE_HEIMDAL_VERSION], 1, [Define if building against Heimdal Kerberos implementation]), heimdal=yes], [heimdal=no], "$KRB5_LIBS")
-+ AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno")
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_EAP],
-+[AC_MSG_CHECKING(for EAP implementation)
-+EAP_DIR=
-+found_eap="no"
-+AC_ARG_WITH(eap,
-+ AC_HELP_STRING([--with-eap],
-+ [Use eap (in specified installation directory)]),
-+ [check_eap_dir="$withval"],
-+ [check_eap_dir=])
-+for dir in $check_eap_dir $prefix /usr /usr/local ../libeap ; do
-+ eapdir="$dir"
-+ if test -f "$dir/src/eap_peer/eap.h"; then
-+ found_eap="yes";
-+ EAP_DIR="${eapdir}"
-+ EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils";
-+ break;
-+ fi
-+done
-+AC_MSG_RESULT($found_eap)
-+if test x_$found_eap != x_yes; then
-+ AC_MSG_ERROR([
-+----------------------------------------------------------------------
-+ Cannot find EAP libraries.
-+
-+ Please install wpa_supplicant or specify installation directory with
-+ --with-eap=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "EAP found in $eapdir\n";
-+ EAP_CFLAGS="$EAP_CFLAGS \
-+-DEAP_TLS \
-+-DEAP_PEAP \
-+-DEAP_TTLS \
-+-DEAP_MD5 \
-+-DEAP_MSCHAPv2 \
-+-DEAP_GTC \
-+-DEAP_OTP \
-+-DEAP_LEAP \
-+-DEAP_PSK \
-+-DEAP_PAX \
-+-DEAP_SAKE \
-+-DEAP_GPSK \
-+-DEAP_GPSK_SHA256 \
-+-DEAP_SERVER_IDENTITY \
-+-DEAP_SERVER_TLS \
-+-DEAP_SERVER_PEAP \
-+-DEAP_SERVER_TTLS \
-+-DEAP_SERVER_MD5 \
-+-DEAP_SERVER_MSCHAPV2 \
-+-DEAP_SERVER_GTC \
-+-DEAP_SERVER_PSK \
-+-DEAP_SERVER_PAX \
-+-DEAP_SERVER_SAKE \
-+-DEAP_SERVER_GPSK \
-+-DEAP_SERVER_GPSK_SHA256 \
-+-DIEEE8021X_EAPOL";
-+ EAP_LIBS="-leap -lutils -lcrypto -ltls";
-+ EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls";
-+ AC_SUBST(EAP_CFLAGS)
-+ AC_SUBST(EAP_LDFLAGS)
-+ AC_SUBST(EAP_LIBS)
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_SHIBSP],
-+[AC_MSG_CHECKING(for Shibboleth implementation)
-+SHIBSP_DIR=
-+found_shibsp="no"
-+AC_ARG_WITH(shibsp,
-+ AC_HELP_STRING([--with-shibsp],
-+ [Use shibspboleth (in specified installation directory)]),
-+ [check_shibsp_dir="$withval"],
-+ [check_shibsp_dir=])
-+for dir in $check_shibsp_dir $prefix /usr /usr/local ; do
-+ shibspdir="$dir"
-+ if test -f "$dir/include/shibsp/SPConfig.h"; then
-+ found_shibsp="yes";
-+ SHIBSP_DIR="${shibspdir}"
-+ SHIBSP_CXXFLAGS="-I$shibspdir/include";
-+ break;
-+ fi
-+done
-+AC_MSG_RESULT($found_shibsp)
-+if test x_$found_shibsp != x_yes; then
-+ AC_MSG_ERROR([
-+----------------------------------------------------------------------
-+ Cannot find Shibboleth libraries.
-+
-+ Please install Shibboleth or specify installation directory with
-+ --with-shibsp=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "Shibboleth found in $shibspdir\n";
-+ SHIBSP_LIBS="-lshibsp -lsaml -lxml-security-c -lxmltooling -lxerces-c";
-+ SHIBSP_LDFLAGS="-L$shibspdir/lib";
-+ AC_SUBST(SHIBSP_CXXFLAGS)
-+ AC_SUBST(SHIBSP_LDFLAGS)
-+ AC_SUBST(SHIBSP_LIBS)
-+ AC_DEFINE_UNQUOTED([HAVE_SHIBSP], 1, [Define is Shibboleth SP is available])
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_SHIBRESOLVER],
-+[AC_MSG_CHECKING(for Shibboleth resolver implementation)
-+SHIBRESOLVER_DIR=
-+found_shibresolver="no"
-+AC_ARG_WITH(shibresolver,
-+ AC_HELP_STRING([--with-shibresolver],
-+ [Use Shibboleth resolver (in specified installation directory)]),
-+ [check_shibresolver_dir="$withval"],
-+ [check_shibresolver_dir=])
-+if test x_$check_shibresolver_dir != x_no; then
-+for dir in $check_shibresolver_dir $prefix /usr /usr/local ; do
-+ shibresolverdir="$dir"
-+ if test -f "$dir/include/shibresolver/resolver.h"; then
-+ found_shibresolver="yes";
-+ SHIBRESOLVER_DIR="${shibresolverdir}"
-+ SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include";
-+ break;
-+ fi
-+done
-+fi
-+AC_MSG_RESULT($found_shibresolver)
-+if test x_$check_shibresolver_dir != x_no; then
-+if test x_$found_shibresolver != x_yes; then
-+ AC_MSG_WARN([
-+----------------------------------------------------------------------
-+ Cannot find Shibboleth resolver libraries, building without
-+ Shibboleth support.
-+
-+ Please install Shibboleth or specify installation directory with
-+ --with-shibresolver=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "Shibboleth resolver found in $shibresolverdir\n";
-+ SHIBRESOLVER_LIBS="-lshibresolver";
-+ SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib";
-+ AC_SUBST(SHIBRESOLVER_CXXFLAGS)
-+ AC_SUBST(SHIBRESOLVER_LDFLAGS)
-+ AC_SUBST(SHIBRESOLVER_LIBS)
-+ AC_DEFINE_UNQUOTED([HAVE_SHIBRESOLVER], 1, [Define is Shibboleth resolver is available])
-+fi
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_OPENSAML],
-+[AC_MSG_CHECKING(for OpenSAML implementation)
-+OPENSAML_DIR=
-+found_opensaml="no"
-+AC_ARG_WITH(opensaml,
-+ AC_HELP_STRING([--with-opensaml],
-+ [Use OpenSAML (in specified installation directory)]),
-+ [check_opensaml_dir="$withval"],
-+ [check_opensaml_dir=])
-+if test x_$check_opensaml_dir != x_no; then
-+for dir in $check_opensaml_dir $prefix /usr /usr/local ; do
-+ opensamldir="$dir"
-+ if test -f "$dir/include/saml/Assertion.h"; then
-+ found_opensaml="yes";
-+ OPENSAML_DIR="${opensamldir}"
-+ OPENSAML_CXXFLAGS="-I$opensamldir/include";
-+ break;
-+ fi
-+done
-+fi
-+AC_MSG_RESULT($found_opensaml)
-+if test x_$check_opensaml_dir != x_no; then
-+if test x_$found_opensaml != x_yes; then
-+ AC_MSG_WARN([
-+----------------------------------------------------------------------
-+ Cannot find OpenSAML libraries, building without OpenSAML support.
-+
-+ Please install OpenSAML or specify installation directory with
-+ --with-opensaml=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "OpenSAML found in $opensamldir\n";
-+ OPENSAML_LIBS="-lsaml -lxml-security-c -lxmltooling -lxerces-c";
-+ OPENSAML_LDFLAGS="-L$opensamldir/lib";
-+ AC_SUBST(OPENSAML_CXXFLAGS)
-+ AC_SUBST(OPENSAML_LDFLAGS)
-+ AC_SUBST(OPENSAML_LIBS)
-+ AC_DEFINE_UNQUOTED([HAVE_OPENSAML], 1, [Define is OpenSAML is available])
-+fi
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_RADSEC],
-+[AC_MSG_CHECKING(for radsec)
-+RADSEC_DIR=
-+found_radsec="no"
-+AC_ARG_WITH(radsec,
-+ AC_HELP_STRING([--with-radsec],
-+ [Use radsec (in specified installation directory)]),
-+ [check_radsec_dir="$withval"],
-+ [check_radsec_dir=])
-+for dir in $check_radsec_dir $prefix /usr /usr/local ; do
-+ radsecdir="$dir"
-+ if test -f "$dir/include/radsec/radsec.h"; then
-+ found_radsec="yes";
-+ RADSEC_DIR="${radsecdir}"
-+ RADSEC_CFLAGS="-I$radsecdir/include";
-+ break;
-+ fi
-+done
-+AC_MSG_RESULT($found_radsec)
-+if test x_$found_radsec != x_yes; then
-+ AC_MSG_ERROR([
-+----------------------------------------------------------------------
-+ Cannot find radsec libraries.
-+
-+ Please install libradsec or specify installation directory with
-+ --with-radsec=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "radsec found in $radsecdir\n";
-+ RADSEC_LIBS="-lradsec";
-+ RADSEC_LDFLAGS="-L$radsecdir/lib";
-+ AC_SUBST(RADSEC_CFLAGS)
-+ AC_SUBST(RADSEC_LDFLAGS)
-+ AC_SUBST(RADSEC_LIBS)
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_JANSSON],
-+[AC_MSG_CHECKING(for jansson)
-+JANSSON_DIR=
-+found_jansson="no"
-+AC_ARG_WITH(jansson,
-+ AC_HELP_STRING([--with-jansson],
-+ [Use jansson (in specified installation directory)]),
-+ [check_jansson_dir="$withval"],
-+ [check_jansson_dir=])
-+for dir in $check_jansson_dir $prefix /usr /usr/local ; do
-+ janssondir="$dir"
-+ if test -f "$dir/include/jansson.h"; then
-+ found_jansson="yes";
-+ JANSSON_DIR="${janssondir}"
-+ JANSSON_CFLAGS="-I$janssondir/include";
-+ break;
-+ fi
-+done
-+AC_MSG_RESULT($found_jansson)
-+if test x_$found_jansson != x_yes; then
-+ AC_MSG_ERROR([
-+----------------------------------------------------------------------
-+ Cannot find jansson libraries.
-+
-+ Please install libjansson or specify installation directory with
-+ --with-jansson=(dir).
-+----------------------------------------------------------------------
-+])
-+else
-+ printf "jansson found in $janssondir\n";
-+ JANSSON_LIBS="-ljansson";
-+ JANSSON_LDFLAGS="-L$janssondir/lib";
-+ AC_SUBST(JANSSON_CFLAGS)
-+ AC_SUBST(JANSSON_LDFLAGS)
-+ AC_SUBST(JANSSON_LIBS)
-+fi
-+])dnl
-+
-+AC_DEFUN([AX_CHECK_LIBMOONSHOT],
-+[AC_MSG_CHECKING(for Moonshot identity selector implementation)
-+LIBMOONSHOT_DIR=
-+LIBMOONSHOT_CFLAGS=
-+LIBMOONSHOT_LDFLAGS=
-+LIBMOONSHOT_LIBS=
-+found_libmoonshot="no"
-+AC_ARG_WITH(libmoonshot,
-+ AC_HELP_STRING([--with-libmoonshot],
-+ [Use libmoonshot (in specified installation directory)]),
-+ [check_libmoonshot_dir="$withval"],
-+ [check_libmoonshot_dir=])
-+for dir in $check_libmoonshot_dir $prefix /usr /usr/local ; do
-+ libmoonshotdir="$dir"
-+ if test -f "$dir/include/libmoonshot.h"; then
-+ found_libmoonshot="yes";
-+ LIBMOONSHOT_DIR="${libmoonshotdir}"
-+ LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include";
-+ break;
-+ fi
-+done
-+AC_MSG_RESULT($found_libmoonshot)
-+if test x_$found_libmoonshot = x_yes; then
-+ printf "libmoonshot found in $libmoonshotdir\n";
-+ LIBMOONSHOT_LIBS="-lmoonshot";
-+ LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib";
-+ AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS")
-+fi
-+ AC_SUBST(LIBMOONSHOT_CFLAGS)
-+ AC_SUBST(LIBMOONSHOT_LDFLAGS)
-+ AC_SUBST(LIBMOONSHOT_LIBS)
-+ AM_CONDITIONAL(LIBMOONSHOT, test "x$found_libmoonshot" != "xno")
-+])dnl
-+
-diff --git a/autogen.sh b/autogen.sh
-new file mode 100755
-index 0000000..13432d0
---- /dev/null
-+++ b/autogen.sh
-@@ -0,0 +1,16 @@
-+#!/bin/sh
-+#
-+# Regenerate autotools files.
-+#
-+
-+PATH=/usr/local/bin:$PATH
-+
-+if [ -x "`which autoreconf 2>/dev/null`" ] ; then
-+ exec autoreconf -ivf
-+fi
-+
-+aclocal -I . -I m4 && \
-+ autoheader && \
-+ libtoolize --automake -c && \
-+ autoconf && \
-+ automake --add-missing --copy
-diff --git a/build-aux/compile b/build-aux/compile
-new file mode 100755
-index 0000000..5360806
---- /dev/null
-+++ b/build-aux/compile
-@@ -0,0 +1,144 @@
-+#! /bin/sh
-+# Wrapper for compilers which do not understand `-c -o'.
-+
-+scriptversion=2009-10-06.20; # UTC
-+
-+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software
-+# Foundation, Inc.
-+# Written by Tom Tromey <tromey@cygnus.com>.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2, or (at your option)
-+# any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-+
-+# As a special exception to the GNU General Public License, if you
-+# distribute this file as part of a program that contains a
-+# configuration script generated by Autoconf, you may include it under
-+# the same distribution terms that you use for the rest of that program.
-+
-+# This file is maintained in Automake, please report
-+# bugs to <bug-automake@gnu.org> or send patches to
-+# <automake-patches@gnu.org>.
-+
-+case $1 in
-+ '')
-+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
-+ exit 1;
-+ ;;
-+ -h | --h*)
-+ cat <<\EOF
-+Usage: compile [--help] [--version] PROGRAM [ARGS]
-+
-+Wrapper for compilers which do not understand `-c -o'.
-+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
-+arguments, and rename the output as expected.
-+
-+If you are trying to build a whole package this is not the
-+right script to run: please start by reading the file `INSTALL'.
-+
-+Report bugs to <bug-automake@gnu.org>.
-+EOF
-+ exit $?
-+ ;;
-+ -v | --v*)
-+ echo "compile $scriptversion"
-+ exit $?
-+ ;;
-+esac
-+
-+ofile=
-+cfile=
-+eat=
-+
-+for arg
-+do
-+ if test -n "$eat"; then
-+ eat=
-+ else
-+ case $1 in
-+ -o)
-+ # configure might choose to run compile as `compile cc -o foo foo.c'.
-+ # So we strip `-o arg' only if arg is an object.
-+ eat=1
-+ case $2 in
-+ *.o | *.obj)
-+ ofile=$2
-+ ;;
-+ *)
-+ set x "$@" -o "$2"
-+ shift
-+ ;;
-+ esac
-+ ;;
-+ *.c)
-+ cfile=$1
-+ set x "$@" "$1"
-+ shift
-+ ;;
-+ *)
-+ set x "$@" "$1"
-+ shift
-+ ;;
-+ esac
-+ fi
-+ shift
-+done
-+
-+if test -z "$ofile" || test -z "$cfile"; then
-+ # If no `-o' option was seen then we might have been invoked from a
-+ # pattern rule where we don't need one. That is ok -- this is a
-+ # normal compilation that the losing compiler can handle. If no
-+ # `.c' file was seen then we are probably linking. That is also
-+ # ok.
-+ exec "$@"
-+fi
-+
-+# Name of file we expect compiler to create.
-+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
-+
-+# Create the lock directory.
-+# Note: use `[/\\:.-]' here to ensure that we don't use the same name
-+# that we are using for the .o file. Also, base the name on the expected
-+# object file name, since that is what matters with a parallel build.
-+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
-+while true; do
-+ if mkdir "$lockdir" >/dev/null 2>&1; then
-+ break
-+ fi
-+ sleep 1
-+done
-+# FIXME: race condition here if user kills between mkdir and trap.
-+trap "rmdir '$lockdir'; exit 1" 1 2 15
-+
-+# Run the compile.
-+"$@"
-+ret=$?
-+
-+if test -f "$cofile"; then
-+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
-+elif test -f "${cofile}bj"; then
-+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
-+fi
-+
-+rmdir "$lockdir"
-+exit $ret
-+
-+# Local Variables:
-+# mode: shell-script
-+# sh-indentation: 2
-+# eval: (add-hook 'write-file-hooks 'time-stamp)
-+# time-stamp-start: "scriptversion="
-+# time-stamp-format: "%:y-%02m-%02d.%02H"
-+# time-stamp-time-zone: "UTC"
-+# time-stamp-end: "; # UTC"
-+# End:
-diff --git a/configure.ac b/configure.ac
-new file mode 100644
-index 0000000..4297345
---- /dev/null
-+++ b/configure.ac
-@@ -0,0 +1,92 @@
-+AC_PREREQ([2.61])
-+AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
-+AC_CONFIG_MACRO_DIR([m4])
-+AC_CONFIG_AUX_DIR([build-aux])
-+
-+dnl AM_INIT_AUTOMAKE([silent-rules])
-+AC_USE_SYSTEM_EXTENSIONS
-+AM_INIT_AUTOMAKE
-+AM_PROG_CC_C_O
-+AM_MAINTAINER_MODE()
-+LT_PREREQ([2.2])
-+LT_INIT([dlopen disable-static win32-dll])
-+
-+dnl AC_PROG_CC
-+AC_PROG_CXX
-+AC_CONFIG_HEADERS([config.h])
-+AC_CHECK_HEADERS(stdarg.h stdio.h stdint.h sys/param.h)
-+AC_REPLACE_FUNCS(vasprintf)
-+
-+dnl Check if we're on Solaris and set CFLAGS accordingly
-+dnl AC_CANONICAL_TARGET
-+dnl case "${target_os}" in
-+dnl solaris*)
-+dnl TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS"
-+dnl if test "$GCC" != yes ; then
-+dnl TARGET_CFLAGS="$TARGET_CFLAGS -mt"
-+dnl else
-+dnl TARGET_CFLAGS="$TARGET_CFLAGS -pthreads"
-+dnl fi
-+dnl TARGET_LDFLAGS="-lpthread -lsocket -lnsl"
-+dnl ;;
-+dnl *)
-+dnl TARGET_CFLAGS="-Wall -pedantic -pthread"
-+dnl TARGET_LDFLAGS=""
-+dnl esac
-+
-+reauth=no
-+AC_ARG_ENABLE(reauth,
-+ [ --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ],
-+ [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
-+ reauth=$enableval
-+ else
-+ echo "--enable-reauth argument must be yes or no"
-+ exit -1
-+ fi
-+ ])
-+
-+if test "x$reauth" = "xyes" ; then
-+ echo "Fast reauthentication protocol enabled"
-+ TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH"
-+fi
-+AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "x$reauth" != "xno")
-+
-+acceptor=yes
-+AC_ARG_ENABLE(acceptor,
-+ [ --enable-acceptor whether to enable acceptor codepaths: yes/no; default yes ],
-+ [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
-+ acceptor=$enableval
-+ else
-+ echo "--enable-acceptor argument must be yes or no"
-+ exit -1
-+ fi
-+ ])
-+
-+if test "x$acceptor" = "xyes" ; then
-+ echo "acceptor enabled"
-+ TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_ACCEPTOR"
-+fi
-+AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, test "x$acceptor" != "xno")
-+
-+AC_SUBST(TARGET_CFLAGS)
-+AC_SUBST(TARGET_LDFLAGS)
-+AX_CHECK_WINDOWS
-+AX_CHECK_KRB5
-+AX_CHECK_OPENSAML
-+AM_CONDITIONAL(OPENSAML, test "x_$check_opensaml_dir" != "x_no")
-+
-+AX_CHECK_SHIBRESOLVER
-+AM_CONDITIONAL(SHIBRESOLVER, test "x_$check_shibresolver_dir" != "x_no")
-+if test x_$found_shibresolver = x_yes; then
-+ AX_CHECK_SHIBSP
-+fi
-+
-+if test "x$acceptor" = "xyes" ; then
-+ AX_CHECK_RADSEC
-+ AX_CHECK_JANSSON
-+fi
-+
-+AX_CHECK_LIBMOONSHOT
-+AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile
-+ mech_eap.spec])
-+AC_OUTPUT
-diff --git a/libeap b/libeap
-new file mode 160000
-index 0000000..3c68005
---- /dev/null
-+++ b/libeap
-@@ -0,0 +1 @@
-+Subproject commit 3c6800594dbfcba5d36cfa5556288eae999f83ba
-diff --git a/m4/minuso.m4 b/m4/minuso.m4
-new file mode 100644
-index 0000000..d8b1620
---- /dev/null
-+++ b/m4/minuso.m4
-@@ -0,0 +1,35 @@
-+## -*- Autoconf -*-
-+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
-+# Free Software Foundation, Inc.
-+#
-+# This file is free software; the Free Software Foundation
-+# gives unlimited permission to copy and/or distribute it,
-+# with or without modifications, as long as this notice is preserved.
-+
-+# serial 6
-+
-+# AM_PROG_CC_C_O
-+# --------------
-+# Like AC_PROG_CC_C_O, but changed for automake.
-+AC_DEFUN([AM_PROG_CC_C_O],
-+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
-+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-+AC_REQUIRE_AUX_FILE([compile])dnl
-+# FIXME: we rely on the cache variable name because
-+# there is no other way.
-+set dummy $CC
-+am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
-+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
-+if test "$am_t" != yes; then
-+ # Losing compiler, so override with the script.
-+ # FIXME: It is wrong to rewrite CC.
-+ # But if we don't then we get into trouble of one sort or another.
-+ # A longer-term fix would be to have automake use am__CC in this case,
-+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
-+ CC="$am_aux_dir/compile $CC"
-+fi
-+dnl Make sure AC_PROG_CC is never called again, or it will override our
-+dnl setting of CC.
-+m4_define([AC_PROG_CC],
-+ [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
-+])
-diff --git a/mech_eap.spec.in b/mech_eap.spec.in
-new file mode 100644
-index 0000000..90ac6cf
---- /dev/null
-+++ b/mech_eap.spec.in
-@@ -0,0 +1,62 @@
-+%global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5}
-+Name: moonshot-gss-eap
-+Version: @VERSION@
-+Release: 3%{?dist}
-+Summary: Moonshot GSS-API Mechanism
-+
-+Group: Security Tools
-+License: BSD
-+URL: http://www.project-moonshot.org/
-+Source0: mech_eap-%{version}.tar.gz
-+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
-+
-+BuildRequires: %{_moonshot_krb5} >= 1.9.1
-+BuildRequires: moonshot-ui-devel
-+BuildRequires: jansson-devel
-+Requires: moonshot-ui
-+BuildRequires: libradsec-devel
-+BuildRequires: shibboleth-devel >= 2.5
-+BuildRequires: libshibresolver-devel
-+
-+
-+
-+%description
-+Project Moonshot provides federated access management.
-+
-+
-+%prep
-+%setup -q -n mech_eap-%{version}
-+
-+
-+%build
-+ export LDFLAGS='-L/usr/%{_lib}/freeradius -Wl,--rpath=/usr/%{_lib}/freeradius'
-+%configure --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --disable-reauth
-+make %{?_smp_mflags}
-+
-+
-+%install
-+rm -rf $RPM_BUILD_ROOT
-+make install DESTDIR=$RPM_BUILD_ROOT
-+
-+
-+%clean
-+rm -rf $RPM_BUILD_ROOT
-+
-+
-+%files
-+%defattr(-,root,root,-)
-+%doc mech_eap/README
-+%doc mech_eap/LICENSE
-+%doc mech_eap/AUTHORS
-+%{_libdir}/gss/mech_eap.so
-+%exclude %{_libdir}/gss/mech_eap.la
-+%{_includedir}/gssapi/*.h
-+#%exclude %{_libdir}/krb5/plugins/authdata/*la
-+#%{_libdir}/krb5/plugins/authdata/*.so
-+
-+
-+
-+%changelog
-+* Wed Sep 28 2011 <hartmans@moonbuildcentos.dev.ja.net> - @VERSION@-2
-+- Add radius_ad plugin
-+
-diff --git a/mech_eap/.gitignore b/mech_eap/.gitignore
-new file mode 100644
-index 0000000..06a3924
---- /dev/null
-+++ b/mech_eap/.gitignore
-@@ -0,0 +1,32 @@
-+/aclocal.m4
-+/autom4te.cache
-+/compile
-+/config.guess
-+/config.log
-+/config.status
-+/config.sub
-+/config.h
-+/configure
-+/config.h.in
-+/depcomp
-+
-+/libtool
-+/ltmain.sh
-+/missing
-+
-+/gsseap_err.[ch]
-+/radsec_err.[ch]
-+
-+.DS_Store
-+
-+Makefile.in
-+Makefile
-+
-+*.la
-+*.lo
-+*~
-+
-+.deps
-+.libs
-+.a.out.dSYM
-+.dSYM
-diff --git a/mech_eap/AUTHORS b/mech_eap/AUTHORS
-new file mode 100644
-index 0000000..3007a4b
---- /dev/null
-+++ b/mech_eap/AUTHORS
-@@ -0,0 +1,6 @@
-+The initial implementation of mech_eap was written by PADL Software
-+under contract to JANET(UK).
-+
-+--
-+Luke Howard <lukeh@padl.com>
-+January, 2011
-diff --git a/mech_eap/COPYING b/mech_eap/COPYING
-new file mode 100644
-index 0000000..7554e77
---- /dev/null
-+++ b/mech_eap/COPYING
-@@ -0,0 +1,3 @@
-+Copyright (c) 2011, JANET(UK)
-+
-+See the LICENSE file for licensing terms.
-diff --git a/mech_eap/LICENSE b/mech_eap/LICENSE
-new file mode 100644
-index 0000000..1b03a95
---- /dev/null
-+++ b/mech_eap/LICENSE
-@@ -0,0 +1,31 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am
-new file mode 100644
-index 0000000..23de6af
---- /dev/null
-+++ b/mech_eap/Makefile.am
-@@ -0,0 +1,189 @@
-+AUTOMAKE_OPTIONS = foreign
-+
-+EXTRA_DIST = gsseap_err.et radsec_err.et \
-+ mech_eap.exports mech_eap-noacceptor.exports radius_ad.exports \
-+ LICENSE AUTHORS
-+
-+
-+gssincludedir = $(includedir)/gssapi
-+gssinclude_HEADERS = gssapi_eap.h
-+
-+EAP_CFLAGS = -I$(srcdir)/../libeap/src -I$(srcdir)/../libeap/src/common -I$(srcdir)/../libeap/src/eap_common \
-+ -I$(srcdir)/../libeap/src/utils
-+
-+if GSSEAP_ENABLE_ACCEPTOR
-+GSSEAP_EXPORTS = mech_eap.exports
-+else
-+GSSEAP_EXPORTS = mech_eap-noacceptor.exports
-+endif
-+
-+gssdir = $(libdir)/gss
-+gss_LTLIBRARIES = mech_eap.la
-+
-+if TARGET_WINDOWS
-+EAP_CFLAGS += -DCONFIG_WIN32_DEFAULTS -DUSE_INTERNAL_CRYPTO
-+OS_LIBS = -lshell32 -ladvapi32 -lws2_32 -lcomerr32
-+mech_eap_la_CFLAGS = -Zi
-+mech_eap_la_CXXFLAGS = -Zi
-+else
-+EAP_CFLAGS += -DEAP_TLS -DEAP_PEAP -DEAP_TTLS -DEAP_MD5 -DEAP_MSCHAPv2 -DEAP_GTC -DEAP_OTP -DEAP_LEAP -DEAP_PSK -DEAP_PAX -DEAP_SAKE -DEAP_GPSK -DEAP_GPSK_SHA256 -DEAP_SERVER_IDENTITY -DEAP_SERVER_TLS -DEAP_SERVER_PEAP -DEAP_SERVER_TTLS -DEAP_SERVER_MD5 -DEAP_SERVER_MSCHAPV2 -DEAP_SERVER_GTC -DEAP_SERVER_PSK -DEAP_SERVER_PAX -DEAP_SERVER_SAKE -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 -DIEEE8021X_EAPOL
-+OS_LIBS =
-+mech_eap_la_CFLAGS = -Werror -Wall -Wunused-parameter
-+mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter
-+endif
-+mech_eap_la_DEPENDENCIES = $(GSSEAP_EXPORTS)
-+
-+mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\"
-+mech_eap_la_CFLAGS += \
-+ @KRB5_CFLAGS@ @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
-+mech_eap_la_CXXFLAGS += \
-+ @KRB5_CFLAGS@ @RADSEC_CFLAGS@ \
-+ @OPENSAML_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ \
-+ @TARGET_CFLAGS@ $(EAP_CFLAGS)
-+mech_eap_la_LDFLAGS = -avoid-version -module \
-+ -export-symbols $(GSSEAP_EXPORTS) -no-undefined \
-+ @KRB5_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
-+if TARGET_WINDOWS
-+mech_eap_la_LDFLAGS += -debug
-+endif
-+
-+mech_eap_la_LIBADD = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \
-+ @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@
-+mech_eap_la_SOURCES = \
-+ acquire_cred.c \
-+ acquire_cred_with_password.c \
-+ add_cred.c \
-+ add_cred_with_password.c \
-+ authorize_localname.c \
-+ canonicalize_name.c \
-+ compare_name.c \
-+ context_time.c \
-+ delete_sec_context.c \
-+ display_name.c \
-+ display_name_ext.c \
-+ display_status.c \
-+ duplicate_name.c \
-+ eap_mech.c \
-+ exchange_meta_data.c \
-+ export_name.c \
-+ export_sec_context.c \
-+ get_mic.c \
-+ gsseap_err.c \
-+ import_name.c \
-+ import_sec_context.c \
-+ indicate_mechs.c \
-+ init_sec_context.c \
-+ inquire_attrs_for_mech.c \
-+ inquire_context.c \
-+ inquire_cred.c \
-+ inquire_cred_by_mech.c \
-+ inquire_cred_by_oid.c \
-+ inquire_mech_for_saslname.c \
-+ inquire_mechs_for_name.c \
-+ inquire_names_for_mech.c \
-+ inquire_saslname_for_mech.c \
-+ inquire_sec_context_by_oid.c \
-+ process_context_token.c \
-+ pseudo_random.c \
-+ query_mechanism_info.c \
-+ query_meta_data.c \
-+ radsec_err.c \
-+ release_cred.c \
-+ release_name.c \
-+ release_oid.c \
-+ set_cred_option.c \
-+ set_sec_context_option.c \
-+ store_cred.c \
-+ unwrap.c \
-+ unwrap_iov.c \
-+ util_buffer.c \
-+ util_context.c \
-+ util_cksum.c \
-+ util_cred.c \
-+ util_crypt.c \
-+ util_krb.c \
-+ util_lucid.c \
-+ util_mech.c \
-+ util_name.c \
-+ util_oid.c \
-+ util_ordering.c \
-+ util_sm.c \
-+ util_tld.c \
-+ util_token.c \
-+ verify_mic.c \
-+ wrap.c \
-+ wrap_iov.c \
-+ wrap_iov_length.c \
-+ wrap_size_limit.c \
-+ gssapiP_eap.h \
-+ util_attr.h \
-+ util_base64.h \
-+ util.h \
-+ util_json.h \
-+ util_radius.h \
-+ util_reauth.h \
-+ util_saml.h \
-+ util_shib.h
-+
-+if LIBMOONSHOT
-+mech_eap_la_SOURCES += util_moonshot.c
-+mech_eap_la_CFLAGS += @LIBMOONSHOT_CFLAGS@
-+mech_eap_la_LDFLAGS += @LIBMOONSHOT_LDFLAGS@
-+mech_eap_la_LIBADD += @LIBMOONSHOT_LIBS@
-+endif
-+
-+
-+if GSSEAP_ENABLE_ACCEPTOR
-+
-+mech_eap_la_SOURCES += \
-+ accept_sec_context.c \
-+ delete_name_attribute.c \
-+ export_name_composite.c \
-+ get_name_attribute.c \
-+ inquire_name.c \
-+ map_name_to_any.c \
-+ release_any_name_mapping.c \
-+ set_name_attribute.c \
-+ util_attr.cpp \
-+ util_base64.c \
-+ util_json.cpp \
-+ util_radius.cpp
-+
-+if OPENSAML
-+mech_eap_la_SOURCES += util_saml.cpp
-+endif
-+
-+if SHIBRESOLVER
-+mech_eap_la_SOURCES += util_shib.cpp
-+endif
-+
-+endif
-+
-+BUILT_SOURCES = gsseap_err.c radsec_err.c gsseap_err.h radsec_err.h
-+
-+if GSSEAP_ENABLE_REAUTH
-+mech_eap_la_SOURCES += util_reauth.c
-+
-+if !HEIMDAL
-+krb5pluginsdir = $(libdir)/krb5/plugins/authdata
-+krb5plugins_LTLIBRARIES = radius_ad.la
-+
-+radius_ad_la_CFLAGS = -Werror -Wall -Wunused-parameter \
-+ @KRB5_CFLAGS@ $(EAP_CFLAGS) @RADSEC_CFLAGS@ @TARGET_CFLAGS@
-+radius_ad_la_LDFLAGS = -avoid-version -module \
-+ -export-symbols radius_ad.exports -no-undefined
-+radius_ad_la_LIBADD = @KRB5_LIBS@
-+radius_ad_la_SOURCES = util_adshim.c authdata_plugin.h
-+endif
-+endif
-+
-+gsseap_err.h gsseap_err.c: gsseap_err.et
-+ $(COMPILE_ET) $<
-+
-+radsec_err.h radsec_err.c: radsec_err.et
-+ $(COMPILE_ET) $<
-+
-+radsec_err.c: radsec_err.h
-+
-+clean-generic:
-+ rm -f gsseap_err.[ch] radsec_err.[ch]
-diff --git a/mech_eap/NEWS b/mech_eap/NEWS
-new file mode 100644
-index 0000000..e69de29
-diff --git a/mech_eap/NOTES b/mech_eap/NOTES
-new file mode 100644
-index 0000000..849ce4e
---- /dev/null
-+++ b/mech_eap/NOTES
-@@ -0,0 +1,9 @@
-+- gss_xxx routines acquire lock, gssXxx don't
-+
-+- git
-+
-+If you do want to update with a rebase, deletethe branch from the
-+server first then push the rebased branch
-+
-+to delete a branch from a server git push origin :branch_to_del
-+
-diff --git a/mech_eap/README b/mech_eap/README
-new file mode 100644
-index 0000000..3cb2d50
---- /dev/null
-+++ b/mech_eap/README
-@@ -0,0 +1,147 @@
-+Overview
-+========
-+
-+This is an implementation of the GSS EAP mechanism, as described in
-+draft-ietf-abfab-gss-eap-01.txt.
-+
-+Building
-+========
-+
-+In order to build this, a recent Kerberos implementation (MIT or
-+Heimdal), Shibboleth, and EAP libraries are required, along with
-+all of their dependencies.
-+
-+Note: not all SPIs are supported by the Heimdal mechanism glue,
-+so not all features will be available.
-+
-+Installing
-+==========
-+
-+GSS mechglue
-+------------
-+
-+When installing, be sure to edit $prefix/etc/gss/mech to register
-+the EAP mechanisms. A sample configuration file is in this directory.
-+You may need to specify an absolute path.
-+
-+RADIUS client library
-+---------------------
-+
-+Make sure your RADIUS library is configured to talk to the server of
-+your choice: see the example radsec.conf in this directory. If you
-+want to use TCP or TLS, you'll need to run radsecproxy in front of
-+your RADIUS server.
-+
-+RADIUS server
-+-------------
-+
-+These instructions apply to FreeRADIUS only, which is downloadable
-+from http://freeradius.org/. After configure, make, install, do the
-+following:
-+
-+On the RADIUS server side, you need to install dictionary.ukerna to
-+$prefix/etc/raddb and include it from the main dictionary file, by
-+adding:
-+
-+ $INCLUDE dictionary.ukerna
-+
-+to $prefix/etc/raddb/dictionary. Make sure these files are world-
-+readable; they weren't in my installation.
-+
-+Edit $prefix/etc/raddb/users to add your test user and password:
-+
-+ bob@PROJECT-MOONSHOT.ORG Cleartext-Password := secret
-+
-+Add an entry for your acceptor to $prefix/etc/raddb/clients.conf:
-+
-+ client somehost {
-+ ipaddr = 127.0.0.1
-+ secret = testing123
-+ require_message_authenticator = yes
-+ }
-+
-+Edit $prefix/etc/raddb/eap.conf and set:
-+
-+ eap {
-+...
-+ default_eap_type = ttls
-+...
-+ tls {
-+ certdir = ...
-+ cadir = ...
-+ private_key_file = ...
-+ certificate_file = ...
-+ }
-+ ttls {
-+ default_eap_type = mschapv2
-+ copy_request_to_tunnel = no
-+ use_tunneled_reply = no
-+ virtual_server = "inner-tunnel"
-+ }
-+...
-+ }
-+
-+to enable EAP-TTLS.
-+
-+If you want the acceptor be able to identify the user, the RADIUS
-+server needs to echo back the EAP username from the inner tunnel;
-+for privacy, mech_eap only sends the realm in the EAP Identity
-+response. To configure this with FreeRADIUS, add:
-+
-+ update outer.reply {
-+ User-Name = "%{request:User-Name}"
-+ }
-+
-+If you want to add a SAML assertion, do this with "update reply"
-+in $prefix/etc/raddb/sites-available/default:
-+
-+ update reply {
-+ SAML-AAA-Assertion = '<saml:Assertion ...'
-+ SAML-AAA-Assertion += '...'
-+ }
-+
-+You'll need to split it into multiple lines because of the RADIUS
-+attribute size limit.
-+
-+Testing
-+=======
-+
-+You can then test the MIT or Cyrus GSS and SASL example programs.
-+Sample usage is given below. Substitute <user>, <pass> and <host>
-+appropriately (<host> is the name of the host running the server,
-+not the RADIUS server).
-+
-+% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" \
-+ -user <user>@<realm> -pass <pass> <host> host@<host> \
-+ "Testing GSS EAP"
-+% gss-server -port 5555 -export host@<host>
-+
-+Note: for SASL you will be prompted for a username and password.
-+
-+% client -C -p 5556 -s host -m EAP-AES128 <host>
-+% server -c -p 5556 -s host -h <host>
-+
-+To test fast reauthentication support, add the following to
-+/etc/krb5.conf:
-+
-+[appdefaults]
-+ eap_gss = {
-+ reauth_use_ccache = TRUE
-+ }
-+
-+This will store a Kerberos ticket for a GSS-EAP authenticated user
-+in a credentials cache, which can then be used for re-authentication
-+to the same acceptor. You must have a valid keytab configured.
-+
-+In this testing phase of Moonshot, it's also possible to store a
-+default identity and credential in a file. The format consists of
-+the string representation of the initiator identity and the password,
-+separated by newlines. The default location of this file is
-+.gss_eap_id in the user's home directory, however the GSSEAP_IDENTITY
-+environment variable can be used to set an alternate location.
-+
-+You can also set a default realm in [appdefaults]; the Kerberos
-+default realm is never used by mech_eap (or at least, that is the
-+intention), so if unspecified you must always qualify names. It should
-+generally not be necessary to specify this.
-+
-diff --git a/mech_eap/README.samba4 b/mech_eap/README.samba4
-new file mode 100644
-index 0000000..d0a94d1
---- /dev/null
-+++ b/mech_eap/README.samba4
-@@ -0,0 +1,52 @@
-+Notes on using Moonshot with Samba4. Replace paths as appropriate.
-+
-+Samba
-+-----
-+
-+* Download Samba4 and apply patches for mechanism agnosticism which are
-+ available at http://www.padl.com/~lukeh/samba/
-+* Join Samba as a member server or domain controller (only tested former)
-+* Extract local service principal key to keytab (currently there do not
-+ appear to be tools to do this, but you can get the cleartext password
-+ from /usr/local/samba/private/secrets.ldb)
-+
-+Shibboleth
-+----------
-+
-+* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
-+ /usr/local/etc/shibboleth/attribute-map.xml:
-+
-+ <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
-+ id="urn:mspac:" binary="true"/>
-+
-+FreeRADIUS
-+----------
-+
-+Install the rlm_mspac module and configure per below.
-+
-+* Install dictionary.ukerna so MS-Windows-Auth-Data is defined
-+* Create /usr/local/etc/raddb/modules/mspac with the following:
-+
-+ mspac {
-+ keytab = /etc/krb5.keytab
-+ spn = host/host.fqdn@KERBEROS.REALM
-+ }
-+
-+* Add mspac to instantiate stanza in radiusd.conf
-+* Add mspac to post-auth stanza in sites-enabled/inner-tunnel
-+
-+You will need to have a TGT for the host service principal before starting
-+radiusd. It's easiest to do this with kinit -k.
-+
-+Testing
-+-------
-+
-+The Samba server doesn't require any specific command line arguments, although
-+on OS X it was necessary to start it with -M single to function under gdb.
-+
-+For the client, the GSS EAP mechanism can be specified on the command line:
-+
-+smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
-+
-+There is no Moonshot SSPI implementation as yet, so it is not possible to test
-+with a Windows client.
-diff --git a/mech_eap/TODO b/mech_eap/TODO
-new file mode 100644
-index 0000000..0111459
---- /dev/null
-+++ b/mech_eap/TODO
-@@ -0,0 +1,6 @@
-+- integration with initiator-side EAP channel bindings
-+- investigate initiator-side credential locking
-+- always intern OIDs so they never need to be freed
-+- handle many-to-many Shibboleth attribute mappings; need to encode both attribute and value index into more
-+- add --with-xerces option
-+- proper acquire_cred_ext implementation pending specification
-diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c
-new file mode 100644
-index 0000000..b089bae
---- /dev/null
-+++ b/mech_eap/accept_sec_context.c
-@@ -0,0 +1,1072 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Establish a security context on the acceptor (server). These functions
-+ * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+static OM_uint32
-+eapGssSmAcceptGssReauth(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target,
-+ gss_OID mech,
-+ OM_uint32 reqFlags,
-+ OM_uint32 timeReq,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags);
-+#endif
-+
-+/*
-+ * Mark an acceptor context as ready for cryptographic operations
-+ */
-+static OM_uint32
-+acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
-+{
-+ OM_uint32 major, tmpMinor;
-+ VALUE_PAIR *vp;
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+
-+ /* Cache encryption type derived from selected mechanism OID */
-+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
-+ &ctx->encryptionType);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
-+
-+ major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
-+ PW_USER_NAME, 0, &vp);
-+ if (major == GSS_S_COMPLETE && vp->length) {
-+ nameBuf.length = vp->length;
-+ nameBuf.value = vp->vp_strvalue;
-+ } else {
-+ ctx->gssFlags |= GSS_C_ANON_FLAG;
-+ }
-+
-+ major = gssEapImportName(minor, &nameBuf,
-+ (ctx->gssFlags & GSS_C_ANON_FLAG) ?
-+ GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
-+ ctx->mechanismUsed,
-+ &ctx->initiatorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
-+ PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
-+ if (GSS_ERROR(major)) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ major = gssEapDeriveRfc3961Key(minor,
-+ vp->vp_octets,
-+ vp->length,
-+ ctx->encryptionType,
-+ &ctx->rfc3961Key);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
-+ &ctx->checksumType);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = sequenceInit(minor,
-+ &ctx->seqState, ctx->recvSeq,
-+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
-+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
-+ TRUE);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapCreateAttrContext(minor, cred, ctx,
-+ &ctx->initiatorName->attrCtx,
-+ &ctx->expiryTime);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (ctx->expiryTime != 0 && ctx->expiryTime < time(NULL)) {
-+ *minor = GSSEAP_CRED_EXPIRED;
-+ return GSS_S_CREDENTIALS_EXPIRED;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+eapGssSmAcceptAcceptorName(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ /* XXX TODO import and validate name from inputToken */
-+
-+ if (ctx->acceptorName != GSS_C_NO_NAME) {
-+ /* Send desired target name to acceptor */
-+ major = gssEapDisplayName(minor, ctx->acceptorName,
-+ outputToken, NULL);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+#ifdef GSSEAP_DEBUG
-+static OM_uint32
-+eapGssSmAcceptVendorInfo(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx GSSEAP_UNUSED,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ fprintf(stderr, "GSS-EAP: vendor: %.*s\n",
-+ (int)inputToken->length, (char *)inputToken->value);
-+
-+ *minor = 0;
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+#endif
-+
-+
-+/*
-+ * Emit a identity EAP request to force the initiator (peer) to identify
-+ * itself.
-+ */
-+static OM_uint32
-+eapGssSmAcceptIdentity(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major;
-+ struct wpabuf *reqData;
-+ gss_buffer_desc pktBuffer;
-+
-+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
-+ *minor = GSSEAP_CRED_MECH_MISMATCH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
-+ *minor = GSSEAP_WRONG_SIZE;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
-+ EAP_CODE_REQUEST, 0);
-+ if (reqData == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ pktBuffer.length = wpabuf_len(reqData);
-+ pktBuffer.value = (void *)wpabuf_head(reqData);
-+
-+ major = duplicateBuffer(minor, &pktBuffer, outputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ wpabuf_free(reqData);
-+
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+
-+ *minor = 0;
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+/*
-+ * Returns TRUE if the input token contains an EAP identity response.
-+ */
-+static int
-+isIdentityResponseP(gss_buffer_t inputToken)
-+{
-+ struct wpabuf respData;
-+
-+ wpabuf_set(&respData, inputToken->value, inputToken->length);
-+
-+ return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
-+}
-+
-+/*
-+ * Save the asserted initiator identity from the EAP identity response.
-+ */
-+static OM_uint32
-+importInitiatorIdentity(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t inputToken)
-+{
-+ OM_uint32 tmpMinor;
-+ struct wpabuf respData;
-+ const unsigned char *pos;
-+ size_t len;
-+ gss_buffer_desc nameBuf;
-+
-+ wpabuf_set(&respData, inputToken->value, inputToken->length);
-+
-+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
-+ &respData, &len);
-+ if (pos == NULL) {
-+ *minor = GSSEAP_PEER_BAD_MESSAGE;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ nameBuf.value = (void *)pos;
-+ nameBuf.length = len;
-+
-+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
-+
-+ return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
-+ ctx->mechanismUsed, &ctx->initiatorName);
-+}
-+
-+/*
-+ * Pass the asserted initiator identity to the authentication server.
-+ */
-+static OM_uint32
-+setInitiatorIdentity(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ VALUE_PAIR **vps)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc nameBuf;
-+
-+ /*
-+ * We should have got an EAP identity response, but if we didn't, then
-+ * we will just avoid sending User-Name. Note that radsecproxy requires
-+ * User-Name to be sent on every request (presumably so it can remain
-+ * stateless).
-+ */
-+ if (ctx->initiatorName != GSS_C_NO_NAME) {
-+ major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ gss_release_buffer(&tmpMinor, &nameBuf);
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * Pass the asserted acceptor identity to the authentication server.
-+ */
-+static OM_uint32
-+setAcceptorIdentity(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ VALUE_PAIR **vps)
-+{
-+ OM_uint32 major;
-+ gss_buffer_desc nameBuf;
-+ krb5_context krbContext = NULL;
-+ krb5_principal krbPrinc;
-+ struct rs_context *rc = ctx->acceptorCtx.radContext;
-+
-+ GSSEAP_ASSERT(rc != NULL);
-+
-+ if (ctx->acceptorName == GSS_C_NO_NAME) {
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
-+ *minor = GSSEAP_BAD_SERVICE_NAME;
-+ return GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ krbPrinc = ctx->acceptorName->krbPrincipal;
-+ GSSEAP_ASSERT(krbPrinc != NULL);
-+ GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 2);
-+
-+ /* Acceptor-Service-Name */
-+ krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
-+
-+ major = gssEapRadiusAddAvp(minor, vps,
-+ PW_GSS_ACCEPTOR_SERVICE_NAME,
-+ VENDORPEC_UKERNA,
-+ &nameBuf);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /* Acceptor-Host-Name */
-+ krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
-+
-+ major = gssEapRadiusAddAvp(minor, vps,
-+ PW_GSS_ACCEPTOR_HOST_NAME,
-+ VENDORPEC_UKERNA,
-+ &nameBuf);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
-+ /* Acceptor-Service-Specific */
-+ krb5_principal_data ssiPrinc = *krbPrinc;
-+ char *ssi;
-+
-+ KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
-+ KRB_PRINC_NAME(&ssiPrinc) += 2;
-+
-+ *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
-+ KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
-+ if (*minor != 0)
-+ return GSS_S_FAILURE;
-+
-+ nameBuf.value = ssi;
-+ nameBuf.length = strlen(ssi);
-+
-+ major = gssEapRadiusAddAvp(minor, vps,
-+ PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
-+ VENDORPEC_UKERNA,
-+ &nameBuf);
-+
-+ if (GSS_ERROR(major)) {
-+ krb5_free_unparsed_name(krbContext, ssi);
-+ return major;
-+ }
-+ krb5_free_unparsed_name(krbContext, ssi);
-+ }
-+
-+ krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
-+ if (nameBuf.length != 0) {
-+ /* Acceptor-Realm-Name */
-+ major = gssEapRadiusAddAvp(minor, vps,
-+ PW_GSS_ACCEPTOR_REALM_NAME,
-+ VENDORPEC_UKERNA,
-+ &nameBuf);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * Allocate a RadSec handle
-+ */
-+static OM_uint32
-+createRadiusHandle(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx)
-+{
-+ struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
-+ struct rs_error *err;
-+ const char *configStanza = "gss-eap";
-+ OM_uint32 major;
-+
-+ GSSEAP_ASSERT(actx->radContext == NULL);
-+ GSSEAP_ASSERT(actx->radConn == NULL);
-+ GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
-+
-+ major = gssEapCreateRadiusContext(minor, cred, &actx->radContext);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (cred->radiusConfigStanza.value != NULL)
-+ configStanza = (const char *)cred->radiusConfigStanza.value;
-+
-+ if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
-+ err = rs_err_conn_pop(actx->radConn);
-+ return gssEapRadiusMapError(minor, err);
-+ }
-+
-+ if (actx->radServer != NULL) {
-+ if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) {
-+ err = rs_err_conn_pop(actx->radConn);
-+ return gssEapRadiusMapError(minor, err);
-+ }
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * Process a EAP response from the initiator.
-+ */
-+static OM_uint32
-+eapGssSmAcceptAuthenticate(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major, tmpMinor;
-+ struct rs_connection *rconn;
-+ struct rs_request *request = NULL;
-+ struct rs_packet *req = NULL, *resp = NULL;
-+ struct radius_packet *frreq, *frresp;
-+
-+ if (ctx->acceptorCtx.radContext == NULL) {
-+ /* May be NULL from an imported partial context */
-+ major = createRadiusHandle(minor, cred, ctx);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (isIdentityResponseP(inputToken)) {
-+ major = importInitiatorIdentity(minor, ctx, inputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ rconn = ctx->acceptorCtx.radConn;
-+
-+ if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) {
-+ major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
-+ goto cleanup;
-+ }
-+ frreq = rs_packet_frpkt(req);
-+
-+ major = setInitiatorIdentity(minor, ctx, &frreq->vps);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = setAcceptorIdentity(minor, ctx, &frreq->vps);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapRadiusAddAvp(minor, &frreq->vps,
-+ PW_EAP_MESSAGE, 0, inputToken);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (ctx->acceptorCtx.state.length != 0) {
-+ major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
-+ &ctx->acceptorCtx.state);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
-+ }
-+
-+ if (rs_request_create(rconn, &request) != 0) {
-+ major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
-+ goto cleanup;
-+ }
-+
-+ rs_request_add_reqpkt(request, req);
-+ req = NULL;
-+
-+ if (rs_request_send(request, &resp) != 0) {
-+ major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
-+ goto cleanup;
-+ }
-+
-+ GSSEAP_ASSERT(resp != NULL);
-+
-+ frresp = rs_packet_frpkt(resp);
-+ switch (frresp->code) {
-+ case PW_ACCESS_CHALLENGE:
-+ case PW_AUTHENTICATION_ACK:
-+ break;
-+ case PW_AUTHENTICATION_REJECT:
-+ *minor = GSSEAP_RADIUS_AUTH_FAILURE;
-+ major = GSS_S_DEFECTIVE_CREDENTIAL;
-+ goto cleanup;
-+ break;
-+ default:
-+ *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ break;
-+ }
-+
-+ major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
-+ outputToken, TRUE);
-+ if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
-+ *minor = GSSEAP_MISSING_EAP_REQUEST;
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ goto cleanup;
-+ } else if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (frresp->code == PW_ACCESS_CHALLENGE) {
-+ major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
-+ &ctx->acceptorCtx.state, TRUE);
-+ if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
-+ goto cleanup;
-+ } else {
-+ ctx->acceptorCtx.vps = frresp->vps;
-+ frresp->vps = NULL;
-+
-+ major = acceptReadyEap(minor, ctx, cred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+ }
-+
-+ major = GSS_S_CONTINUE_NEEDED;
-+ *minor = 0;
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+
-+cleanup:
-+ if (request != NULL)
-+ rs_request_destroy(request);
-+ if (req != NULL)
-+ rs_packet_destroy(req);
-+ if (resp != NULL)
-+ rs_packet_destroy(resp);
-+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) {
-+ GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
-+
-+ rs_conn_destroy(ctx->acceptorCtx.radConn);
-+ ctx->acceptorCtx.radConn = NULL;
-+ }
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+eapGssSmAcceptGssFlags(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ unsigned char *p;
-+ OM_uint32 initiatorGssFlags;
-+
-+ GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
-+
-+ if (inputToken->length < 4) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ /* allow flags to grow for future expansion */
-+ p = (unsigned char *)inputToken->value + inputToken->length - 4;
-+
-+ initiatorGssFlags = load_uint32_be(p);
-+ initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK;
-+
-+ ctx->gssFlags |= initiatorGssFlags;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+static OM_uint32
-+eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+ gss_iov_buffer_desc iov[2];
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-+ iov[0].buffer.length = 0;
-+ iov[0].buffer.value = NULL;
-+
-+ iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
-+
-+ /* XXX necessary because decrypted in place and we verify it later */
-+ major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-+ iov, 2, TOK_TYPE_WRAP);
-+ if (GSS_ERROR(major)) {
-+ gssEapReleaseIov(iov, 2);
-+ return major;
-+ }
-+
-+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
-+ !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
-+ major = GSS_S_BAD_BINDINGS;
-+ *minor = GSSEAP_BINDINGS_MISMATCH;
-+ } else {
-+ major = GSS_S_CONTINUE_NEEDED;
-+ *minor = 0;
-+ }
-+
-+ gssEapReleaseIov(iov, 2);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+
-+ *minor = 0;
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+static OM_uint32
-+eapGssSmAcceptReauthCreds(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ /*
-+ * If we're built with fast reauthentication enabled, then
-+ * fabricate a ticket from the initiator to ourselves.
-+ */
-+ major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
-+ if (major == GSS_S_UNAVAILABLE)
-+ major = GSS_S_COMPLETE;
-+ if (major == GSS_S_COMPLETE)
-+ major = GSS_S_CONTINUE_NEEDED;
-+
-+ return major;
-+}
-+#endif
-+
-+static OM_uint32
-+eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major;
-+
-+ major = gssEapMakeTokenMIC(minor, ctx, outputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
-+
-+ *minor = 0;
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static struct gss_eap_sm eapGssAcceptorSm[] = {
-+ {
-+ ITOK_TYPE_ACCEPTOR_NAME_REQ,
-+ ITOK_TYPE_ACCEPTOR_NAME_RESP,
-+ GSSEAP_STATE_INITIAL,
-+ 0,
-+ eapGssSmAcceptAcceptorName
-+ },
-+#ifdef GSSEAP_DEBUG
-+ {
-+ ITOK_TYPE_VENDOR_INFO,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_INITIAL,
-+ 0,
-+ eapGssSmAcceptVendorInfo,
-+ },
-+#endif
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ {
-+ ITOK_TYPE_REAUTH_REQ,
-+ ITOK_TYPE_REAUTH_RESP,
-+ GSSEAP_STATE_INITIAL,
-+ 0,
-+ eapGssSmAcceptGssReauth,
-+ },
-+#endif
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_EAP_REQ,
-+ GSSEAP_STATE_INITIAL,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmAcceptIdentity,
-+ },
-+ {
-+ ITOK_TYPE_EAP_RESP,
-+ ITOK_TYPE_EAP_REQ,
-+ GSSEAP_STATE_AUTHENTICATE,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmAcceptAuthenticate
-+ },
-+ {
-+ ITOK_TYPE_GSS_FLAGS,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ 0,
-+ eapGssSmAcceptGssFlags
-+ },
-+ {
-+ ITOK_TYPE_GSS_CHANNEL_BINDINGS,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmAcceptGssChannelBindings,
-+ },
-+ {
-+ ITOK_TYPE_INITIATOR_MIC,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmAcceptInitiatorMIC,
-+ },
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_REAUTH_CREDS,
-+ GSSEAP_STATE_ACCEPTOR_EXTS,
-+ 0,
-+ eapGssSmAcceptReauthCreds,
-+ },
-+#endif
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_ACCEPTOR_MIC,
-+ GSSEAP_STATE_ACCEPTOR_EXTS,
-+ 0,
-+ eapGssSmAcceptAcceptorMIC
-+ },
-+};
-+
-+OM_uint32
-+gssEapAcceptSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ 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, tmpMinor;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL) {
-+ if (ctx->cred == GSS_C_NO_CREDENTIAL) {
-+ major = gssEapAcquireCred(minor,
-+ GSS_C_NO_NAME,
-+ GSS_C_INDEFINITE,
-+ GSS_C_NO_OID_SET,
-+ GSS_C_ACCEPT,
-+ &ctx->cred,
-+ NULL,
-+ NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ cred = ctx->cred;
-+ }
-+
-+ /*
-+ * Previously we acquired the credential mutex here, but it should not be
-+ * necessary as the acceptor does not access any mutable elements of the
-+ * credential handle.
-+ */
-+
-+ /*
-+ * Calling gssEapInquireCred() forces the default acceptor credential name
-+ * to be resolved.
-+ */
-+ major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapSmStep(minor,
-+ cred,
-+ ctx,
-+ GSS_C_NO_NAME,
-+ GSS_C_NO_OID,
-+ 0,
-+ GSS_C_INDEFINITE,
-+ input_chan_bindings,
-+ input_token,
-+ output_token,
-+ eapGssAcceptorSm,
-+ sizeof(eapGssAcceptorSm) / sizeof(eapGssAcceptorSm[0]));
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (mech_type != NULL) {
-+ OM_uint32 tmpMajor;
-+
-+ tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, mech_type);
-+ if (GSS_ERROR(tmpMajor)) {
-+ major = tmpMajor;
-+ *minor = tmpMinor;
-+ goto cleanup;
-+ }
-+ }
-+ if (ret_flags != NULL)
-+ *ret_flags = ctx->gssFlags;
-+ if (delegated_cred_handle != NULL)
-+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
-+
-+ if (major == GSS_S_COMPLETE) {
-+ if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
-+ major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+ if (time_rec != NULL) {
-+ major = gssEapContextTime(&tmpMinor, ctx, time_rec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+ }
-+
-+ GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
-+
-+cleanup:
-+ return major;
-+}
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+static OM_uint32
-+acceptReadyKrb(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ const gss_name_t initiator,
-+ const gss_OID mech,
-+ OM_uint32 timeRec)
-+{
-+ OM_uint32 major;
-+
-+ major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+eapGssSmAcceptGssReauth(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_name_t krbInitiator = GSS_C_NO_NAME;
-+ OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
-+
-+ /*
-+ * If we're built with fast reauthentication support, it's valid
-+ * for an initiator to send a GSS reauthentication token as its
-+ * initial context token, causing us to short-circuit the state
-+ * machine and process Kerberos GSS messages instead.
-+ */
-+
-+ ctx->flags |= CTX_FLAG_KRB_REAUTH;
-+
-+ major = gssAcceptSecContext(minor,
-+ &ctx->reauthCtx,
-+ cred->reauthCred,
-+ inputToken,
-+ chanBindings,
-+ &krbInitiator,
-+ &mech,
-+ outputToken,
-+ &gssFlags,
-+ &timeRec,
-+ NULL);
-+ if (major == GSS_S_COMPLETE) {
-+ major = acceptReadyKrb(minor, ctx, cred,
-+ krbInitiator, mech, timeRec);
-+ if (major == GSS_S_COMPLETE) {
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
-+ }
-+ ctx->gssFlags = gssFlags;
-+ } else if (GSS_ERROR(major) &&
-+ (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) {
-+ /* pretend reauthentication attempt never happened */
-+ gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
-+ ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
-+ major = GSS_S_CONTINUE_NEEDED;
-+ }
-+
-+ gssReleaseName(&tmpMinor, &krbInitiator);
-+
-+ return major;
-+}
-+#endif /* GSSEAP_ENABLE_REAUTH */
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_accept_sec_context(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_cred_id_t cred,
-+ 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, tmpMinor;
-+ gss_ctx_id_t ctx = *context_handle;
-+
-+ *minor = 0;
-+
-+ output_token->length = 0;
-+ output_token->value = NULL;
-+
-+ if (src_name != NULL)
-+ *src_name = GSS_C_NO_NAME;
-+
-+ if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ major = gssEapAllocContext(minor, &ctx);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ *context_handle = ctx;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapAcceptSecContext(minor,
-+ ctx,
-+ cred,
-+ input_token,
-+ input_chan_bindings,
-+ src_name,
-+ mech_type,
-+ output_token,
-+ ret_flags,
-+ time_rec,
-+ delegated_cred_handle);
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ if (GSS_ERROR(major))
-+ gssEapReleaseContext(&tmpMinor, context_handle);
-+
-+ return major;
-+}
-diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c
-new file mode 100644
-index 0000000..ae2648e
---- /dev/null
-+++ b/mech_eap/acquire_cred.c
-@@ -0,0 +1,52 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for acquiring a credential handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_acquire_cred(OM_uint32 *minor,
-+ 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 gssEapAcquireCred(minor, desired_name,
-+ time_req, desired_mechs, cred_usage,
-+ output_cred_handle, actual_mechs, time_rec);
-+}
-diff --git a/mech_eap/acquire_cred_with_password.c b/mech_eap/acquire_cred_with_password.c
-new file mode 100644
-index 0000000..8e08358
---- /dev/null
-+++ b/mech_eap/acquire_cred_with_password.c
-@@ -0,0 +1,67 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for acquiring a credential handle using a password.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gssspi_acquire_cred_with_password(OM_uint32 *minor,
-+ 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 major, tmpMinor;
-+
-+ major = gssEapAcquireCred(minor, desired_name,
-+ time_req, desired_mechs, cred_usage,
-+ output_cred_handle, actual_mechs, time_rec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapSetCredPassword(minor, *output_cred_handle, password);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gssEapReleaseCred(&tmpMinor, output_cred_handle);
-+
-+ return major;
-+}
-diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c
-new file mode 100644
-index 0000000..64d97c0
---- /dev/null
-+++ b/mech_eap/add_cred.c
-@@ -0,0 +1,87 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for acquiring a credential handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/*
-+ * Note that this shouldn't really be required to be implemented by anything
-+ * apart from the mechanism glue layer. However, Heimdal does call into the
-+ * mechanism here.
-+ */
-+OM_uint32 GSSAPI_CALLCONV
-+gss_add_cred(OM_uint32 *minor,
-+ gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
-+ 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 major;
-+ OM_uint32 time_req, time_rec = 0;
-+ gss_OID_set_desc mechs;
-+
-+ *minor = 0;
-+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
-+
-+ if (cred_usage == GSS_C_ACCEPT)
-+ time_req = acceptor_time_req;
-+ else
-+ time_req = initiator_time_req;
-+
-+ mechs.count = 1;
-+ mechs.elements = desired_mech;
-+
-+ major = gssEapAcquireCred(minor,
-+ desired_name,
-+ time_req,
-+ &mechs,
-+ cred_usage,
-+ output_cred_handle,
-+ actual_mechs,
-+ &time_rec);
-+
-+ if (initiator_time_rec != NULL)
-+ *initiator_time_rec = time_rec;
-+ if (acceptor_time_rec != NULL)
-+ *acceptor_time_rec = time_rec;
-+
-+ return major;
-+}
-diff --git a/mech_eap/add_cred_with_password.c b/mech_eap/add_cred_with_password.c
-new file mode 100644
-index 0000000..b982f0d
---- /dev/null
-+++ b/mech_eap/add_cred_with_password.c
-@@ -0,0 +1,93 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for acquiring a credential handle using a password.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_add_cred_with_password(OM_uint32 *minor,
-+ const gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
-+ 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 major, tmpMinor;
-+ OM_uint32 time_req, time_rec = 0;
-+ gss_OID_set_desc mechs;
-+
-+ *minor = 0;
-+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
-+
-+ if (cred_usage == GSS_C_ACCEPT)
-+ time_req = acceptor_time_req;
-+ else
-+ time_req = initiator_time_req;
-+
-+ mechs.count = 1;
-+ mechs.elements = desired_mech;
-+
-+ major = gssEapAcquireCred(minor,
-+ desired_name,
-+ time_req,
-+ &mechs,
-+ cred_usage,
-+ output_cred_handle,
-+ actual_mechs,
-+ &time_rec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapSetCredPassword(minor, *output_cred_handle, password);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (initiator_time_rec != NULL)
-+ *initiator_time_rec = time_rec;
-+ if (acceptor_time_rec != NULL)
-+ *acceptor_time_rec = time_rec;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gssEapReleaseCred(&tmpMinor, output_cred_handle);
-+
-+ return major;
-+}
-diff --git a/mech_eap/authdata_plugin.h b/mech_eap/authdata_plugin.h
-new file mode 100644
-index 0000000..32bff2f
---- /dev/null
-+++ b/mech_eap/authdata_plugin.h
-@@ -0,0 +1,331 @@
-+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-+/*
-+ * krb5/authdata_plugin.h
-+ *
-+ * Copyright (C) 2007 Apple 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 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.
-+ *
-+ * AuthorizationData plugin definitions for Kerberos 5.
-+ */
-+
-+/*
-+ * This is considered an INTERNAL interface at this time.
-+ *
-+ * Some work is needed before exporting it:
-+ *
-+ * + Documentation.
-+ * + Sample code.
-+ * + Test cases (preferably automated testing under "make check").
-+ * + Hook into TGS exchange too; will change API.
-+ * + Examine memory management issues, especially for Windows; may
-+ * change API.
-+ *
-+ * Other changes that would be nice to have, but not necessarily
-+ * before making this interface public:
-+ *
-+ * + Library support for AD-IF-RELEVANT and similar wrappers. (We can
-+ * make the plugin construct them if it wants them.)
-+ * + KDC could combine/optimize wrapped AD elements provided by
-+ * multiple plugins, e.g., two IF-RELEVANT sequences could be
-+ * merged. (The preauth plugin API also has this bug, we're going
-+ * to need a general fix.)
-+ */
-+
-+#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
-+#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
-+#include <krb5/krb5.h>
-+
-+/*
-+ * While arguments of these types are passed-in, for the most part a
-+ * authorization data module can treat them as opaque. If we need
-+ * keying data, we can ask for it directly.
-+ */
-+struct _krb5_db_entry_new;
-+
-+/*
-+ * The function table / structure which an authdata server module must export as
-+ * "authdata_server_0". NOTE: replace "0" with "1" for the type and
-+ * variable names if this gets picked up by upstream. If the interfaces work
-+ * correctly, future versions of the table will add either more callbacks or
-+ * more arguments to callbacks, and in both cases we'll be able to wrap the v0
-+ * functions.
-+ */
-+/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
-+typedef struct krb5plugin_authdata_server_ftable_v0 {
-+ /* Not-usually-visible name. */
-+ char *name;
-+
-+ /*
-+ * Per-plugin initialization/cleanup. The init function is called
-+ * by the KDC when the plugin is loaded, and the fini function is
-+ * called before the plugin is unloaded. Both are optional.
-+ */
-+ krb5_error_code (*init_proc)(krb5_context, void **);
-+ void (*fini_proc)(krb5_context, void *);
-+ /*
-+ * Actual authorization data handling function. If this field
-+ * holds a null pointer, this mechanism will be skipped, and the
-+ * init/fini functions will not be run.
-+ *
-+ * This function should only modify the field
-+ * enc_tkt_reply->authorization_data. All other values should be
-+ * considered inputs only. And, it should *modify* the field, not
-+ * overwrite it and assume that there are no other authdata
-+ * plugins in use.
-+ *
-+ * Memory management: authorization_data is a malloc-allocated,
-+ * null-terminated sequence of malloc-allocated pointers to
-+ * authorization data structures. This plugin code currently
-+ * assumes the libraries, KDC, and plugin all use the same malloc
-+ * pool, which may be a problem if/when we get the KDC code
-+ * running on Windows.
-+ *
-+ * If this function returns a non-zero error code, a message
-+ * is logged, but no other action is taken. Other authdata
-+ * plugins will be called, and a response will be sent to the
-+ * client (barring other problems).
-+ */
-+ krb5_error_code (*authdata_proc)(krb5_context,
-+ struct _krb5_db_entry_new *client,
-+ krb5_data *req_pkt,
-+ krb5_kdc_req *request,
-+ krb5_enc_tkt_part *enc_tkt_reply);
-+} krb5plugin_server_authdata_ftable_v0;
-+
-+typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0;
-+
-+typedef struct krb5plugin_authdata_server_ftable_v2 {
-+ /* Not-usually-visible name. */
-+ char *name;
-+
-+ /*
-+ * Per-plugin initialization/cleanup. The init function is called
-+ * by the KDC when the plugin is loaded, and the fini function is
-+ * called before the plugin is unloaded. Both are optional.
-+ */
-+ krb5_error_code (*init_proc)(krb5_context, void **);
-+ void (*fini_proc)(krb5_context, void *);
-+ /*
-+ * Actual authorization data handling function. If this field
-+ * holds a null pointer, this mechanism will be skipped, and the
-+ * init/fini functions will not be run.
-+ *
-+ * This function should only modify the field
-+ * enc_tkt_reply->authorization_data. All other values should be
-+ * considered inputs only. And, it should *modify* the field, not
-+ * overwrite it and assume that there are no other authdata
-+ * plugins in use.
-+ *
-+ * Memory management: authorization_data is a malloc-allocated,
-+ * null-terminated sequence of malloc-allocated pointers to
-+ * authorization data structures. This plugin code currently
-+ * assumes the libraries, KDC, and plugin all use the same malloc
-+ * pool, which may be a problem if/when we get the KDC code
-+ * running on Windows.
-+ *
-+ * If this function returns a non-zero error code, a message
-+ * is logged, but no other action is taken. Other authdata
-+ * plugins will be called, and a response will be sent to the
-+ * client (barring other problems).
-+ */
-+ krb5_error_code (*authdata_proc)(krb5_context,
-+ unsigned int flags,
-+ struct _krb5_db_entry_new *client,
-+ struct _krb5_db_entry_new *server,
-+ struct _krb5_db_entry_new *tgs,
-+ krb5_keyblock *client_key,
-+ krb5_keyblock *server_key,
-+ krb5_keyblock *tgs_key,
-+ krb5_data *req_pkt,
-+ krb5_kdc_req *request,
-+ krb5_const_principal for_user_princ,
-+ krb5_enc_tkt_part *enc_tkt_request,
-+ krb5_enc_tkt_part *enc_tkt_reply);
-+} krb5plugin_authdata_server_ftable_v2;
-+
-+typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2;
-+
-+typedef krb5_error_code
-+(*authdata_client_plugin_init_proc)(krb5_context context,
-+ void **plugin_context);
-+
-+#define AD_USAGE_AS_REQ 0x01
-+#define AD_USAGE_TGS_REQ 0x02
-+#define AD_USAGE_AP_REQ 0x04
-+#define AD_USAGE_KDC_ISSUED 0x08
-+#define AD_USAGE_MASK 0x0F
-+#define AD_INFORMATIONAL 0x10
-+
-+struct _krb5_authdata_context;
-+
-+typedef void
-+(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
-+ void *plugin_context,
-+ krb5_authdatatype ad_type,
-+ krb5_flags *flags);
-+
-+typedef void
-+(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
-+ void *plugin_context);
-+
-+typedef krb5_error_code
-+(*authdata_client_request_init_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void **request_context);
-+
-+typedef void
-+(*authdata_client_request_fini_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context);
-+
-+typedef krb5_error_code
-+(*authdata_client_import_authdata_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_authdata **authdata,
-+ krb5_boolean kdc_issued_flag,
-+ krb5_const_principal issuer);
-+
-+typedef krb5_error_code
-+(*authdata_client_export_authdata_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_flags usage,
-+ krb5_authdata ***authdata);
-+
-+typedef krb5_error_code
-+(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_data **attrs);
-+
-+typedef krb5_error_code
-+(*authdata_client_get_attribute_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ const krb5_data *attribute,
-+ krb5_boolean *authenticated,
-+ krb5_boolean *complete,
-+ krb5_data *value,
-+ krb5_data *display_value,
-+ int *more);
-+
-+typedef krb5_error_code
-+(*authdata_client_set_attribute_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_boolean complete,
-+ const krb5_data *attribute,
-+ const krb5_data *value);
-+
-+typedef krb5_error_code
-+(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ const krb5_data *attribute);
-+
-+typedef krb5_error_code
-+(*authdata_client_export_internal_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_boolean restrict_authenticated,
-+ void **ptr);
-+
-+typedef void
-+(*authdata_client_free_internal_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ void *ptr);
-+
-+typedef krb5_error_code
-+(*authdata_client_verify_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ const krb5_auth_context *auth_context,
-+ const krb5_keyblock *key,
-+ const krb5_ap_req *req);
-+
-+typedef krb5_error_code
-+(*authdata_client_size_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ size_t *sizep);
-+
-+typedef krb5_error_code
-+(*authdata_client_externalize_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_octet **buffer,
-+ size_t *lenremain);
-+
-+typedef krb5_error_code
-+(*authdata_client_internalize_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ krb5_octet **buffer,
-+ size_t *lenremain);
-+
-+typedef krb5_error_code
-+(*authdata_client_copy_proc)(krb5_context kcontext,
-+ struct _krb5_authdata_context *context,
-+ void *plugin_context,
-+ void *request_context,
-+ void *dst_plugin_context,
-+ void *dst_request_context);
-+
-+typedef struct krb5plugin_authdata_client_ftable_v0 {
-+ char *name;
-+ krb5_authdatatype *ad_type_list;
-+ authdata_client_plugin_init_proc init;
-+ authdata_client_plugin_fini_proc fini;
-+ authdata_client_plugin_flags_proc flags;
-+ authdata_client_request_init_proc request_init;
-+ authdata_client_request_fini_proc request_fini;
-+ authdata_client_get_attribute_types_proc get_attribute_types;
-+ authdata_client_get_attribute_proc get_attribute;
-+ authdata_client_set_attribute_proc set_attribute;
-+ authdata_client_delete_attribute_proc delete_attribute;
-+ authdata_client_export_authdata_proc export_authdata;
-+ authdata_client_import_authdata_proc import_authdata;
-+ authdata_client_export_internal_proc export_internal;
-+ authdata_client_free_internal_proc free_internal;
-+ authdata_client_verify_proc verify;
-+ authdata_client_size_proc size;
-+ authdata_client_externalize_proc externalize;
-+ authdata_client_internalize_proc internalize;
-+ authdata_client_copy_proc copy; /* optional */
-+} krb5plugin_authdata_client_ftable_v0;
-+
-+#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
-diff --git a/mech_eap/authorize_localname.c b/mech_eap/authorize_localname.c
-new file mode 100644
-index 0000000..0037e2b
---- /dev/null
-+++ b/mech_eap/authorize_localname.c
-@@ -0,0 +1,54 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Local authorization services.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gssspi_authorize_localname(OM_uint32 *minor,
-+ const gss_name_t name GSSEAP_UNUSED,
-+ gss_const_buffer_t local_user GSSEAP_UNUSED,
-+ gss_const_OID local_nametype GSSEAP_UNUSED)
-+{
-+ /*
-+ * The MIT mechglue will fallback to comparing names in the absence
-+ * of a mechanism implementation of gss_userok. To avoid this and
-+ * force the mechglue to use attribute-based authorization, always
-+ * return access denied here.
-+ */
-+
-+ *minor = 0;
-+ return GSS_S_UNAUTHORIZED;
-+}
-diff --git a/mech_eap/canonicalize_name.c b/mech_eap/canonicalize_name.c
-new file mode 100644
-index 0000000..5e66798
---- /dev/null
-+++ b/mech_eap/canonicalize_name.c
-@@ -0,0 +1,64 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Function for canonicalizing a name; presently just duplicates it.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_canonicalize_name(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ const gss_OID mech_type,
-+ gss_name_t *output_name)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (!gssEapIsMechanismOid(mech_type))
-+ return GSS_S_BAD_MECH;
-+
-+ if (input_name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
-+
-+ major = gssEapCanonicalizeName(minor, input_name, mech_type, output_name);
-+
-+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/compare_name.c b/mech_eap/compare_name.c
-new file mode 100644
-index 0000000..edadf3e
---- /dev/null
-+++ b/mech_eap/compare_name.c
-@@ -0,0 +1,46 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Compare two names.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_compare_name(OM_uint32 *minor,
-+ gss_name_t name1,
-+ gss_name_t name2,
-+ int *name_equal)
-+{
-+ return gssEapCompareName(minor, name1, name2, name_equal);
-+}
-diff --git a/mech_eap/context_time.c b/mech_eap/context_time.c
-new file mode 100644
-index 0000000..ae47d6c
---- /dev/null
-+++ b/mech_eap/context_time.c
-@@ -0,0 +1,69 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Determine remaining lifetime of a context handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_context_time(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ OM_uint32 *time_rec)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ major = GSS_S_NO_CONTEXT;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapContextTime(minor, ctx, time_rec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/delete_name_attribute.c b/mech_eap/delete_name_attribute.c
-new file mode 100644
-index 0000000..fe0ff8f
---- /dev/null
-+++ b/mech_eap/delete_name_attribute.c
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for removing a name attribute.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_delete_name_attribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t attr)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapDeleteNameAttribute(minor, name, attr);
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/delete_sec_context.c b/mech_eap/delete_sec_context.c
-new file mode 100644
-index 0000000..7913e45
---- /dev/null
-+++ b/mech_eap/delete_sec_context.c
-@@ -0,0 +1,81 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Release a context handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_delete_sec_context(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_buffer_t output_token)
-+{
-+ OM_uint32 major;
-+ gss_ctx_id_t ctx = *context_handle;
-+
-+ *minor = 0;
-+
-+ if (output_token != GSS_C_NO_BUFFER) {
-+ output_token->length = 0;
-+ output_token->value = NULL;
-+ }
-+
-+ if (ctx == GSS_C_NO_CONTEXT)
-+ return GSS_S_COMPLETE;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (output_token != GSS_C_NO_BUFFER) {
-+ gss_iov_buffer_desc iov[2];
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[0].buffer.value = NULL;
-+ iov[0].buffer.length = 0;
-+
-+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-+ iov[1].buffer.value = NULL;
-+ iov[1].buffer.length = 0;
-+
-+ major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
-+ iov, 2, TOK_TYPE_DELETE_CONTEXT);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ return major;
-+ }
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return gssEapReleaseContext(minor, context_handle);
-+}
-diff --git a/mech_eap/dictionary.ukerna b/mech_eap/dictionary.ukerna
-new file mode 100644
-index 0000000..0e35d43
---- /dev/null
-+++ b/mech_eap/dictionary.ukerna
-@@ -0,0 +1,20 @@
-+# -*- text -*-
-+#
-+# GSS-EAP VSAs
-+#
-+# $Id$
-+#
-+
-+VENDOR UKERNA 25622
-+
-+BEGIN-VENDOR UKERNA
-+
-+ATTRIBUTE GSS-Acceptor-Service-Name 128 string
-+ATTRIBUTE GSS-Acceptor-Host-Name 129 string
-+ATTRIBUTE GSS-Acceptor-Service-Specific 130 string
-+ATTRIBUTE GSS-Acceptor-Realm-Name 131 string
-+ATTRIBUTE SAML-AAA-Assertion 132 string
-+ATTRIBUTE MS-Windows-Auth-Data 133 octets
-+ATTRIBUTE MS-Windows-Group-Sid 134 string
-+
-+END-VENDOR UKERNA
-diff --git a/mech_eap/display_name.c b/mech_eap/display_name.c
-new file mode 100644
-index 0000000..2d87e66
---- /dev/null
-+++ b/mech_eap/display_name.c
-@@ -0,0 +1,48 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Wrapper for "displaying" (returning string representation of) a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_display_name(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t output_name_buffer,
-+ gss_OID *output_name_type)
-+{
-+ /* Lock not required as long as attributes are not used */
-+ return gssEapDisplayName(minor, name, output_name_buffer,
-+ output_name_type);
-+}
-diff --git a/mech_eap/display_name_ext.c b/mech_eap/display_name_ext.c
-new file mode 100644
-index 0000000..d6791d4
---- /dev/null
-+++ b/mech_eap/display_name_ext.c
-@@ -0,0 +1,51 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Parameterized version of gss_display_name(), currently unimplemented.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_display_name_ext(OM_uint32 *minor,
-+ gss_name_t name GSSEAP_UNUSED,
-+ gss_OID display_as_name_type GSSEAP_UNUSED,
-+ gss_buffer_t display_name)
-+{
-+ *minor = 0;
-+
-+ display_name->length = 0;
-+ display_name->value = NULL;
-+
-+ return GSS_S_UNAVAILABLE;
-+}
-diff --git a/mech_eap/display_status.c b/mech_eap/display_status.c
-new file mode 100644
-index 0000000..fc0d1ab
---- /dev/null
-+++ b/mech_eap/display_status.c
-@@ -0,0 +1,203 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Function for converting mechanism error codes to strings.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+struct gss_eap_status_info {
-+ OM_uint32 code;
-+ char *message;
-+ struct gss_eap_status_info *next;
-+};
-+
-+void
-+gssEapDestroyStatusInfo(struct gss_eap_status_info *p)
-+{
-+ struct gss_eap_status_info *next;
-+
-+ for (; p != NULL; p = next) {
-+ next = p->next;
-+ GSSEAP_FREE(p->message);
-+ GSSEAP_FREE(p);
-+ }
-+}
-+
-+/*
-+ * Associate a message with a mechanism (minor) status code. This function
-+ * takes ownership of the message regardless of success. The message must
-+ * be explicitly cleared, if required, so it is suggested that a specific
-+ * minor code is either always or never associated with a message, to avoid
-+ * dangling (and potentially confusing) error messages.
-+ */
-+static void
-+saveStatusInfoNoCopy(OM_uint32 minor, char *message)
-+{
-+ struct gss_eap_status_info **next = NULL, *p = NULL;
-+ struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
-+
-+ if (tld != NULL) {
-+ for (p = tld->statusInfo; p != NULL; p = p->next) {
-+ if (p->code == minor) {
-+ /* Set message in-place */
-+ if (p->message != NULL)
-+ GSSEAP_FREE(p->message);
-+ p->message = message;
-+ return;
-+ }
-+ next = &p->next;
-+ }
-+ p = GSSEAP_CALLOC(1, sizeof(*p));
-+ }
-+
-+ if (p == NULL) {
-+ if (message != NULL)
-+ GSSEAP_FREE(message);
-+ return;
-+ }
-+
-+ p->code = minor;
-+ p->message = message;
-+
-+ if (next != NULL)
-+ *next = p;
-+ else
-+ tld->statusInfo = p;
-+}
-+
-+static const char *
-+getStatusInfo(OM_uint32 minor)
-+{
-+ struct gss_eap_status_info *p;
-+ struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
-+
-+ if (tld != NULL) {
-+ for (p = tld->statusInfo; p != NULL; p = p->next) {
-+ if (p->code == minor)
-+ return p->message;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+void
-+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
-+{
-+#ifdef WIN32
-+ OM_uint32 tmpMajor, tmpMinor;
-+ char buf[BUFSIZ];
-+ gss_buffer_desc s = GSS_C_EMPTY_BUFFER;
-+ va_list ap;
-+
-+ if (format != NULL) {
-+ va_start(ap, format);
-+ snprintf(buf, sizeof(buf), format, ap);
-+ va_end(ap);
-+ }
-+
-+ tmpMajor = makeStringBuffer(&tmpMinor, buf, &s);
-+ if (!GSS_ERROR(tmpMajor))
-+ saveStatusInfoNoCopy(minor, (char *)s.value);
-+#else
-+ char *s = NULL;
-+ int n;
-+ va_list ap;
-+
-+ if (format != NULL) {
-+ va_start(ap, format);
-+ n = vasprintf(&s, format, ap);
-+ if (n == -1)
-+ s = NULL;
-+ va_end(ap);
-+ }
-+
-+ saveStatusInfoNoCopy(minor, s);
-+#endif /* WIN32 */
-+}
-+
-+OM_uint32
-+gssEapDisplayStatus(OM_uint32 *minor,
-+ OM_uint32 status_value,
-+ gss_buffer_t status_string)
-+{
-+ OM_uint32 major;
-+ krb5_context krbContext = NULL;
-+ const char *errMsg;
-+
-+ status_string->length = 0;
-+ status_string->value = NULL;
-+
-+ errMsg = getStatusInfo(status_value);
-+ if (errMsg == NULL) {
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ /* Try the com_err message */
-+ errMsg = krb5_get_error_message(krbContext, status_value);
-+ }
-+
-+ if (errMsg != NULL) {
-+ major = makeStringBuffer(minor, errMsg, status_string);
-+ } else {
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+ }
-+
-+ if (krbContext != NULL)
-+ krb5_free_error_message(krbContext, errMsg);
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_display_status(OM_uint32 *minor,
-+ OM_uint32 status_value,
-+ int status_type,
-+ gss_OID mech_type,
-+ OM_uint32 *message_context,
-+ gss_buffer_t status_string)
-+{
-+ if (!gssEapIsMechanismOid(mech_type)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (status_type != GSS_C_MECH_CODE ||
-+ *message_context != 0) {
-+ /* we rely on the mechglue for GSS_C_GSS_CODE */
-+ *minor = 0;
-+ return GSS_S_BAD_STATUS;
-+ }
-+
-+ return gssEapDisplayStatus(minor, status_value, status_string);
-+}
-diff --git a/mech_eap/duplicate_name.c b/mech_eap/duplicate_name.c
-new file mode 100644
-index 0000000..303619e
---- /dev/null
-+++ b/mech_eap/duplicate_name.c
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Duplicate a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_duplicate_name(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ gss_name_t *dest_name)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (input_name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
-+
-+ major = gssEapDuplicateName(minor, input_name, dest_name);
-+
-+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/eap_mech.c b/mech_eap/eap_mech.c
-new file mode 100644
-index 0000000..96e00c2
---- /dev/null
-+++ b/mech_eap/eap_mech.c
-@@ -0,0 +1,219 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Initialisation and finalise functions.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static OM_uint32
-+eapPeerRegisterMethods(OM_uint32 *minor)
-+{
-+ OM_uint32 ret = 0;
-+
-+#ifdef EAP_MD5
-+ if (ret == 0)
-+ ret = eap_peer_md5_register();
-+#endif /* EAP_MD5 */
-+
-+#ifdef EAP_TLS
-+ if (ret == 0)
-+ ret = eap_peer_tls_register();
-+#endif /* EAP_TLS */
-+
-+#ifdef EAP_MSCHAPv2
-+ if (ret == 0)
-+ ret = eap_peer_mschapv2_register();
-+#endif /* EAP_MSCHAPv2 */
-+
-+#ifdef EAP_PEAP
-+ if (ret == 0)
-+ ret = eap_peer_peap_register();
-+#endif /* EAP_PEAP */
-+
-+#ifdef EAP_TTLS
-+ if (ret == 0)
-+ ret = eap_peer_ttls_register();
-+#endif /* EAP_TTLS */
-+
-+#ifdef EAP_GTC
-+ if (ret == 0)
-+ ret = eap_peer_gtc_register();
-+#endif /* EAP_GTC */
-+
-+#ifdef EAP_OTP
-+ if (ret == 0)
-+ ret = eap_peer_otp_register();
-+#endif /* EAP_OTP */
-+
-+#ifdef EAP_SIM
-+ if (ret == 0)
-+ ret = eap_peer_sim_register();
-+#endif /* EAP_SIM */
-+
-+#ifdef EAP_LEAP
-+ if (ret == 0)
-+ ret = eap_peer_leap_register();
-+#endif /* EAP_LEAP */
-+
-+#ifdef EAP_PSK
-+ if (ret == 0)
-+ ret = eap_peer_psk_register();
-+#endif /* EAP_PSK */
-+
-+#ifdef EAP_AKA
-+ if (ret == 0)
-+ ret = eap_peer_aka_register();
-+#endif /* EAP_AKA */
-+
-+#ifdef EAP_AKA_PRIME
-+ if (ret == 0)
-+ ret = eap_peer_aka_prime_register();
-+#endif /* EAP_AKA_PRIME */
-+
-+#ifdef EAP_FAST
-+ if (ret == 0)
-+ ret = eap_peer_fast_register();
-+#endif /* EAP_FAST */
-+
-+#ifdef EAP_PAX
-+ if (ret == 0)
-+ ret = eap_peer_pax_register();
-+#endif /* EAP_PAX */
-+
-+#ifdef EAP_SAKE
-+ if (ret == 0)
-+ ret = eap_peer_sake_register();
-+#endif /* EAP_SAKE */
-+
-+#ifdef EAP_GPSK
-+ if (ret == 0)
-+ ret = eap_peer_gpsk_register();
-+#endif /* EAP_GPSK */
-+
-+#ifdef EAP_WSC
-+ if (ret == 0)
-+ ret = eap_peer_wsc_register();
-+#endif /* EAP_WSC */
-+
-+#ifdef EAP_IKEV2
-+ if (ret == 0)
-+ ret = eap_peer_ikev2_register();
-+#endif /* EAP_IKEV2 */
-+
-+#ifdef EAP_VENDOR_TEST
-+ if (ret == 0)
-+ ret = eap_peer_vendor_test_register();
-+#endif /* EAP_VENDOR_TEST */
-+
-+#ifdef EAP_TNC
-+ if (ret == 0)
-+ ret = eap_peer_tnc_register();
-+#endif /* EAP_TNC */
-+
-+ if (ret == 0)
-+ return GSS_S_COMPLETE;
-+
-+ *minor = GSSEAP_LIBEAP_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+}
-+
-+static OM_uint32
-+gssEapInitLibEap(OM_uint32 *minor)
-+{
-+ return eapPeerRegisterMethods(minor);
-+}
-+
-+static OM_uint32
-+gssEapInitLibRadsec(OM_uint32 *minor)
-+{
-+ if (0) {
-+ *minor = GSSEAP_RADSEC_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+void gssEapFinalize(void) GSSEAP_DESTRUCTOR;
-+
-+OM_uint32
-+gssEapInitiatorInit(OM_uint32 *minor)
-+{
-+ OM_uint32 major;
-+
-+ initialize_eapg_error_table();
-+ initialize_rse_error_table();
-+
-+ major = gssEapInitLibEap(minor);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gssEapInitLibRadsec(minor);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ major = gssEapReauthInitialize(minor);
-+ if (GSS_ERROR(major))
-+ return major;
-+#endif
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+void
-+gssEapFinalize(void)
-+{
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ OM_uint32 minor;
-+
-+ gssEapAttrProvidersFinalize(&minor);
-+#endif
-+ eap_peer_unregister_methods();
-+}
-+
-+#ifdef GSSEAP_CONSTRUCTOR
-+static void gssEapInitiatorInitAssert(void) GSSEAP_CONSTRUCTOR;
-+
-+static void
-+gssEapInitiatorInitAssert(void)
-+{
-+ OM_uint32 major, minor;
-+
-+ major = gssEapInitiatorInit(&minor);
-+
-+ GSSEAP_ASSERT(!GSS_ERROR(major));
-+}
-+#endif
-diff --git a/mech_eap/exchange_meta_data.c b/mech_eap/exchange_meta_data.c
-new file mode 100644
-index 0000000..5d56795
---- /dev/null
-+++ b/mech_eap/exchange_meta_data.c
-@@ -0,0 +1,82 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gssEapExchangeMetaData(OM_uint32 *minor,
-+ gss_const_OID mech GSSEAP_UNUSED,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t *ctx GSSEAP_UNUSED,
-+ const gss_name_t name GSSEAP_UNUSED,
-+ OM_uint32 req_flags GSSEAP_UNUSED,
-+ gss_const_buffer_t meta_data GSSEAP_UNUSED)
-+{
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_exchange_meta_data(OM_uint32 *minor,
-+ gss_const_OID mech,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t *context_handle,
-+ const gss_name_t name,
-+ OM_uint32 req_flags,
-+ gss_const_buffer_t meta_data)
-+{
-+ gss_ctx_id_t ctx = *context_handle;
-+ OM_uint32 major;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ if (*context_handle != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapExchangeMetaData(minor, mech, cred, &ctx,
-+ name, req_flags, meta_data);
-+
-+ if (*context_handle != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ else
-+ *context_handle = ctx;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/export_name.c b/mech_eap/export_name.c
-new file mode 100644
-index 0000000..d91033f
---- /dev/null
-+++ b/mech_eap/export_name.c
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Serialise a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_export_name(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ gss_buffer_t exported_name)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (input_name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
-+
-+ major = gssEapExportName(minor, input_name, exported_name);
-+
-+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/export_name_composite.c b/mech_eap/export_name_composite.c
-new file mode 100644
-index 0000000..b2a90ae
---- /dev/null
-+++ b/mech_eap/export_name_composite.c
-@@ -0,0 +1,62 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Serialise a name and its attributes.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_export_name_composite(OM_uint32 *minor,
-+ gss_name_t input_name,
-+ gss_buffer_t exported_name)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (input_name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
-+
-+ major = gssEapExportNameInternal(minor, input_name, exported_name,
-+ EXPORT_NAME_FLAG_OID |
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+
-+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/export_sec_context.c b/mech_eap/export_sec_context.c
-new file mode 100644
-index 0000000..e5be6d8
---- /dev/null
-+++ b/mech_eap/export_sec_context.c
-@@ -0,0 +1,246 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Serialise a security context. On the acceptor, this may be partially
-+ * established.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+static OM_uint32
-+gssEapExportPartialContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t token)
-+{
-+ OM_uint32 major, tmpMinor;
-+ size_t length, serverLen = 0;
-+ unsigned char *p;
-+ char serverBuf[MAXHOSTNAMELEN];
-+ if (ctx->acceptorCtx.radConn != NULL) {
-+ if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn,
-+ serverBuf, sizeof(serverBuf)) != 0) {
-+#if 0
-+ return gssEapRadiusMapError(minor,
-+ rs_err_conn_pop(ctx->acceptorCtx.radConn));
-+#else
-+ serverBuf[0] = '\0'; /* not implemented yet */
-+#endif
-+ }
-+ serverLen = strlen(serverBuf);
-+ }
-+ length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
-+
-+ token->value = GSSEAP_MALLOC(length);
-+ if (token->value == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ token->length = length;
-+
-+ p = (unsigned char *)token->value;
-+
-+ store_uint32_be(serverLen, p);
-+ p += 4;
-+ if (serverLen != 0) {
-+ memcpy(p, serverBuf, serverLen);
-+ p += serverLen;
-+ }
-+
-+ store_uint32_be(ctx->acceptorCtx.state.length, p);
-+ p += 4;
-+ if (ctx->acceptorCtx.state.length != 0) {
-+ memcpy(p, ctx->acceptorCtx.state.value,
-+ ctx->acceptorCtx.state.length);
-+ p += ctx->acceptorCtx.state.length;
-+ }
-+
-+ GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gss_release_buffer(&tmpMinor, token);
-+
-+ return major;
-+}
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+OM_uint32
-+gssEapExportSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t token)
-+{
-+ OM_uint32 major, tmpMinor;
-+ size_t length;
-+ gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc key;
-+ unsigned char *p;
-+
-+ if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) ||
-+ ctx->mechanismUsed == GSS_C_NO_OID) {
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ return GSS_S_NO_CONTEXT;
-+ }
-+
-+ key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
-+ key.value = KRB_KEY_DATA(&ctx->rfc3961Key);
-+
-+ if (ctx->initiatorName != GSS_C_NO_NAME) {
-+ major = gssEapExportNameInternal(minor, ctx->initiatorName,
-+ &initiatorName,
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (ctx->acceptorName != GSS_C_NO_NAME) {
-+ major = gssEapExportNameInternal(minor, ctx->acceptorName,
-+ &acceptorName,
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ /*
-+ * The partial context is only transmitted for unestablished acceptor
-+ * contexts.
-+ */
-+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
-+ (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
-+ major = gssEapExportPartialContext(minor, ctx, &partialCtx);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+#endif
-+
-+ length = 16; /* version, state, flags, */
-+ length += 4 + ctx->mechanismUsed->length; /* mechanismUsed */
-+ length += 12 + key.length; /* rfc3961Key.value */
-+ length += 4 + initiatorName.length; /* initiatorName.value */
-+ length += 4 + acceptorName.length; /* acceptorName.value */
-+ length += 24 + sequenceSize(ctx->seqState); /* seqState */
-+
-+ if (partialCtx.value != NULL)
-+ length += 4 + partialCtx.length; /* partialCtx.value */
-+
-+ token->value = GSSEAP_MALLOC(length);
-+ if (token->value == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ token->length = length;
-+
-+ p = (unsigned char *)token->value;
-+
-+ store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]); /* version */
-+ store_uint32_be(GSSEAP_SM_STATE(ctx), &p[4]);
-+ store_uint32_be(ctx->flags, &p[8]);
-+ store_uint32_be(ctx->gssFlags, &p[12]);
-+ p = store_oid(ctx->mechanismUsed, &p[16]);
-+
-+ store_uint32_be(ctx->checksumType, &p[0]);
-+ store_uint32_be(ctx->encryptionType, &p[4]);
-+ p = store_buffer(&key, &p[8], FALSE);
-+
-+ p = store_buffer(&initiatorName, p, FALSE);
-+ p = store_buffer(&acceptorName, p, FALSE);
-+
-+ store_uint64_be(ctx->expiryTime, &p[0]);
-+ store_uint64_be(ctx->sendSeq, &p[8]);
-+ store_uint64_be(ctx->recvSeq, &p[16]);
-+ p += 24;
-+
-+ major = sequenceExternalize(minor, ctx->seqState, &p, &length);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (partialCtx.value != NULL)
-+ p = store_buffer(&partialCtx, p, FALSE);
-+
-+ GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gss_release_buffer(&tmpMinor, token);
-+ gss_release_buffer(&tmpMinor, &initiatorName);
-+ gss_release_buffer(&tmpMinor, &acceptorName);
-+ gss_release_buffer(&tmpMinor, &partialCtx);
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_export_sec_context(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_buffer_t interprocess_token)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_ctx_id_t ctx = *context_handle;
-+
-+ interprocess_token->length = 0;
-+ interprocess_token->value = NULL;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapExportSecContext(minor, ctx, interprocess_token);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ return major;
-+ }
-+
-+ *context_handle = GSS_C_NO_CONTEXT;
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ gssEapReleaseContext(&tmpMinor, &ctx);
-+
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/get_mic.c b/mech_eap/get_mic.c
-new file mode 100644
-index 0000000..7161e9c
---- /dev/null
-+++ b/mech_eap/get_mic.c
-@@ -0,0 +1,89 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Message protection services: make a message integerity check.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_get_mic(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_qop_t qop_req,
-+ gss_buffer_t message_buffer,
-+ gss_buffer_t message_token)
-+{
-+ OM_uint32 major;
-+ gss_iov_buffer_desc iov[2];
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ if (qop_req != GSS_C_QOP_DEFAULT) {
-+ *minor = GSSEAP_UNKNOWN_QOP;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ *minor = 0;
-+
-+ message_token->value = NULL;
-+ message_token->length = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[0].buffer = *message_buffer;
-+
-+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-+ iov[1].buffer.value = NULL;
-+ iov[1].buffer.length = 0;
-+
-+ major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ *message_token = iov[1].buffer;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/get_name_attribute.c b/mech_eap/get_name_attribute.c
-new file mode 100644
-index 0000000..a885823
---- /dev/null
-+++ b/mech_eap/get_name_attribute.c
-@@ -0,0 +1,67 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+/*
-+ * Wrapper for retrieving a naming attribute.
-+ */
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_get_name_attribute(OM_uint32 *minor,
-+ 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 major;
-+
-+ *minor = 0;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapGetNameAttribute(minor, name, attr,
-+ authenticated, complete,
-+ value, display_value, more);
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h
-new file mode 100644
-index 0000000..d1790a0
---- /dev/null
-+++ b/mech_eap/gssapiP_eap.h
-@@ -0,0 +1,410 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+#ifndef _GSSAPIP_EAP_H_
-+#define _GSSAPIP_EAP_H_ 1
-+
-+#include "config.h"
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+#define KRB5_DEPRECATED /* so we can use krb5_free_unparsed_name() */
-+#endif
-+
-+#include <assert.h>
-+#include <string.h>
-+#include <errno.h>
-+#ifdef HAVE_UNISTD_H
-+#include <unistd.h>
-+#endif
-+#ifdef HAVE_STDLIB_H
-+#include <stdlib.h>
-+#endif
-+#ifdef HAVE_STDARG_H
-+#include <stdarg.h>
-+#endif
-+#include <time.h>
-+#ifdef HAVE_SYS_PARAM_H
-+#include <sys/param.h>
-+#endif
-+
-+#ifdef WIN32
-+#ifndef MAXHOSTNAMELEN
-+# include <WinSock2.h>
-+# define MAXHOSTNAMELEN NI_MAXHOST
-+#endif
-+#endif
-+
-+/* GSS headers */
-+#include <gssapi/gssapi.h>
-+#include <gssapi/gssapi_krb5.h>
-+#ifdef HAVE_HEIMDAL_VERSION
-+typedef struct gss_any *gss_any_t;
-+#else
-+#include <gssapi/gssapi_ext.h>
-+#endif
-+#include "gssapi_eap.h"
-+
-+#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
-+typedef const gss_OID_desc *gss_const_OID;
-+#endif
-+
-+/* Kerberos headers */
-+#include <krb5.h>
-+
-+/* EAP headers */
-+#include <includes.h>
-+#include <common.h>
-+#include <eap_peer/eap.h>
-+#include <eap_peer/eap_config.h>
-+#include <eap_peer/eap_methods.h>
-+#include <eap_common/eap_common.h>
-+#include <wpabuf.h>
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+/* FreeRADIUS headers */
-+#ifdef __cplusplus
-+extern "C" {
-+#ifndef WIN32
-+#define operator fr_operator
-+#endif
-+#endif
-+#include <freeradius/libradius.h>
-+#include <freeradius/radius.h>
-+
-+#undef pid_t
-+
-+/* libradsec headers */
-+#include <radsec/radsec.h>
-+#include <radsec/request.h>
-+#ifdef __cplusplus
-+#ifndef WIN32
-+#undef operator
-+#endif
-+}
-+#endif
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+#include "gsseap_err.h"
-+#include "radsec_err.h"
-+#include "util.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/* These name flags are informative and not actually used by anything yet */
-+#define NAME_FLAG_NAI 0x00000001
-+#define NAME_FLAG_SERVICE 0x00000002
-+#define NAME_FLAG_COMPOSITE 0x00000004
-+
-+struct gss_eap_saml_attr_ctx;
-+struct gss_eap_attr_ctx;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+struct gss_name_t_desc_struct
-+#else
-+struct gss_name_struct
-+#endif
-+{
-+ GSSEAP_MUTEX mutex; /* mutex protects attrCtx */
-+ OM_uint32 flags;
-+ gss_OID mechanismUsed; /* this is immutable */
-+ krb5_principal krbPrincipal; /* this is immutable */
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ struct gss_eap_attr_ctx *attrCtx;
-+#endif
-+};
-+
-+#define CRED_FLAG_INITIATE 0x00010000
-+#define CRED_FLAG_ACCEPT 0x00020000
-+#define CRED_FLAG_PASSWORD 0x00040000
-+#define CRED_FLAG_DEFAULT_CCACHE 0x00080000
-+#define CRED_FLAG_RESOLVED 0x00100000
-+#define CRED_FLAG_TARGET 0x00200000
-+#define CRED_FLAG_PUBLIC_MASK 0x0000FFFF
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+struct gss_cred_id_t_desc_struct
-+#else
-+struct gss_cred_id_struct
-+#endif
-+{
-+ GSSEAP_MUTEX mutex;
-+ OM_uint32 flags;
-+ gss_name_t name;
-+ gss_name_t target; /* for initiator */
-+ gss_buffer_desc password;
-+ gss_OID_set mechanisms;
-+ time_t expiryTime;
-+ gss_buffer_desc radiusConfigFile;
-+ gss_buffer_desc radiusConfigStanza;
-+ gss_buffer_desc caCertificate;
-+ gss_buffer_desc subjectNameConstraint;
-+ gss_buffer_desc subjectAltNameConstraint;
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ krb5_ccache krbCredCache;
-+ gss_cred_id_t reauthCred;
-+#endif
-+};
-+
-+#define CTX_FLAG_INITIATOR 0x00000001
-+#define CTX_FLAG_KRB_REAUTH 0x00000002
-+
-+#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
-+
-+#define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == GSSEAP_STATE_ESTABLISHED)
-+
-+/* Initiator context flags */
-+#define CTX_FLAG_EAP_SUCCESS 0x00010000
-+#define CTX_FLAG_EAP_RESTART 0x00020000
-+#define CTX_FLAG_EAP_FAIL 0x00040000
-+#define CTX_FLAG_EAP_RESP 0x00080000
-+#define CTX_FLAG_EAP_NO_RESP 0x00100000
-+#define CTX_FLAG_EAP_REQ 0x00200000
-+#define CTX_FLAG_EAP_PORT_ENABLED 0x00400000
-+#define CTX_FLAG_EAP_ALT_ACCEPT 0x00800000
-+#define CTX_FLAG_EAP_ALT_REJECT 0x01000000
-+#define CTX_FLAG_EAP_MASK 0xFFFF0000
-+
-+struct gss_eap_initiator_ctx {
-+ unsigned int idleWhile;
-+ struct eap_peer_config eapPeerConfig;
-+ struct eap_sm *eap;
-+ struct wpabuf reqData;
-+};
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+struct gss_eap_acceptor_ctx {
-+ struct rs_context *radContext;
-+ struct rs_connection *radConn;
-+ char *radServer;
-+ gss_buffer_desc state;
-+ VALUE_PAIR *vps;
-+};
-+#endif
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+struct gss_ctx_id_t_desc_struct
-+#else
-+struct gss_ctx_id_struct
-+#endif
-+{
-+ GSSEAP_MUTEX mutex;
-+ enum gss_eap_state state;
-+ OM_uint32 flags;
-+ OM_uint32 gssFlags;
-+ gss_OID mechanismUsed;
-+ krb5_cksumtype checksumType;
-+ krb5_enctype encryptionType;
-+ krb5_keyblock rfc3961Key;
-+ gss_name_t initiatorName;
-+ gss_name_t acceptorName;
-+ time_t expiryTime;
-+ uint64_t sendSeq, recvSeq;
-+ void *seqState;
-+ gss_cred_id_t cred;
-+ union {
-+ struct gss_eap_initiator_ctx initiator;
-+ #define initiatorCtx ctxU.initiator
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ struct gss_eap_acceptor_ctx acceptor;
-+ #define acceptorCtx ctxU.acceptor
-+#endif
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ gss_ctx_id_t reauth;
-+ #define reauthCtx ctxU.reauth
-+#endif
-+ } ctxU;
-+ const struct gss_eap_token_buffer_set *inputTokens;
-+ const struct gss_eap_token_buffer_set *outputTokens;
-+};
-+
-+#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01
-+#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02
-+#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04
-+
-+#define KEY_USAGE_ACCEPTOR_SEAL 22
-+#define KEY_USAGE_ACCEPTOR_SIGN 23
-+#define KEY_USAGE_INITIATOR_SEAL 24
-+#define KEY_USAGE_INITIATOR_SIGN 25
-+
-+/* accept_sec_context.c */
-+OM_uint32
-+gssEapAcceptSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ 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);
-+
-+/* init_sec_context.c */
-+OM_uint32
-+gssEapInitSecContext(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ 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);
-+
-+/* wrap_iov.c */
-+OM_uint32
-+gssEapWrapOrGetMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype);
-+
-+OM_uint32
-+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
-+ gss_ctx_id_t ctx,
-+ int *conf_state,
-+ gss_qop_t *qop_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype);
-+
-+OM_uint32
-+gssEapWrapIovLength(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ gss_qop_t qop_req,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count);
-+OM_uint32
-+gssEapWrap(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ gss_qop_t qop_req,
-+ gss_buffer_t input_message_buffer,
-+ int *conf_state,
-+ gss_buffer_t output_message_buffer);
-+
-+unsigned char
-+rfc4121Flags(gss_ctx_id_t ctx, int receiving);
-+
-+/* display_status.c */
-+void
-+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
-+
-+OM_uint32
-+gssEapDisplayStatus(OM_uint32 *minor,
-+ OM_uint32 status_value,
-+ gss_buffer_t status_string);
-+
-+#define IS_WIRE_ERROR(err) ((err) > GSSEAP_RESERVED && \
-+ (err) <= GSSEAP_RADIUS_PROT_FAILURE)
-+
-+/* upper bound of RADIUS error range must be kept in sync with radsec.h */
-+#define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \
-+ (err) <= ERROR_TABLE_BASE_rse + 20)
-+
-+/* exchange_meta_data.c */
-+OM_uint32 GSSAPI_CALLCONV
-+gssEapExchangeMetaData(OM_uint32 *minor,
-+ gss_const_OID mech,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t *ctx,
-+ const gss_name_t name,
-+ OM_uint32 req_flags,
-+ gss_const_buffer_t meta_data);
-+
-+/* export_sec_context.c */
-+OM_uint32
-+gssEapExportSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t token);
-+
-+/* import_sec_context.c */
-+OM_uint32
-+gssEapImportContext(OM_uint32 *minor,
-+ gss_buffer_t token,
-+ gss_ctx_id_t ctx);
-+
-+/* inquire_sec_context_by_oid.c */
-+#define NEGOEX_INITIATOR_SALT "gss-eap-negoex-initiator"
-+#define NEGOEX_INITIATOR_SALT_LEN (sizeof(NEGOEX_INITIATOR_SALT) - 1)
-+
-+#define NEGOEX_ACCEPTOR_SALT "gss-eap-negoex-acceptor"
-+#define NEGOEX_ACCEPTOR_SALT_LEN (sizeof(NEGOEX_ACCEPTOR_SALT) - 1)
-+
-+/* pseudo_random.c */
-+OM_uint32
-+gssEapPseudoRandom(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int prf_key,
-+ const gss_buffer_t prf_in,
-+ ssize_t desired_output_len,
-+ gss_buffer_t prf_out);
-+
-+/* query_mechanism_info.c */
-+OM_uint32
-+gssQueryMechanismInfo(OM_uint32 *minor,
-+ gss_const_OID mech_oid,
-+ unsigned char auth_scheme[16]);
-+
-+/* query_meta_data.c */
-+OM_uint32
-+gssEapQueryMetaData(OM_uint32 *minor,
-+ gss_const_OID mech GSSEAP_UNUSED,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t *context_handle,
-+ const gss_name_t name,
-+ OM_uint32 req_flags GSSEAP_UNUSED,
-+ gss_buffer_t meta_data);
-+
-+/* eap_mech.c */
-+OM_uint32
-+gssEapInitiatorInit(OM_uint32 *minor);
-+
-+void
-+gssEapFinalize(void);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _GSSAPIP_EAP_H_ */
-diff --git a/mech_eap/gssapi_eap.h b/mech_eap/gssapi_eap.h
-new file mode 100644
-index 0000000..588665b
---- /dev/null
-+++ b/mech_eap/gssapi_eap.h
-@@ -0,0 +1,90 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+#ifndef _GSSAPI_EAP_H_
-+#define _GSSAPI_EAP_H_ 1
-+
-+#include <gssapi/gssapi.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif /* __cplusplus */
-+
-+/*
-+ * GSS EAP mechanism OIDs.
-+ */
-+extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM;
-+extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
-+
-+/*
-+ * Mechanism name OID.
-+ */
-+extern gss_OID GSS_EAP_NT_EAP_NAME;
-+
-+/*
-+ * The libradsec configuration file; defaults to radsec.conf
-+ * in the system configuration directory if unspecified.
-+ */
-+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
-+
-+/*
-+ * The stanza in the libradsec configuration file; defaults
-+ * to "gss-eap" if unspecified.
-+ */
-+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA;
-+
-+/*
-+ * Flags as a 32-bit integer in network byte order,
-+ * followed by a boolean octet indicating whether to
-+ * clear the specified flags (if absent, defaults to
-+ * FALSE, ie. set flags).
-+ */
-+extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG;
-+
-+/*
-+ * Password; for mechanism glues that do not support
-+ * gss_acquire_cred_with_password(), this can be set
-+ * on an existing credentials handle.
-+ */
-+extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD;
-+
-+/*
-+ * Credentials flag indicating the local attributes
-+ * processing should be skipped.
-+ */
-+#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG 0x00000001
-+
-+#ifdef __cplusplus
-+}
-+#endif /* __cplusplus */
-+
-+#endif /* _GSSAPI_EAP_H_ */
-diff --git a/mech_eap/gsseap_err.et b/mech_eap/gsseap_err.et
-new file mode 100644
-index 0000000..d60c2c7
---- /dev/null
-+++ b/mech_eap/gsseap_err.et
-@@ -0,0 +1,162 @@
-+#
-+# Copyright (c) 2011, JANET(UK)
-+# 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 JANET(UK) nor the names of its contributors
-+# may be used to endorse or promote products derived from this software
-+# without specific prior written permission.
-+#
-+# THIS SOFTWARE IS PROVIDED BY THE 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.
-+#
-+
-+error_table eapg
-+
-+#
-+# Protocol errors that can be returned in an error token. This should match
-+# up with makeErrorToken in accept_sec_context.c.
-+#
-+error_code GSSEAP_RESERVED, ""
-+error_code GSSEAP_WRONG_SIZE, "Buffer is incorrect size"
-+error_code GSSEAP_WRONG_MECH, "Mechanism OID is incorrect"
-+error_code GSSEAP_BAD_TOK_HEADER, "Token header is malformed or corrupt"
-+error_code GSSEAP_TOK_TRUNC, "Token is missing data"
-+error_code GSSEAP_BAD_DIRECTION, "Packet was replayed in wrong direction"
-+error_code GSSEAP_WRONG_TOK_ID, "Received token ID does not match expected token ID"
-+error_code GSSEAP_CRIT_ITOK_UNAVAILABLE, "Critical inner token type unavailable"
-+error_code GSSEAP_MISSING_REQUIRED_ITOK, "Missing required inner token"
-+error_code GSSEAP_DUPLICATE_ITOK, "Duplicate inner token received"
-+error_code GSSEAP_WRONG_ITOK, "Recieved invalid inner token for current state"
-+error_code GSSEAP_KEY_UNAVAILABLE, "EAP key unavailable"
-+error_code GSSEAP_KEY_TOO_SHORT, "EAP key too short"
-+error_code GSSEAP_RADIUS_AUTH_FAILURE, "Authentication rejected by RADIUS server"
-+error_code GSSEAP_UNKNOWN_RADIUS_CODE, "Received unknown response code from RADIUS server"
-+error_code GSSEAP_MISSING_EAP_REQUEST, "RADIUS response is missing EAP request"
-+error_code GSSEAP_RADIUS_PROT_FAILURE, "Generic RADIUS failure"
-+
-+#
-+# Context errors
-+#
-+error_code GSSEAP_CONTEXT_ESTABLISHED, "Context is already fully established"
-+error_code GSSEAP_CONTEXT_INCOMPLETE, "Attempt to use incomplete security context"
-+error_code GSSEAP_BAD_CONTEXT_TOKEN, "Context token is malformed or corrupt"
-+error_code GSSEAP_BAD_ERROR_TOKEN, "Error token is malformed or corrupt"
-+error_code GSSEAP_BAD_CONTEXT_OPTION, "Bad context option"
-+
-+#
-+# Name errors
-+#
-+error_code GSSEAP_BAD_SERVICE_NAME, "Name is not a valid service name"
-+error_code GSSEAP_BAD_INITIATOR_NAME, "Initiator identity must be a valid name"
-+error_code GSSEAP_NO_HOSTNAME, "Could not determine local host name"
-+error_code GSSEAP_NO_ACCEPTOR_NAME, "Could not determine acceptor identity"
-+error_code GSSEAP_BAD_NAME_TOKEN, "Name token is malformed or corrupt"
-+error_code GSSEAP_NO_LOCAL_MAPPING, "Unable to map name to a local identity"
-+
-+#
-+# Credential errors
-+#
-+error_code GSSEAP_BAD_USAGE, "Credential usage type is unknown"
-+error_code GSSEAP_CRED_USAGE_MISMATCH, "Credential usage does not match requested usage"
-+error_code GSSEAP_CRED_MECH_MISMATCH, "Credential is not usable with this mechanism"
-+error_code GSSEAP_CRED_EXPIRED, "Attributes indicate credentials have expired"
-+error_code GSSEAP_BAD_CRED_OPTION, "Bad credential option"
-+error_code GSSEAP_NO_DEFAULT_IDENTITY, "Default credentials identity unavailable"
-+error_code GSSEAP_NO_DEFAULT_CRED, "Missing default password or other credentials"
-+error_code GSSEAP_CRED_RESOLVED, "Credential is already fully resolved"
-+
-+#
-+# Local identity service errors
-+#
-+error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE, "Unable to start identity service"
-+error_code GSSEAP_NO_IDENTITY_SELECTED, "No identity selected"
-+error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR, "Identity service installation error"
-+error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR, "Identity service OS error"
-+error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR, "Identity service IPC error"
-+error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR, "Unknown identity service error"
-+
-+#
-+# Wrap/unwrap/PRF errors
-+#
-+error_code GSSEAP_BAD_WRAP_TOKEN, "Bad RFC 4121 wrap or MIC token"
-+error_code GSSEAP_MISSING_IOV, "IOV is missing required buffer"
-+error_code GSSEAP_BAD_STREAM_IOV, "Stream IOV can only contain a single data buffer"
-+error_code GSSEAP_BAD_PADDING_IOV, "Padding IOV is not permitted for RFC 4121 tokens"
-+error_code GSSEAP_UNKNOWN_QOP, "Unknown quality of protection specified"
-+error_code GSSEAP_INPUT_TOO_LONG, "PRF input too long"
-+error_code GSSEAP_BAD_PRF_KEY, "PRF key usage type is unknown"
-+
-+#
-+# libeap errors
-+#
-+error_code GSSEAP_LIBEAP_INIT_FAILURE, "Failed to initialize EAP library"
-+error_code GSSEAP_PEER_SM_INIT_FAILURE, "Failed to create EAP state machine"
-+error_code GSSEAP_PEER_SM_STEP_FAILURE, "Failed to step EAP state machine"
-+error_code GSSEAP_PEER_AUTH_FAILURE, "EAP peer authentication failure"
-+error_code GSSEAP_PEER_BAD_MESSAGE, "Received bad EAP message"
-+
-+#
-+# RadSec initialisation errors
-+#
-+error_code GSSEAP_RADSEC_INIT_FAILURE, "Failed to initialize RadSec library"
-+error_code GSSEAP_RADSEC_CONTEXT_FAILURE, "Failed to create RadSec context"
-+
-+#
-+# Attribute errors
-+#
-+error_code GSSEAP_NO_ATTR_CONTEXT, "Name has no attributes"
-+error_code GSSEAP_NO_ATTR_PROVIDERS, "Failed to initialize attribute providers"
-+error_code GSSEAP_NO_SUCH_ATTR, "Unknown naming attribute"
-+error_code GSSEAP_BAD_ATTR_TOKEN, "Serialised attributes are malformed or corrupt"
-+error_code GSSEAP_ATTR_CONTEXT_FAILURE, "Failed to initialize attribute context"
-+
-+#
-+# OpenSAML errors
-+#
-+error_code GSSEAP_SAML_INIT_FAILURE, "Failed to initialize SAML library"
-+error_code GSSEAP_SAML_SEC_POLICY_FAILURE, "Failed to process SAML security policy"
-+error_code GSSEAP_SAML_BINDING_FAILURE, "Failed in SAML binding processing"
-+error_code GSSEAP_SAML_PROFILE_FAILURE, "Failed to process SAML profile"
-+error_code GSSEAP_SAML_FATAL_PROFILE_FAILURE, "Non-recoverable failure in SAML profile processing"
-+error_code GSSEAP_SAML_RETRY_PROFILE_FAILURE, "Temporary failure in SAML profile processing"
-+error_code GSSEAP_SAML_METADATA_FAILURE, "Failure related to SAML metadata use"
-+
-+#
-+# Shibboleth errors
-+#
-+error_code GSSEAP_SHIB_INIT_FAILURE, "Failed to initialize Shibboleth"
-+error_code GSSEAP_SHIB_ATTR_FAILURE, "Failure during local attribute processing"
-+error_code GSSEAP_SHIB_ATTR_EXTRACT_FAILURE, "Failed to extract local attributes"
-+error_code GSSEAP_SHIB_ATTR_FILTER_FAILURE, "Failed to filter local attributes"
-+error_code GSSEAP_SHIB_ATTR_RESOLVE_FAILURE, "Failed to resolve local attributes"
-+error_code GSSEAP_SHIB_CONFIG_FAILURE, "Local attribute configuration failure"
-+error_code GSSEAP_SHIB_LISTENER_FAILURE, "Failed to communicate with local attribute server"
-+
-+#
-+# Extensions
-+#
-+error_code GSSEAP_BINDINGS_MISMATCH, "Channel bindings do not match"
-+error_code GSSEAP_NO_MECHGLUE_SYMBOL, "Could not find symbol in mechanism glue"
-+error_code GSSEAP_BAD_INVOCATION, "Bad mechanism invoke OID"
-+
-+end
-diff --git a/mech_eap/import_name.c b/mech_eap/import_name.c
-new file mode 100644
-index 0000000..8049e01
---- /dev/null
-+++ b/mech_eap/import_name.c
-@@ -0,0 +1,47 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Deserialise a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_import_name(OM_uint32 *minor,
-+ gss_buffer_t import_name_buffer,
-+ gss_OID input_name_type,
-+ gss_name_t *output_name)
-+{
-+ return gssEapImportName(minor, import_name_buffer,
-+ input_name_type, GSS_C_NO_OID, output_name);
-+}
-diff --git a/mech_eap/import_sec_context.c b/mech_eap/import_sec_context.c
-new file mode 100644
-index 0000000..1533a16
---- /dev/null
-+++ b/mech_eap/import_sec_context.c
-@@ -0,0 +1,374 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Deserialise a context handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#define UPDATE_REMAIN(n) do { \
-+ p += (n); \
-+ remain -= (n); \
-+ } while (0)
-+
-+#define CHECK_REMAIN(n) do { \
-+ if (remain < (n)) { \
-+ *minor = GSSEAP_TOK_TRUNC; \
-+ return GSS_S_DEFECTIVE_TOKEN; \
-+ } \
-+ } while (0)
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+static OM_uint32
-+gssEapImportPartialContext(OM_uint32 *minor,
-+ unsigned char **pBuf,
-+ size_t *pRemain,
-+ gss_ctx_id_t ctx)
-+{
-+ OM_uint32 major;
-+ unsigned char *p = *pBuf;
-+ size_t remain = *pRemain;
-+ gss_buffer_desc buf;
-+ size_t ctxLength, serverLen;
-+
-+ /* Length of partial RADIUS context */
-+ CHECK_REMAIN(4);
-+ ctxLength = load_uint32_be(p);
-+ UPDATE_REMAIN(4);
-+
-+ CHECK_REMAIN(ctxLength);
-+ remain = ctxLength; /* check against partial context length */
-+
-+ /* Selected RADIUS server */
-+ CHECK_REMAIN(4);
-+ serverLen = load_uint32_be(p);
-+ UPDATE_REMAIN(4);
-+
-+ if (serverLen != 0) {
-+ CHECK_REMAIN(serverLen);
-+
-+ ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1);
-+ if (ctx->acceptorCtx.radServer == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+ memcpy(ctx->acceptorCtx.radServer, p, serverLen);
-+ ctx->acceptorCtx.radServer[serverLen] = '\0';
-+
-+ UPDATE_REMAIN(serverLen);
-+ }
-+
-+ /* RADIUS state blob */
-+ CHECK_REMAIN(4);
-+ buf.length = load_uint32_be(p);
-+ UPDATE_REMAIN(4);
-+
-+ if (buf.length != 0) {
-+ CHECK_REMAIN(buf.length);
-+
-+ buf.value = p;
-+
-+ major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ UPDATE_REMAIN(buf.length);
-+ }
-+
-+#ifdef GSSEAP_DEBUG
-+ GSSEAP_ASSERT(remain == 0);
-+#endif
-+
-+ *pBuf = p;
-+ *pRemain -= 4 + ctxLength;
-+
-+ return GSS_S_COMPLETE;
-+}
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+static OM_uint32
-+importMechanismOid(OM_uint32 *minor,
-+ unsigned char **pBuf,
-+ size_t *pRemain,
-+ gss_OID *pOid)
-+{
-+ OM_uint32 major;
-+ unsigned char *p = *pBuf;
-+ size_t remain = *pRemain;
-+ gss_OID_desc oidBuf;
-+
-+ oidBuf.length = load_uint32_be(p);
-+ if (remain < 4 + oidBuf.length || oidBuf.length == 0) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ oidBuf.elements = &p[4];
-+
-+ major = gssEapCanonicalizeOid(minor, &oidBuf, 0, pOid);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ *pBuf += 4 + oidBuf.length;
-+ *pRemain -= 4 + oidBuf.length;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+importKerberosKey(OM_uint32 *minor,
-+ unsigned char **pBuf,
-+ size_t *pRemain,
-+ krb5_cksumtype *checksumType,
-+ krb5_enctype *pEncryptionType,
-+ krb5_keyblock *pKey)
-+{
-+ unsigned char *p = *pBuf;
-+ size_t remain = *pRemain;
-+ OM_uint32 encryptionType;
-+ OM_uint32 length;
-+ krb5_context krbContext;
-+ krb5_keyblock key;
-+ krb5_error_code code;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ KRB_KEY_INIT(pKey);
-+
-+ if (remain < 12) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ *checksumType = load_uint32_be(&p[0]);
-+ encryptionType = load_uint32_be(&p[4]);
-+ length = load_uint32_be(&p[8]);
-+
-+ if ((length != 0) != (encryptionType != ENCTYPE_NULL)) {
-+ *minor = GSSEAP_BAD_CONTEXT_TOKEN;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ if (remain - 12 < length) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ if (encryptionType != ENCTYPE_NULL) {
-+ KRB_KEY_INIT(&key);
-+
-+ KRB_KEY_TYPE(&key) = encryptionType;
-+ KRB_KEY_LENGTH(&key) = length;
-+ KRB_KEY_DATA(&key) = &p[12];
-+
-+ code = krb5_copy_keyblock_contents(krbContext, &key, pKey);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+ }
-+
-+ *pBuf += 12 + length;
-+ *pRemain -= 12 + length;
-+ *pEncryptionType = encryptionType;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+importName(OM_uint32 *minor,
-+ unsigned char **pBuf,
-+ size_t *pRemain,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major;
-+ unsigned char *p = *pBuf;
-+ size_t remain = *pRemain;
-+ gss_buffer_desc tmp;
-+
-+ if (remain < 4) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ tmp.length = load_uint32_be(p);
-+ if (tmp.length != 0) {
-+ if (remain - 4 < tmp.length) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ tmp.value = p + 4;
-+
-+ major = gssEapImportNameInternal(minor, &tmp, pName,
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ *pBuf += 4 + tmp.length;
-+ *pRemain -= 4 + tmp.length;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapImportContext(OM_uint32 *minor,
-+ gss_buffer_t token,
-+ gss_ctx_id_t ctx)
-+{
-+ OM_uint32 major;
-+ unsigned char *p = (unsigned char *)token->value;
-+ size_t remain = token->length;
-+
-+ if (remain < 16) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+ if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) {
-+ *minor = GSSEAP_BAD_CONTEXT_TOKEN;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+ ctx->state = load_uint32_be(&p[4]);
-+ ctx->flags = load_uint32_be(&p[8]);
-+ ctx->gssFlags = load_uint32_be(&p[12]);
-+ p += 16;
-+ remain -= 16;
-+
-+ /* Validate state */
-+ if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL ||
-+ GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ /* Only acceptor can export partial context tokens */
-+ if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = importKerberosKey(minor, &p, &remain,
-+ &ctx->checksumType,
-+ &ctx->encryptionType,
-+ &ctx->rfc3961Key);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = importName(minor, &p, &remain, &ctx->initiatorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = importName(minor, &p, &remain, &ctx->acceptorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /* Check that, if context is established, names are valid */
-+ if (CTX_IS_ESTABLISHED(ctx) &&
-+ (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME
-+ : ctx->initiatorName == GSS_C_NO_NAME)) {
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ if (remain < 24 + sequenceSize(ctx->seqState)) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+ ctx->expiryTime = (time_t)load_uint64_be(&p[0]);
-+ ctx->sendSeq = load_uint64_be(&p[8]);
-+ ctx->recvSeq = load_uint64_be(&p[16]);
-+ p += 24;
-+ remain -= 24;
-+
-+ major = sequenceInternalize(minor, &ctx->seqState, &p, &remain);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ /*
-+ * The partial context should only be expected for unestablished
-+ * acceptor contexts.
-+ */
-+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
-+ (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
-+ major = gssEapImportPartialContext(minor, &p, &remain, ctx);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+#ifdef GSSEAP_DEBUG
-+ GSSEAP_ASSERT(remain == 0);
-+#endif
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_import_sec_context(OM_uint32 *minor,
-+ gss_buffer_t interprocess_token,
-+ gss_ctx_id_t *context_handle)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
-+
-+ *context_handle = GSS_C_NO_CONTEXT;
-+
-+ if (interprocess_token == GSS_C_NO_BUFFER ||
-+ interprocess_token->length == 0) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ major = gssEapAllocContext(minor, &ctx);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapImportContext(minor, interprocess_token, ctx);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ *context_handle = ctx;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gssEapReleaseContext(&tmpMinor, &ctx);
-+
-+ return major;
-+}
-diff --git a/mech_eap/indicate_mechs.c b/mech_eap/indicate_mechs.c
-new file mode 100644
-index 0000000..d4d275e
---- /dev/null
-+++ b/mech_eap/indicate_mechs.c
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Enumerate the supported mechanism OIDs.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_indicate_mechs(OM_uint32 *minor,
-+ gss_OID_set *mech_set)
-+{
-+ return gssEapIndicateMechs(minor, mech_set);
-+}
-diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c
-new file mode 100644
-index 0000000..e99b479
---- /dev/null
-+++ b/mech_eap/init_sec_context.c
-@@ -0,0 +1,1097 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Establish a security context on the initiator (client). These functions
-+ * wrap around libeap.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static OM_uint32
-+policyVariableToFlag(enum eapol_bool_var variable)
-+{
-+ OM_uint32 flag = 0;
-+
-+ switch (variable) {
-+ case EAPOL_eapSuccess:
-+ flag = CTX_FLAG_EAP_SUCCESS;
-+ break;
-+ case EAPOL_eapRestart:
-+ flag = CTX_FLAG_EAP_RESTART;
-+ break;
-+ case EAPOL_eapFail:
-+ flag = CTX_FLAG_EAP_FAIL;
-+ break;
-+ case EAPOL_eapResp:
-+ flag = CTX_FLAG_EAP_RESP;
-+ break;
-+ case EAPOL_eapNoResp:
-+ flag = CTX_FLAG_EAP_NO_RESP;
-+ break;
-+ case EAPOL_eapReq:
-+ flag = CTX_FLAG_EAP_REQ;
-+ break;
-+ case EAPOL_portEnabled:
-+ flag = CTX_FLAG_EAP_PORT_ENABLED;
-+ break;
-+ case EAPOL_altAccept:
-+ flag = CTX_FLAG_EAP_ALT_ACCEPT;
-+ break;
-+ case EAPOL_altReject:
-+ flag = CTX_FLAG_EAP_ALT_REJECT;
-+ break;
-+ }
-+
-+ return flag;
-+}
-+
-+static struct eap_peer_config *
-+peerGetConfig(void *ctx)
-+{
-+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
-+
-+ return &gssCtx->initiatorCtx.eapPeerConfig;
-+}
-+
-+static Boolean
-+peerGetBool(void *data, enum eapol_bool_var variable)
-+{
-+ gss_ctx_id_t ctx = data;
-+ OM_uint32 flag;
-+
-+ if (ctx == GSS_C_NO_CONTEXT)
-+ return FALSE;
-+
-+ flag = policyVariableToFlag(variable);
-+
-+ return ((ctx->flags & flag) != 0);
-+}
-+
-+static void
-+peerSetBool(void *data, enum eapol_bool_var variable,
-+ Boolean value)
-+{
-+ gss_ctx_id_t ctx = data;
-+ OM_uint32 flag;
-+
-+ if (ctx == GSS_C_NO_CONTEXT)
-+ return;
-+
-+ flag = policyVariableToFlag(variable);
-+
-+ if (value)
-+ ctx->flags |= flag;
-+ else
-+ ctx->flags &= ~(flag);
-+}
-+
-+static unsigned int
-+peerGetInt(void *data, enum eapol_int_var variable)
-+{
-+ gss_ctx_id_t ctx = data;
-+
-+ if (ctx == GSS_C_NO_CONTEXT)
-+ return FALSE;
-+
-+ GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
-+
-+ switch (variable) {
-+ case EAPOL_idleWhile:
-+ return ctx->initiatorCtx.idleWhile;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static void
-+peerSetInt(void *data, enum eapol_int_var variable,
-+ unsigned int value)
-+{
-+ gss_ctx_id_t ctx = data;
-+
-+ if (ctx == GSS_C_NO_CONTEXT)
-+ return;
-+
-+ GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
-+
-+ switch (variable) {
-+ case EAPOL_idleWhile:
-+ ctx->initiatorCtx.idleWhile = value;
-+ break;
-+ }
-+}
-+
-+static struct wpabuf *
-+peerGetEapReqData(void *ctx)
-+{
-+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
-+
-+ return &gssCtx->initiatorCtx.reqData;
-+}
-+
-+static void
-+peerSetConfigBlob(void *ctx GSSEAP_UNUSED,
-+ struct wpa_config_blob *blob GSSEAP_UNUSED)
-+{
-+}
-+
-+static const struct wpa_config_blob *
-+peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
-+ const char *name GSSEAP_UNUSED)
-+{
-+ return NULL;
-+}
-+
-+static void
-+peerNotifyPending(void *ctx GSSEAP_UNUSED)
-+{
-+}
-+
-+static struct eapol_callbacks gssEapPolicyCallbacks = {
-+ peerGetConfig,
-+ peerGetBool,
-+ peerSetBool,
-+ peerGetInt,
-+ peerSetInt,
-+ peerGetEapReqData,
-+ peerSetConfigBlob,
-+ peerGetConfigBlob,
-+ peerNotifyPending,
-+};
-+
-+#ifdef GSSEAP_DEBUG
-+extern int wpa_debug_level;
-+#endif
-+
-+static OM_uint32
-+peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
-+{
-+ OM_uint32 major;
-+ krb5_context krbContext;
-+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
-+ gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
-+ gss_cred_id_t cred = ctx->cred;
-+
-+ eapPeerConfig->identity = NULL;
-+ eapPeerConfig->identity_len = 0;
-+ eapPeerConfig->anonymous_identity = NULL;
-+ eapPeerConfig->anonymous_identity_len = 0;
-+ eapPeerConfig->password = NULL;
-+ eapPeerConfig->password_len = 0;
-+
-+ GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ eapPeerConfig->fragment_size = 1024;
-+#ifdef GSSEAP_DEBUG
-+ wpa_debug_level = 0;
-+#endif
-+
-+ GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME);
-+
-+ if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
-+ *minor = GSSEAP_BAD_INITIATOR_NAME;
-+ return GSS_S_BAD_NAME;
-+ }
-+
-+ /* identity */
-+ major = gssEapDisplayName(minor, cred->name, &identity, NULL);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ eapPeerConfig->identity = (unsigned char *)identity.value;
-+ eapPeerConfig->identity_len = identity.length;
-+
-+ krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm);
-+
-+ /* anonymous_identity */
-+ eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2);
-+ if (eapPeerConfig->anonymous_identity == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ eapPeerConfig->anonymous_identity[0] = '@';
-+ memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length);
-+ eapPeerConfig->anonymous_identity[1 + realm.length] = '\0';
-+ eapPeerConfig->anonymous_identity_len = 1 + realm.length;
-+
-+ /* password */
-+ eapPeerConfig->password = (unsigned char *)cred->password.value;
-+ eapPeerConfig->password_len = cred->password.length;
-+
-+ /* certs */
-+ eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
-+ eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
-+ eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+peerConfigFree(OM_uint32 *minor,
-+ gss_ctx_id_t ctx)
-+{
-+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
-+
-+ if (eapPeerConfig->identity != NULL) {
-+ GSSEAP_FREE(eapPeerConfig->identity);
-+ eapPeerConfig->identity = NULL;
-+ eapPeerConfig->identity_len = 0;
-+ }
-+
-+ if (eapPeerConfig->anonymous_identity != NULL) {
-+ GSSEAP_FREE(eapPeerConfig->anonymous_identity);
-+ eapPeerConfig->anonymous_identity = NULL;
-+ eapPeerConfig->anonymous_identity_len = 0;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * Mark an initiator context as ready for cryptographic operations
-+ */
-+static OM_uint32
-+initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
-+{
-+ OM_uint32 major;
-+ const unsigned char *key;
-+ size_t keyLength;
-+
-+#if 1
-+ /* XXX actually check for mutual auth */
-+ if (reqFlags & GSS_C_MUTUAL_FLAG)
-+ ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
-+#endif
-+
-+ /* Cache encryption type derived from selected mechanism OID */
-+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (!eap_key_available(ctx->initiatorCtx.eap)) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
-+
-+ if (keyLength < EAP_EMSK_LEN) {
-+ *minor = GSSEAP_KEY_TOO_SHORT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ major = gssEapDeriveRfc3961Key(minor,
-+ &key[EAP_EMSK_LEN / 2],
-+ EAP_EMSK_LEN / 2,
-+ ctx->encryptionType,
-+ &ctx->rfc3961Key);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
-+ &ctx->checksumType);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = sequenceInit(minor,
-+ &ctx->seqState,
-+ ctx->recvSeq,
-+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
-+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
-+ TRUE);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+initBegin(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target,
-+ gss_OID mech,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+ gss_cred_id_t cred = ctx->cred;
-+
-+ GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
-+
-+ if (cred->expiryTime)
-+ ctx->expiryTime = cred->expiryTime;
-+ else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
-+ ctx->expiryTime = 0;
-+ else
-+ ctx->expiryTime = time(NULL) + timeReq;
-+
-+ /*
-+ * The credential mutex protects its name, however we need to
-+ * explicitly lock the acceptor name (unlikely as it may be
-+ * that it has attributes set on it).
-+ */
-+ major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (target != GSS_C_NO_NAME) {
-+ GSSEAP_MUTEX_LOCK(&target->mutex);
-+
-+ major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
-+ return major;
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
-+ }
-+
-+ major = gssEapCanonicalizeOid(minor,
-+ mech,
-+ OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH,
-+ &ctx->mechanismUsed);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /* If credentials were provided, check they're usable with this mech */
-+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
-+ *minor = GSSEAP_CRED_MECH_MISMATCH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+eapGssSmInitError(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx GSSEAP_UNUSED,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+ unsigned char *p;
-+
-+ if (inputToken->length < 8) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ p = (unsigned char *)inputToken->value;
-+
-+ major = load_uint32_be(&p[0]);
-+ *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
-+
-+ if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_BAD_ERROR_TOKEN;
-+ }
-+
-+ GSSEAP_ASSERT(GSS_ERROR(major));
-+
-+ return major;
-+}
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+static OM_uint32
-+eapGssSmInitGssReauth(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags,
-+ OM_uint32 timeReq,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_name_t mechTarget = GSS_C_NO_NAME;
-+ gss_OID actualMech = GSS_C_NO_OID;
-+ OM_uint32 gssFlags, timeRec;
-+
-+ /*
-+ * Here we use the passed in credential handle because the resolved
-+ * context credential does not currently have the reauth creds.
-+ */
-+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
-+ if (!gssEapCanReauthP(cred, target, timeReq))
-+ return GSS_S_CONTINUE_NEEDED;
-+
-+ ctx->flags |= CTX_FLAG_KRB_REAUTH;
-+ } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_WRONG_ITOK;
-+ goto cleanup;
-+ }
-+
-+ GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
-+
-+ major = gssEapMechToGlueName(minor, target, &mechTarget);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssInitSecContext(minor,
-+ cred->reauthCred,
-+ &ctx->reauthCtx,
-+ mechTarget,
-+ (gss_OID)gss_mech_krb5,
-+ reqFlags | GSS_C_MUTUAL_FLAG,
-+ timeReq,
-+ chanBindings,
-+ inputToken,
-+ &actualMech,
-+ outputToken,
-+ &gssFlags,
-+ &timeRec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ctx->gssFlags = gssFlags;
-+
-+ if (major == GSS_S_COMPLETE) {
-+ GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
-+
-+ major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
-+ } else {
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
-+ }
-+
-+cleanup:
-+ gssReleaseName(&tmpMinor, &mechTarget);
-+
-+ return major;
-+}
-+#endif /* GSSEAP_ENABLE_REAUTH */
-+
-+#ifdef GSSEAP_DEBUG
-+static OM_uint32
-+eapGssSmInitVendorInfo(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx GSSEAP_UNUSED,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ major = makeStringBuffer(minor, "JANET(UK)", outputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+#endif
-+
-+static OM_uint32
-+eapGssSmInitAcceptorName(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL &&
-+ ctx->acceptorName != GSS_C_NO_NAME) {
-+
-+ /* Send desired target name to acceptor */
-+ major = gssEapDisplayName(minor, ctx->acceptorName,
-+ outputToken, NULL);
-+ if (GSS_ERROR(major))
-+ return major;
-+ } else if (inputToken != GSS_C_NO_BUFFER &&
-+ ctx->acceptorName == GSS_C_NO_NAME) {
-+ /* Accept target name hint from acceptor */
-+ major = gssEapImportName(minor, inputToken,
-+ GSS_C_NT_USER_NAME,
-+ ctx->mechanismUsed,
-+ &ctx->acceptorName);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ /*
-+ * Currently, other parts of the code assume that the acceptor name
-+ * is available, hence this check.
-+ */
-+ if (ctx->acceptorName == GSS_C_NO_NAME) {
-+ *minor = GSSEAP_NO_ACCEPTOR_NAME;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+static OM_uint32
-+eapGssSmInitIdentity(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags)
-+{
-+ struct eap_config eapConfig;
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
-+ OM_uint32 tmpMinor;
-+
-+ /* server didn't support reauthentication, sent EAP request */
-+ gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
-+ ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
-+ } else
-+#endif
-+ *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
-+
-+ GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
-+ GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
-+
-+ memset(&eapConfig, 0, sizeof(eapConfig));
-+
-+ ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
-+ &gssEapPolicyCallbacks,
-+ ctx,
-+ &eapConfig);
-+ if (ctx->initiatorCtx.eap == NULL) {
-+ *minor = GSSEAP_PEER_SM_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
-+
-+ /* poke EAP state machine */
-+ if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) {
-+ *minor = GSSEAP_PEER_SM_STEP_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+
-+ *minor = 0;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+static OM_uint32
-+eapGssSmInitAuthenticate(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major;
-+ OM_uint32 tmpMinor;
-+ struct wpabuf *resp = NULL;
-+
-+ *minor = 0;
-+
-+ GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
-+
-+ major = peerConfigInit(minor, ctx);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL);
-+ GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
-+
-+ ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
-+
-+ wpabuf_set(&ctx->initiatorCtx.reqData,
-+ inputToken->value, inputToken->length);
-+
-+ major = GSS_S_CONTINUE_NEEDED;
-+
-+ eap_peer_sm_step(ctx->initiatorCtx.eap);
-+ if (ctx->flags & CTX_FLAG_EAP_RESP) {
-+ ctx->flags &= ~(CTX_FLAG_EAP_RESP);
-+
-+ resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
-+ } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
-+ major = initReady(minor, ctx, reqFlags);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
-+ major = GSS_S_CONTINUE_NEEDED;
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+ } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
-+ major = GSS_S_DEFECTIVE_CREDENTIAL;
-+ *minor = GSSEAP_PEER_AUTH_FAILURE;
-+ } else {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_PEER_BAD_MESSAGE;
-+ }
-+
-+cleanup:
-+ if (resp != NULL) {
-+ OM_uint32 tmpMajor;
-+ gss_buffer_desc respBuf;
-+
-+ GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
-+
-+ respBuf.length = wpabuf_len(resp);
-+ respBuf.value = (void *)wpabuf_head(resp);
-+
-+ tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
-+ if (GSS_ERROR(tmpMajor)) {
-+ major = tmpMajor;
-+ *minor = tmpMinor;
-+ }
-+
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+ }
-+
-+ wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
-+ peerConfigFree(&tmpMinor, ctx);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+eapGssSmInitGssFlags(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ unsigned char wireFlags[4];
-+ gss_buffer_desc flagsBuf;
-+
-+ store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
-+
-+ flagsBuf.length = sizeof(wireFlags);
-+ flagsBuf.value = wireFlags;
-+
-+ return duplicateBuffer(minor, &flagsBuf, outputToken);
-+}
-+
-+static OM_uint32
-+eapGssSmInitGssChannelBindings(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major;
-+ gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
-+
-+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
-+ buffer = chanBindings->application_data;
-+
-+ major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
-+ &buffer, NULL, outputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ GSSEAP_ASSERT(outputToken->value != NULL);
-+
-+ *minor = 0;
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+static OM_uint32
-+eapGssSmInitInitiatorMIC(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken GSSEAP_UNUSED,
-+ gss_buffer_t outputToken,
-+ OM_uint32 *smFlags)
-+{
-+ OM_uint32 major;
-+
-+ major = gssEapMakeTokenMIC(minor, ctx, outputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ GSSEAP_SM_TRANSITION_NEXT(ctx);
-+
-+ *minor = 0;
-+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
-+
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+static OM_uint32
-+eapGssSmInitReauthCreds(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) {
-+ major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+#endif /* GSSEAP_ENABLE_REAUTH */
-+
-+static OM_uint32
-+eapGssSmInitAcceptorMIC(OM_uint32 *minor,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target GSSEAP_UNUSED,
-+ gss_OID mech GSSEAP_UNUSED,
-+ OM_uint32 reqFlags GSSEAP_UNUSED,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken GSSEAP_UNUSED,
-+ OM_uint32 *smFlags GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+
-+ major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
-+
-+ *minor = 0;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static struct gss_eap_sm eapGssInitiatorSm[] = {
-+ {
-+ ITOK_TYPE_CONTEXT_ERR,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
-+ 0,
-+ eapGssSmInitError
-+ },
-+ {
-+ ITOK_TYPE_ACCEPTOR_NAME_RESP,
-+ ITOK_TYPE_ACCEPTOR_NAME_REQ,
-+ GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
-+ 0,
-+ eapGssSmInitAcceptorName
-+ },
-+#ifdef GSSEAP_DEBUG
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_VENDOR_INFO,
-+ GSSEAP_STATE_INITIAL,
-+ 0,
-+ eapGssSmInitVendorInfo
-+ },
-+#endif
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ {
-+ ITOK_TYPE_REAUTH_RESP,
-+ ITOK_TYPE_REAUTH_REQ,
-+ GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
-+ 0,
-+ eapGssSmInitGssReauth
-+ },
-+#endif
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_NONE,
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ GSSEAP_STATE_REAUTHENTICATE |
-+#endif
-+ GSSEAP_STATE_INITIAL,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmInitIdentity
-+ },
-+ {
-+ ITOK_TYPE_EAP_REQ,
-+ ITOK_TYPE_EAP_RESP,
-+ GSSEAP_STATE_AUTHENTICATE,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmInitAuthenticate
-+ },
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_GSS_FLAGS,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ 0,
-+ eapGssSmInitGssFlags
-+ },
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_GSS_CHANNEL_BINDINGS,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmInitGssChannelBindings
-+ },
-+ {
-+ ITOK_TYPE_NONE,
-+ ITOK_TYPE_INITIATOR_MIC,
-+ GSSEAP_STATE_INITIATOR_EXTS,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmInitInitiatorMIC
-+ },
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ {
-+ ITOK_TYPE_REAUTH_CREDS,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_ACCEPTOR_EXTS,
-+ 0,
-+ eapGssSmInitReauthCreds
-+ },
-+#endif
-+ /* other extensions go here */
-+ {
-+ ITOK_TYPE_ACCEPTOR_MIC,
-+ ITOK_TYPE_NONE,
-+ GSSEAP_STATE_ACCEPTOR_EXTS,
-+ SM_ITOK_FLAG_REQUIRED,
-+ eapGssSmInitAcceptorMIC
-+ }
-+};
-+
-+OM_uint32
-+gssEapInitSecContext(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ 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, tmpMinor;
-+ int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
-+
-+ /*
-+ * XXX is acquiring the credential lock here necessary? The password is
-+ * mutable but the contract could specify that this is not updated whilst
-+ * a context is being initialized.
-+ */
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ if (ctx->cred == GSS_C_NO_CREDENTIAL) {
-+ major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
-+
-+ GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
-+ GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
-+
-+ if (initialContextToken) {
-+ major = initBegin(minor, ctx, target_name, mech_type,
-+ req_flags, time_req, input_chan_bindings);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ major = gssEapSmStep(minor,
-+ cred,
-+ ctx,
-+ target_name,
-+ mech_type,
-+ req_flags,
-+ time_req,
-+ input_chan_bindings,
-+ input_token,
-+ output_token,
-+ eapGssInitiatorSm,
-+ sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0]));
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (actual_mech_type != NULL) {
-+ OM_uint32 tmpMajor;
-+
-+ tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type);
-+ if (GSS_ERROR(tmpMajor)) {
-+ major = tmpMajor;
-+ *minor = tmpMinor;
-+ goto cleanup;
-+ }
-+ }
-+ if (ret_flags != NULL)
-+ *ret_flags = ctx->gssFlags;
-+ if (time_rec != NULL)
-+ gssEapContextTime(&tmpMinor, ctx, time_rec);
-+
-+ GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
-+
-+cleanup:
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+ if (ctx->cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_init_sec_context(OM_uint32 *minor,
-+ 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)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_ctx_id_t ctx = *context_handle;
-+
-+ *minor = 0;
-+
-+ output_token->length = 0;
-+ output_token->value = NULL;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
-+ *minor = GSSEAP_WRONG_SIZE;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ major = gssEapAllocContext(minor, &ctx);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ ctx->flags |= CTX_FLAG_INITIATOR;
-+
-+ *context_handle = ctx;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapInitSecContext(minor,
-+ cred,
-+ ctx,
-+ target_name,
-+ mech_type,
-+ req_flags,
-+ time_req,
-+ input_chan_bindings,
-+ input_token,
-+ actual_mech_type,
-+ output_token,
-+ ret_flags,
-+ time_rec);
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ if (GSS_ERROR(major))
-+ gssEapReleaseContext(&tmpMinor, context_handle);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_attrs_for_mech.c b/mech_eap/inquire_attrs_for_mech.c
-new file mode 100644
-index 0000000..a359f68
---- /dev/null
-+++ b/mech_eap/inquire_attrs_for_mech.c
-@@ -0,0 +1,137 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Enumerate the features supported by the GSS EAP mechanism.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#define MA_ADD(ma, set) do { \
-+ major = gss_add_oid_set_member(minor, (gss_OID)(ma), (set)); \
-+ if (GSS_ERROR(major)) \
-+ goto cleanup; \
-+ } while (0)
-+
-+#define MA_SUPPORTED(ma) MA_ADD((ma), mech_attrs)
-+#define MA_KNOWN(ma) MA_ADD((ma), known_mech_attrs)
-+
-+OM_uint32 GSSAPI_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 major, tmpMinor;
-+
-+ if (mech_attrs != NULL)
-+ *mech_attrs = GSS_C_NO_OID_SET;
-+ if (known_mech_attrs != NULL)
-+ *known_mech_attrs = GSS_C_NO_OID_SET;
-+
-+ if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (mech_attrs != NULL) {
-+ major = gss_create_empty_oid_set(minor, mech_attrs);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
-+ if (oidEqual(mech_oid, GSS_EAP_MECHANISM))
-+ MA_SUPPORTED(GSS_C_MA_MECH_PSEUDO);
-+ else
-+ 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_AUTH_INIT_INIT);
-+ 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_REPLAY_DET);
-+ MA_SUPPORTED(GSS_C_MA_OOS_DET);
-+ MA_SUPPORTED(GSS_C_MA_CBINDINGS);
-+ MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
-+#endif
-+ }
-+
-+ if (known_mech_attrs != NULL) {
-+ major = gss_create_empty_oid_set(minor, known_mech_attrs);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
-+ MA_KNOWN(GSS_C_MA_MECH_CONCRETE);
-+ MA_KNOWN(GSS_C_MA_MECH_PSEUDO);
-+ MA_KNOWN(GSS_C_MA_MECH_COMPOSITE);
-+ MA_KNOWN(GSS_C_MA_MECH_NEGO);
-+ MA_KNOWN(GSS_C_MA_MECH_GLUE);
-+ MA_KNOWN(GSS_C_MA_NOT_MECH);
-+ MA_KNOWN(GSS_C_MA_DEPRECATED);
-+ MA_KNOWN(GSS_C_MA_NOT_DFLT_MECH);
-+ MA_KNOWN(GSS_C_MA_ITOK_FRAMED);
-+ MA_KNOWN(GSS_C_MA_AUTH_INIT);
-+ MA_KNOWN(GSS_C_MA_AUTH_TARG);
-+ MA_KNOWN(GSS_C_MA_AUTH_INIT_INIT);
-+ MA_KNOWN(GSS_C_MA_AUTH_TARG_INIT);
-+ MA_KNOWN(GSS_C_MA_AUTH_INIT_ANON);
-+ MA_KNOWN(GSS_C_MA_AUTH_TARG_ANON);
-+ MA_KNOWN(GSS_C_MA_DELEG_CRED);
-+ MA_KNOWN(GSS_C_MA_INTEG_PROT);
-+ MA_KNOWN(GSS_C_MA_CONF_PROT);
-+ MA_KNOWN(GSS_C_MA_MIC);
-+ MA_KNOWN(GSS_C_MA_WRAP);
-+ MA_KNOWN(GSS_C_MA_PROT_READY);
-+ MA_KNOWN(GSS_C_MA_REPLAY_DET);
-+ MA_KNOWN(GSS_C_MA_OOS_DET);
-+ MA_KNOWN(GSS_C_MA_CBINDINGS);
-+ MA_KNOWN(GSS_C_MA_PFS);
-+ MA_KNOWN(GSS_C_MA_COMPRESS);
-+ MA_KNOWN(GSS_C_MA_CTX_TRANS);
-+#endif
-+ }
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ gss_release_oid_set(&tmpMinor, mech_attrs);
-+ gss_release_oid_set(&tmpMinor, known_mech_attrs);
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_context.c b/mech_eap/inquire_context.c
-new file mode 100644
-index 0000000..d37818d
---- /dev/null
-+++ b/mech_eap/inquire_context.c
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return context handle properties.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_context(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ 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 major, tmpMinor;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (src_name != NULL) {
-+ major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (targ_name != NULL) {
-+ major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (lifetime_rec != NULL) {
-+ time_t now, lifetime;
-+
-+ if (ctx->expiryTime == 0) {
-+ lifetime = GSS_C_INDEFINITE;
-+ } else {
-+ now = time(NULL);
-+ lifetime = now - ctx->expiryTime;
-+ if (lifetime < 0)
-+ lifetime = 0;
-+ }
-+
-+ *lifetime_rec = lifetime;
-+ }
-+
-+ if (mech_type != NULL) {
-+ major = gssEapCanonicalizeOid(minor, ctx->mechanismUsed, 0, mech_type);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (ctx_flags != NULL) {
-+ *ctx_flags = ctx->gssFlags;
-+ }
-+
-+ if (locally_initiated != NULL) {
-+ *locally_initiated = CTX_IS_INITIATOR(ctx);
-+ }
-+
-+ if (open != NULL) {
-+ *open = CTX_IS_ESTABLISHED(ctx);
-+ }
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ if (GSS_ERROR(major)) {
-+ gssEapReleaseName(&tmpMinor, src_name);
-+ gssEapReleaseName(&tmpMinor, targ_name);
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_cred.c b/mech_eap/inquire_cred.c
-new file mode 100644
-index 0000000..227ab16
---- /dev/null
-+++ b/mech_eap/inquire_cred.c
-@@ -0,0 +1,61 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return credential handle properties.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_cred(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_name_t *name,
-+ OM_uint32 *pLifetime,
-+ gss_cred_usage_t *cred_usage,
-+ gss_OID_set *mechanisms)
-+{
-+ OM_uint32 major;
-+
-+ if (cred == NULL) {
-+ *minor = EINVAL;
-+ return GSS_S_NO_CRED;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ major = gssEapInquireCred(minor, cred, name, pLifetime, cred_usage, mechanisms);
-+
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_cred_by_mech.c b/mech_eap/inquire_cred_by_mech.c
-new file mode 100644
-index 0000000..191902d
---- /dev/null
-+++ b/mech_eap/inquire_cred_by_mech.c
-@@ -0,0 +1,76 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return credential handle properties.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_cred_by_mech(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_OID mech_type,
-+ gss_name_t *name,
-+ OM_uint32 *pInitiatorLifetime,
-+ OM_uint32 *pAcceptorLifetime,
-+ gss_cred_usage_t *cred_usage)
-+{
-+ OM_uint32 major, lifetime;
-+
-+ if (cred == NULL) {
-+ *minor = EINVAL;
-+ return GSS_S_NO_CRED;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ if (!gssEapCredAvailable(cred, mech_type)) {
-+ major = GSS_S_BAD_MECH;
-+ *minor = GSSEAP_CRED_MECH_MISMATCH;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapInquireCred(minor, cred, name, &lifetime, cred_usage, NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (pInitiatorLifetime != NULL)
-+ *pInitiatorLifetime = (cred->flags & CRED_FLAG_INITIATE) ? lifetime : 0;
-+ if (pAcceptorLifetime != NULL)
-+ *pAcceptorLifetime = (cred->flags & CRED_FLAG_ACCEPT) ? lifetime : 0;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_cred_by_oid.c b/mech_eap/inquire_cred_by_oid.c
-new file mode 100644
-index 0000000..2ad34ed
---- /dev/null
-+++ b/mech_eap/inquire_cred_by_oid.c
-@@ -0,0 +1,83 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return extended credential handle properties.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#if 0
-+static struct {
-+ gss_OID_desc oid;
-+ OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t,
-+ const gss_OID, gss_buffer_set_t *);
-+} inquireCredOps[] = {
-+};
-+#endif
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_cred_by_oid(OM_uint32 *minor,
-+ const gss_cred_id_t cred_handle,
-+ const gss_OID desired_object GSSEAP_UNUSED,
-+ gss_buffer_set_t *data_set)
-+{
-+ OM_uint32 major;
-+#if 0
-+ int i;
-+#endif
-+ *data_set = GSS_C_NO_BUFFER_SET;
-+
-+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&cred_handle->mutex);
-+
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_BAD_CRED_OPTION;
-+
-+#if 0
-+ for (i = 0; i < sizeof(inquireCredOps) / sizeof(inquireCredOps[0]); i++) {
-+ if (oidEqual(&inquireCredOps[i].oid, desired_object)) {
-+ major = (*inquireCredOps[i].inquire)(minor, cred_handle,
-+ desired_object, data_set);
-+ break;
-+ }
-+ }
-+#endif
-+
-+ GSSEAP_MUTEX_UNLOCK(&cred_handle->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_mech_for_saslname.c b/mech_eap/inquire_mech_for_saslname.c
-new file mode 100644
-index 0000000..bd518c0
---- /dev/null
-+++ b/mech_eap/inquire_mech_for_saslname.c
-@@ -0,0 +1,84 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Map mechanism OID to a SASL mechanism name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_saslname_for_mech(OM_uint32 *minor,
-+ const gss_OID mech,
-+ gss_buffer_t sasl_mech_name,
-+ gss_buffer_t mech_name,
-+ gss_buffer_t mech_description)
-+{
-+ OM_uint32 major;
-+ gss_buffer_t name;
-+ krb5_enctype etype = ENCTYPE_NULL;
-+
-+ /* Dynamically construct mechanism name from Kerberos string enctype */
-+ major = gssEapOidToEnctype(minor, mech, &etype);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (mech_name != GSS_C_NO_BUFFER) {
-+ krb5_context krbContext;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ *minor = krbEnctypeToString(krbContext, etype, "eap-", mech_name);
-+ if (*minor != 0)
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (mech_description != GSS_C_NO_BUFFER) {
-+ major = makeStringBuffer(minor,
-+ "Extensible Authentication Protocol GSS-API Mechanism",
-+ mech_description);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ if (sasl_mech_name != GSS_C_NO_BUFFER) {
-+ name = gssEapOidToSaslName(mech);
-+ if (name == GSS_C_NO_BUFFER) {
-+ major = GSS_S_BAD_MECH;
-+ *minor = GSSEAP_WRONG_MECH;
-+ } else {
-+ major = duplicateBuffer(minor, name, sasl_mech_name);
-+ }
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_mechs_for_name.c b/mech_eap/inquire_mechs_for_name.c
-new file mode 100644
-index 0000000..89c869c
---- /dev/null
-+++ b/mech_eap/inquire_mechs_for_name.c
-@@ -0,0 +1,69 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Determine mechanism OIDs supported by name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_mechs_for_name(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ gss_OID_set *mech_types)
-+{
-+ OM_uint32 major, tmpMinor;
-+
-+ *minor = 0;
-+ *mech_types = GSS_C_NO_OID_SET;
-+
-+ if (input_name != GSS_C_NO_NAME &&
-+ input_name->mechanismUsed != GSS_C_NO_OID) {
-+ major = gss_create_empty_oid_set(minor, mech_types);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ major = gss_add_oid_set_member(minor,
-+ input_name->mechanismUsed,
-+ mech_types);
-+ if (GSS_ERROR(major)) {
-+ gss_release_oid_set(&tmpMinor, mech_types);
-+ return major;
-+ }
-+ } else {
-+ major = gssEapIndicateMechs(minor, mech_types);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_name.c b/mech_eap/inquire_name.c
-new file mode 100644
-index 0000000..78b08a0
---- /dev/null
-+++ b/mech_eap/inquire_name.c
-@@ -0,0 +1,75 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Enumerate name attributes.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_name(OM_uint32 *minor,
-+ gss_name_t name,
-+ int *name_is_MN,
-+ gss_OID *MN_mech,
-+ gss_buffer_set_t *attrs)
-+{
-+ OM_uint32 major, tmpMinor;
-+
-+ *minor = 0;
-+
-+ if (name_is_MN != NULL)
-+ *name_is_MN = 0;
-+ if (MN_mech != NULL)
-+ *MN_mech = GSS_C_NO_OID;
-+ if (attrs != NULL)
-+ *attrs = GSS_C_NO_BUFFER_SET;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ if (attrs == NULL)
-+ return GSS_S_COMPLETE;
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapInquireName(minor, name, name_is_MN, MN_mech, attrs);
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ if (GSS_ERROR(major))
-+ gss_release_buffer_set(&tmpMinor, attrs);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_names_for_mech.c b/mech_eap/inquire_names_for_mech.c
-new file mode 100644
-index 0000000..0e60340
---- /dev/null
-+++ b/mech_eap/inquire_names_for_mech.c
-@@ -0,0 +1,77 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return supported name OID types.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_names_for_mech(OM_uint32 *minor,
-+ gss_OID mechanism,
-+ gss_OID_set *ret_name_types)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_OID nameTypes[] = {
-+ GSS_C_NT_USER_NAME,
-+ GSS_C_NT_HOSTBASED_SERVICE,
-+ GSS_C_NT_EXPORT_NAME,
-+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
-+ GSS_C_NT_COMPOSITE_EXPORT,
-+#endif
-+ GSS_EAP_NT_EAP_NAME,
-+ GSS_C_NT_ANONYMOUS,
-+ };
-+ size_t i;
-+
-+ if (!gssEapIsMechanismOid(mechanism)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ major = gss_create_empty_oid_set(minor, ret_name_types);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) {
-+ major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gss_release_oid_set(&tmpMinor, ret_name_types);
-+
-+ return major;
-+}
-diff --git a/mech_eap/inquire_saslname_for_mech.c b/mech_eap/inquire_saslname_for_mech.c
-new file mode 100644
-index 0000000..d6d7c14
---- /dev/null
-+++ b/mech_eap/inquire_saslname_for_mech.c
-@@ -0,0 +1,51 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Map SASL mechanism name to a mechanism OID.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_mech_for_saslname(OM_uint32 *minor,
-+ const gss_buffer_t sasl_mech_name,
-+ gss_OID *mech_type)
-+{
-+ *mech_type = gssEapSaslNameToOid(sasl_mech_name);
-+ if (*mech_type == GSS_C_NO_OID) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/inquire_sec_context_by_oid.c b/mech_eap/inquire_sec_context_by_oid.c
-new file mode 100644
-index 0000000..7435f2e
---- /dev/null
-+++ b/mech_eap/inquire_sec_context_by_oid.c
-@@ -0,0 +1,248 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Return extended properties of a context handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static OM_uint32
-+addEnctypeOidToBufferSet(OM_uint32 *minor,
-+ krb5_enctype encryptionType,
-+ gss_buffer_set_t *dataSet)
-+{
-+ OM_uint32 major;
-+ unsigned char oidBuf[16];
-+ gss_OID_desc oid;
-+ gss_buffer_desc buf;
-+
-+ oid.length = sizeof(oidBuf);
-+ oid.elements = oidBuf;
-+
-+ major = composeOid(minor,
-+ "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
-+ 10,
-+ encryptionType,
-+ &oid);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ buf.length = oid.length;
-+ buf.value = oid.elements;
-+
-+ major = gss_add_buffer_set_member(minor, &buf, dataSet);
-+
-+ return major;
-+}
-+
-+static void
-+zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_buffer_set_t set = *dataSet;
-+ size_t i;
-+
-+ if (set == GSS_C_NO_BUFFER_SET)
-+ return;
-+
-+ for (i = 0; i <set->count; i++)
-+ memset(set->elements[i].value, 0, set->elements[i].length);
-+
-+ gss_release_buffer_set(&tmpMinor, dataSet);
-+}
-+
-+static OM_uint32
-+inquireSessionKey(OM_uint32 *minor,
-+ const gss_ctx_id_t ctx,
-+ const gss_OID desired_object GSSEAP_UNUSED,
-+ gss_buffer_set_t *dataSet)
-+{
-+ OM_uint32 major;
-+ gss_buffer_desc buf;
-+
-+ if (ctx->encryptionType == ENCTYPE_NULL) {
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+
-+ buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
-+ buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
-+
-+ major = gss_add_buffer_set_member(minor, &buf, dataSet);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ zeroAndReleaseBufferSet(dataSet);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+inquireNegoExKey(OM_uint32 *minor,
-+ const gss_ctx_id_t ctx,
-+ const gss_OID desired_object,
-+ gss_buffer_set_t *dataSet)
-+{
-+ OM_uint32 major, tmpMinor;
-+ int bInitiatorKey;
-+ gss_buffer_desc salt;
-+ gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
-+ size_t keySize;
-+
-+ bInitiatorKey = CTX_IS_INITIATOR(ctx);
-+
-+ if (ctx->encryptionType == ENCTYPE_NULL) {
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+
-+ /*
-+ * If the caller supplied the verify key OID, then we need the acceptor
-+ * key if we are the initiator, and vice versa.
-+ */
-+ if (desired_object->length == 11 &&
-+ memcmp(desired_object->elements,
-+ "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
-+ bInitiatorKey ^= 1;
-+
-+ if (bInitiatorKey) {
-+ salt.length = NEGOEX_INITIATOR_SALT_LEN;
-+ salt.value = NEGOEX_INITIATOR_SALT;
-+ } else {
-+ salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
-+ salt.value = NEGOEX_ACCEPTOR_SALT;
-+ }
-+
-+ keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
-+
-+ major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
-+ keySize, &key);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gss_add_buffer_set_member(minor, &key, dataSet);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (key.value != NULL) {
-+ memset(key.value, 0, key.length);
-+ gss_release_buffer(&tmpMinor, &key);
-+ }
-+ if (GSS_ERROR(major))
-+ zeroAndReleaseBufferSet(dataSet);
-+
-+ return major;
-+}
-+
-+static struct {
-+ gss_OID_desc oid;
-+ OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t,
-+ const gss_OID, gss_buffer_set_t *);
-+} inquireCtxOps[] = {
-+ {
-+ /* GSS_C_INQ_SSPI_SESSION_KEY */
-+ { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
-+ inquireSessionKey
-+ },
-+ {
-+ /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
-+ { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
-+ gssEapExportLucidSecContext
-+ },
-+ {
-+ /* GSS_C_INQ_NEGOEX_KEY */
-+ { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
-+ inquireNegoExKey
-+ },
-+ {
-+ /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
-+ { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
-+ inquireNegoExKey
-+ },
-+};
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_inquire_sec_context_by_oid(OM_uint32 *minor,
-+ const gss_ctx_id_t ctx,
-+ const gss_OID desired_object,
-+ gss_buffer_set_t *data_set)
-+{
-+ OM_uint32 major;
-+ int i;
-+
-+ *data_set = GSS_C_NO_BUFFER_SET;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+#if 0
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ major = GSS_S_NO_CONTEXT;
-+ goto cleanup;
-+ }
-+#endif
-+
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_BAD_CONTEXT_OPTION;
-+
-+ for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
-+ if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
-+ major = (*inquireCtxOps[i].inquire)(minor, ctx,
-+ desired_object, data_set);
-+ break;
-+ }
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/install-sh b/mech_eap/install-sh
-new file mode 100755
-index 0000000..6781b98
---- /dev/null
-+++ b/mech_eap/install-sh
-@@ -0,0 +1,520 @@
-+#!/bin/sh
-+# install - install a program, script, or datafile
-+
-+scriptversion=2009-04-28.21; # UTC
-+
-+# This originates from X11R5 (mit/util/scripts/install.sh), which was
-+# later released in X11R6 (xc/config/util/install.sh) with the
-+# following copyright and license.
-+#
-+# Copyright (C) 1994 X Consortium
-+#
-+# 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
-+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+#
-+# Except as contained in this notice, the name of the X Consortium shall not
-+# be used in advertising or otherwise to promote the sale, use or other deal-
-+# ings in this Software without prior written authorization from the X Consor-
-+# tium.
-+#
-+#
-+# FSF changes to this file are in the public domain.
-+#
-+# Calling this script install-sh is preferred over install.sh, to prevent
-+# `make' implicit rules from creating a file called install from it
-+# when there is no Makefile.
-+#
-+# This script is compatible with the BSD install script, but was written
-+# from scratch.
-+
-+nl='
-+'
-+IFS=" "" $nl"
-+
-+# set DOITPROG to echo to test this script
-+
-+# Don't use :- since 4.3BSD and earlier shells don't like it.
-+doit=${DOITPROG-}
-+if test -z "$doit"; then
-+ doit_exec=exec
-+else
-+ doit_exec=$doit
-+fi
-+
-+# Put in absolute file names if you don't have them in your path;
-+# or use environment vars.
-+
-+chgrpprog=${CHGRPPROG-chgrp}
-+chmodprog=${CHMODPROG-chmod}
-+chownprog=${CHOWNPROG-chown}
-+cmpprog=${CMPPROG-cmp}
-+cpprog=${CPPROG-cp}
-+mkdirprog=${MKDIRPROG-mkdir}
-+mvprog=${MVPROG-mv}
-+rmprog=${RMPROG-rm}
-+stripprog=${STRIPPROG-strip}
-+
-+posix_glob='?'
-+initialize_posix_glob='
-+ test "$posix_glob" != "?" || {
-+ if (set -f) 2>/dev/null; then
-+ posix_glob=
-+ else
-+ posix_glob=:
-+ fi
-+ }
-+'
-+
-+posix_mkdir=
-+
-+# Desired mode of installed file.
-+mode=0755
-+
-+chgrpcmd=
-+chmodcmd=$chmodprog
-+chowncmd=
-+mvcmd=$mvprog
-+rmcmd="$rmprog -f"
-+stripcmd=
-+
-+src=
-+dst=
-+dir_arg=
-+dst_arg=
-+
-+copy_on_change=false
-+no_target_directory=
-+
-+usage="\
-+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
-+ or: $0 [OPTION]... SRCFILES... DIRECTORY
-+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
-+ or: $0 [OPTION]... -d DIRECTORIES...
-+
-+In the 1st form, copy SRCFILE to DSTFILE.
-+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-+In the 4th, create DIRECTORIES.
-+
-+Options:
-+ --help display this help and exit.
-+ --version display version info and exit.
-+
-+ -c (ignored)
-+ -C install only if different (preserve the last data modification time)
-+ -d create directories instead of installing files.
-+ -g GROUP $chgrpprog installed files to GROUP.
-+ -m MODE $chmodprog installed files to MODE.
-+ -o USER $chownprog installed files to USER.
-+ -s $stripprog installed files.
-+ -t DIRECTORY install into DIRECTORY.
-+ -T report an error if DSTFILE is a directory.
-+
-+Environment variables override the default commands:
-+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
-+ RMPROG STRIPPROG
-+"
-+
-+while test $# -ne 0; do
-+ case $1 in
-+ -c) ;;
-+
-+ -C) copy_on_change=true;;
-+
-+ -d) dir_arg=true;;
-+
-+ -g) chgrpcmd="$chgrpprog $2"
-+ shift;;
-+
-+ --help) echo "$usage"; exit $?;;
-+
-+ -m) mode=$2
-+ case $mode in
-+ *' '* | *' '* | *'
-+'* | *'*'* | *'?'* | *'['*)
-+ echo "$0: invalid mode: $mode" >&2
-+ exit 1;;
-+ esac
-+ shift;;
-+
-+ -o) chowncmd="$chownprog $2"
-+ shift;;
-+
-+ -s) stripcmd=$stripprog;;
-+
-+ -t) dst_arg=$2
-+ shift;;
-+
-+ -T) no_target_directory=true;;
-+
-+ --version) echo "$0 $scriptversion"; exit $?;;
-+
-+ --) shift
-+ break;;
-+
-+ -*) echo "$0: invalid option: $1" >&2
-+ exit 1;;
-+
-+ *) break;;
-+ esac
-+ shift
-+done
-+
-+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
-+ # When -d is used, all remaining arguments are directories to create.
-+ # When -t is used, the destination is already specified.
-+ # Otherwise, the last argument is the destination. Remove it from $@.
-+ for arg
-+ do
-+ if test -n "$dst_arg"; then
-+ # $@ is not empty: it contains at least $arg.
-+ set fnord "$@" "$dst_arg"
-+ shift # fnord
-+ fi
-+ shift # arg
-+ dst_arg=$arg
-+ done
-+fi
-+
-+if test $# -eq 0; then
-+ if test -z "$dir_arg"; then
-+ echo "$0: no input file specified." >&2
-+ exit 1
-+ fi
-+ # It's OK to call `install-sh -d' without argument.
-+ # This can happen when creating conditional directories.
-+ exit 0
-+fi
-+
-+if test -z "$dir_arg"; then
-+ trap '(exit $?); exit' 1 2 13 15
-+
-+ # Set umask so as not to create temps with too-generous modes.
-+ # However, 'strip' requires both read and write access to temps.
-+ case $mode in
-+ # Optimize common cases.
-+ *644) cp_umask=133;;
-+ *755) cp_umask=22;;
-+
-+ *[0-7])
-+ if test -z "$stripcmd"; then
-+ u_plus_rw=
-+ else
-+ u_plus_rw='% 200'
-+ fi
-+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
-+ *)
-+ if test -z "$stripcmd"; then
-+ u_plus_rw=
-+ else
-+ u_plus_rw=,u+rw
-+ fi
-+ cp_umask=$mode$u_plus_rw;;
-+ esac
-+fi
-+
-+for src
-+do
-+ # Protect names starting with `-'.
-+ case $src in
-+ -*) src=./$src;;
-+ esac
-+
-+ if test -n "$dir_arg"; then
-+ dst=$src
-+ dstdir=$dst
-+ test -d "$dstdir"
-+ dstdir_status=$?
-+ else
-+
-+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
-+ # might cause directories to be created, which would be especially bad
-+ # if $src (and thus $dsttmp) contains '*'.
-+ if test ! -f "$src" && test ! -d "$src"; then
-+ echo "$0: $src does not exist." >&2
-+ exit 1
-+ fi
-+
-+ if test -z "$dst_arg"; then
-+ echo "$0: no destination specified." >&2
-+ exit 1
-+ fi
-+
-+ dst=$dst_arg
-+ # Protect names starting with `-'.
-+ case $dst in
-+ -*) dst=./$dst;;
-+ esac
-+
-+ # If destination is a directory, append the input filename; won't work
-+ # if double slashes aren't ignored.
-+ if test -d "$dst"; then
-+ if test -n "$no_target_directory"; then
-+ echo "$0: $dst_arg: Is a directory" >&2
-+ exit 1
-+ fi
-+ dstdir=$dst
-+ dst=$dstdir/`basename "$src"`
-+ dstdir_status=0
-+ else
-+ # Prefer dirname, but fall back on a substitute if dirname fails.
-+ dstdir=`
-+ (dirname "$dst") 2>/dev/null ||
-+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-+ X"$dst" : 'X\(//\)[^/]' \| \
-+ X"$dst" : 'X\(//\)$' \| \
-+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
-+ echo X"$dst" |
-+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-+ s//\1/
-+ q
-+ }
-+ /^X\(\/\/\)[^/].*/{
-+ s//\1/
-+ q
-+ }
-+ /^X\(\/\/\)$/{
-+ s//\1/
-+ q
-+ }
-+ /^X\(\/\).*/{
-+ s//\1/
-+ q
-+ }
-+ s/.*/./; q'
-+ `
-+
-+ test -d "$dstdir"
-+ dstdir_status=$?
-+ fi
-+ fi
-+
-+ obsolete_mkdir_used=false
-+
-+ if test $dstdir_status != 0; then
-+ case $posix_mkdir in
-+ '')
-+ # Create intermediate dirs using mode 755 as modified by the umask.
-+ # This is like FreeBSD 'install' as of 1997-10-28.
-+ umask=`umask`
-+ case $stripcmd.$umask in
-+ # Optimize common cases.
-+ *[2367][2367]) mkdir_umask=$umask;;
-+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-+
-+ *[0-7])
-+ mkdir_umask=`expr $umask + 22 \
-+ - $umask % 100 % 40 + $umask % 20 \
-+ - $umask % 10 % 4 + $umask % 2
-+ `;;
-+ *) mkdir_umask=$umask,go-w;;
-+ esac
-+
-+ # With -d, create the new directory with the user-specified mode.
-+ # Otherwise, rely on $mkdir_umask.
-+ if test -n "$dir_arg"; then
-+ mkdir_mode=-m$mode
-+ else
-+ mkdir_mode=
-+ fi
-+
-+ posix_mkdir=false
-+ case $umask in
-+ *[123567][0-7][0-7])
-+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
-+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-+ ;;
-+ *)
-+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-+
-+ if (umask $mkdir_umask &&
-+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
-+ then
-+ if test -z "$dir_arg" || {
-+ # Check for POSIX incompatibilities with -m.
-+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-+ # other-writeable bit of parent directory when it shouldn't.
-+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
-+ case $ls_ld_tmpdir in
-+ d????-?r-*) different_mode=700;;
-+ d????-?--*) different_mode=755;;
-+ *) false;;
-+ esac &&
-+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
-+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
-+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-+ }
-+ }
-+ then posix_mkdir=:
-+ fi
-+ rmdir "$tmpdir/d" "$tmpdir"
-+ else
-+ # Remove any dirs left behind by ancient mkdir implementations.
-+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
-+ fi
-+ trap '' 0;;
-+ esac;;
-+ esac
-+
-+ if
-+ $posix_mkdir && (
-+ umask $mkdir_umask &&
-+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
-+ )
-+ then :
-+ else
-+
-+ # The umask is ridiculous, or mkdir does not conform to POSIX,
-+ # or it failed possibly due to a race condition. Create the
-+ # directory the slow way, step by step, checking for races as we go.
-+
-+ case $dstdir in
-+ /*) prefix='/';;
-+ -*) prefix='./';;
-+ *) prefix='';;
-+ esac
-+
-+ eval "$initialize_posix_glob"
-+
-+ oIFS=$IFS
-+ IFS=/
-+ $posix_glob set -f
-+ set fnord $dstdir
-+ shift
-+ $posix_glob set +f
-+ IFS=$oIFS
-+
-+ prefixes=
-+
-+ for d
-+ do
-+ test -z "$d" && continue
-+
-+ prefix=$prefix$d
-+ if test -d "$prefix"; then
-+ prefixes=
-+ else
-+ if $posix_mkdir; then
-+ (umask=$mkdir_umask &&
-+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
-+ # Don't fail if two instances are running concurrently.
-+ test -d "$prefix" || exit 1
-+ else
-+ case $prefix in
-+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
-+ *) qprefix=$prefix;;
-+ esac
-+ prefixes="$prefixes '$qprefix'"
-+ fi
-+ fi
-+ prefix=$prefix/
-+ done
-+
-+ if test -n "$prefixes"; then
-+ # Don't fail if two instances are running concurrently.
-+ (umask $mkdir_umask &&
-+ eval "\$doit_exec \$mkdirprog $prefixes") ||
-+ test -d "$dstdir" || exit 1
-+ obsolete_mkdir_used=true
-+ fi
-+ fi
-+ fi
-+
-+ if test -n "$dir_arg"; then
-+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
-+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
-+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
-+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
-+ else
-+
-+ # Make a couple of temp file names in the proper directory.
-+ dsttmp=$dstdir/_inst.$$_
-+ rmtmp=$dstdir/_rm.$$_
-+
-+ # Trap to clean up those temp files at exit.
-+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
-+
-+ # Copy the file name to the temp name.
-+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
-+
-+ # and set any options; do chmod last to preserve setuid bits.
-+ #
-+ # If any of these fail, we abort the whole thing. If we want to
-+ # ignore errors from any of these, just make sure not to ignore
-+ # errors from the above "$doit $cpprog $src $dsttmp" command.
-+ #
-+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
-+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
-+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
-+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-+
-+ # If -C, don't bother to copy if it wouldn't change the file.
-+ if $copy_on_change &&
-+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
-+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
-+
-+ eval "$initialize_posix_glob" &&
-+ $posix_glob set -f &&
-+ set X $old && old=:$2:$4:$5:$6 &&
-+ set X $new && new=:$2:$4:$5:$6 &&
-+ $posix_glob set +f &&
-+
-+ test "$old" = "$new" &&
-+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
-+ then
-+ rm -f "$dsttmp"
-+ else
-+ # Rename the file to the real destination.
-+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-+
-+ # The rename failed, perhaps because mv can't rename something else
-+ # to itself, or perhaps because mv is so ancient that it does not
-+ # support -f.
-+ {
-+ # Now remove or move aside any old file at destination location.
-+ # We try this two ways since rm can't unlink itself on some
-+ # systems and the destination file might be busy for other
-+ # reasons. In this case, the final cleanup might fail but the new
-+ # file should still install successfully.
-+ {
-+ test ! -f "$dst" ||
-+ $doit $rmcmd -f "$dst" 2>/dev/null ||
-+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
-+ } ||
-+ { echo "$0: cannot unlink or rename $dst" >&2
-+ (exit 1); exit 1
-+ }
-+ } &&
-+
-+ # Now rename the file to the real destination.
-+ $doit $mvcmd "$dsttmp" "$dst"
-+ }
-+ fi || exit 1
-+
-+ trap '' 0
-+ fi
-+done
-+
-+# Local variables:
-+# eval: (add-hook 'write-file-hooks 'time-stamp)
-+# time-stamp-start: "scriptversion="
-+# time-stamp-format: "%:y-%02m-%02d.%02H"
-+# time-stamp-time-zone: "UTC"
-+# time-stamp-end: "; # UTC"
-+# End:
-diff --git a/mech_eap/map_name_to_any.c b/mech_eap/map_name_to_any.c
-new file mode 100644
-index 0000000..2a8a96c
---- /dev/null
-+++ b/mech_eap/map_name_to_any.c
-@@ -0,0 +1,58 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_map_name_to_any(OM_uint32 *minor,
-+ gss_name_t name,
-+ int authenticated,
-+ gss_buffer_t type_id,
-+ gss_any_t *output)
-+{
-+ OM_uint32 major;
-+
-+ *output = (gss_any_t)NULL;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapMapNameToAny(minor, name, authenticated, type_id, output);
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/mech b/mech_eap/mech
-new file mode 100644
-index 0000000..258a43a
---- /dev/null
-+++ b/mech_eap/mech
-@@ -0,0 +1,8 @@
-+#
-+# Sample mechanism glue configuration for EAP GSS mechanism.
-+#
-+# Any encryption type supported by Kerberos can be defined as the
-+# last element of the OID arc.
-+#
-+eap-aes128 1.3.6.1.4.1.5322.22.1.17 mech_eap.so
-+eap-aes256 1.3.6.1.4.1.5322.22.1.18 mech_eap.so
-diff --git a/mech_eap/mech_eap-noacceptor.exports b/mech_eap/mech_eap-noacceptor.exports
-new file mode 100644
-index 0000000..f00df8a
---- /dev/null
-+++ b/mech_eap/mech_eap-noacceptor.exports
-@@ -0,0 +1,55 @@
-+gss_acquire_cred
-+gss_add_cred
-+gss_add_cred_with_password
-+gss_canonicalize_name
-+gss_compare_name
-+gss_context_time
-+gss_delete_sec_context
-+gss_display_name
-+gss_display_name_ext
-+gss_display_status
-+gss_duplicate_name
-+gss_exchange_meta_data
-+gss_export_name
-+gss_export_sec_context
-+gss_get_mic
-+gss_import_name
-+gss_import_sec_context
-+gss_indicate_mechs
-+gss_init_sec_context
-+gss_inquire_attrs_for_mech
-+gss_inquire_context
-+gss_inquire_cred
-+gss_inquire_cred_by_mech
-+gss_inquire_cred_by_oid
-+gss_inquire_mechs_for_name
-+gss_inquire_mech_for_saslname
-+gss_inquire_names_for_mech
-+gss_inquire_saslname_for_mech
-+gss_inquire_sec_context_by_oid
-+gss_process_context_token
-+gss_pseudo_random
-+gss_query_mechanism_info
-+gss_query_meta_data
-+gss_release_cred
-+gss_release_name
-+gss_internal_release_oid
-+gss_set_sec_context_option
-+gss_store_cred
-+gss_unwrap
-+gss_unwrap_iov
-+gss_verify_mic
-+gss_wrap
-+gss_wrap_iov
-+gss_wrap_iov_length
-+gss_wrap_size_limit
-+GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
-+GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
-+GSS_EAP_NT_EAP_NAME
-+GSS_EAP_CRED_SET_CRED_FLAG
-+GSS_EAP_CRED_SET_CRED_PASSWORD
-+GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
-+GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
-+gssspi_acquire_cred_with_password
-+gssspi_authorize_localname
-+gssspi_set_cred_option
-diff --git a/mech_eap/mech_eap.exports b/mech_eap/mech_eap.exports
-new file mode 100644
-index 0000000..6a17a17
---- /dev/null
-+++ b/mech_eap/mech_eap.exports
-@@ -0,0 +1,63 @@
-+gss_accept_sec_context
-+gss_acquire_cred
-+gss_add_cred
-+gss_add_cred_with_password
-+gss_canonicalize_name
-+gss_compare_name
-+gss_context_time
-+gss_delete_name_attribute
-+gss_delete_sec_context
-+gss_display_name
-+gss_display_name_ext
-+gss_display_status
-+gss_duplicate_name
-+gss_exchange_meta_data
-+gss_export_name
-+gss_export_name_composite
-+gss_export_sec_context
-+gss_get_mic
-+gss_get_name_attribute
-+gss_import_name
-+gss_import_sec_context
-+gss_indicate_mechs
-+gss_init_sec_context
-+gss_inquire_attrs_for_mech
-+gss_inquire_context
-+gss_inquire_cred
-+gss_inquire_cred_by_mech
-+gss_inquire_cred_by_oid
-+gss_inquire_mechs_for_name
-+gss_inquire_mech_for_saslname
-+gss_inquire_name
-+gss_inquire_names_for_mech
-+gss_inquire_saslname_for_mech
-+gss_inquire_sec_context_by_oid
-+gss_map_name_to_any
-+gss_process_context_token
-+gss_pseudo_random
-+gss_query_mechanism_info
-+gss_query_meta_data
-+gss_release_any_name_mapping
-+gss_release_cred
-+gss_release_name
-+gss_internal_release_oid
-+gss_set_name_attribute
-+gss_set_sec_context_option
-+gss_store_cred
-+gss_unwrap
-+gss_unwrap_iov
-+gss_verify_mic
-+gss_wrap
-+gss_wrap_iov
-+gss_wrap_iov_length
-+gss_wrap_size_limit
-+GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
-+GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
-+GSS_EAP_NT_EAP_NAME
-+GSS_EAP_CRED_SET_CRED_FLAG
-+GSS_EAP_CRED_SET_CRED_PASSWORD
-+GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
-+GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
-+gssspi_acquire_cred_with_password
-+gssspi_authorize_localname
-+gssspi_set_cred_option
-diff --git a/mech_eap/mech_invoke.c b/mech_eap/mech_invoke.c
-new file mode 100644
-index 0000000..bc9bba3
---- /dev/null
-+++ b/mech_eap/mech_invoke.c
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gssspi_mech_invoke(OM_uint32 *minor,
-+ const gss_OID desired_mech,
-+ const gss_OID desired_object,
-+ gss_buffer_t value)
-+{
-+ *minor = GSSEAP_BAD_INVOCATION;
-+
-+ return GSS_S_UNAVAILABLE;
-+}
-diff --git a/mech_eap/process_context_token.c b/mech_eap/process_context_token.c
-new file mode 100644
-index 0000000..02a4b6d
---- /dev/null
-+++ b/mech_eap/process_context_token.c
-@@ -0,0 +1,71 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_process_context_token(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t token_buffer)
-+{
-+ OM_uint32 major;
-+ gss_iov_buffer_desc iov[1];
-+
-+ *minor = 0;
-+
-+ if (ctx == NULL) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ return GSS_S_NO_CONTEXT;
-+ }
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
-+ iov[0].buffer = *token_buffer;
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-+ iov, 1, TOK_TYPE_DELETE_CONTEXT);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ return major;
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return gssEapReleaseContext(minor, &ctx);
-+}
-diff --git a/mech_eap/pseudo_random.c b/mech_eap/pseudo_random.c
-new file mode 100644
-index 0000000..61d1f2a
---- /dev/null
-+++ b/mech_eap/pseudo_random.c
-@@ -0,0 +1,195 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * PRF
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+gssEapPseudoRandom(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int prf_key,
-+ const gss_buffer_t prf_in,
-+ ssize_t desired_output_len,
-+ gss_buffer_t prf_out)
-+{
-+ krb5_error_code code;
-+ int i;
-+ OM_uint32 tmpMinor;
-+ size_t prflen;
-+ krb5_data t, ns;
-+ unsigned char *p;
-+ krb5_context krbContext;
-+
-+ prf_out->length = 0;
-+ prf_out->value = NULL;
-+
-+ *minor = 0;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ KRB_DATA_INIT(&t);
-+ KRB_DATA_INIT(&ns);
-+
-+ if (prf_key != GSS_C_PRF_KEY_PARTIAL &&
-+ prf_key != GSS_C_PRF_KEY_FULL) {
-+ code = GSSEAP_BAD_PRF_KEY;
-+ goto cleanup;
-+ }
-+
-+ prf_out->value = GSSEAP_MALLOC(desired_output_len);
-+ if (prf_out->value == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+ prf_out->length = desired_output_len;
-+
-+ code = krb5_c_prf_length(krbContext,
-+ ctx->encryptionType,
-+ &prflen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ ns.length = 4 + prf_in->length;
-+ ns.data = GSSEAP_MALLOC(ns.length);
-+ if (ns.data == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+#ifndef HAVE_HEIMDAL_VERSION
-+ /* Same API, but different allocation rules, unfortunately. */
-+ t.length = prflen;
-+ t.data = GSSEAP_MALLOC(t.length);
-+ if (t.data == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+#endif
-+
-+ memcpy((unsigned char *)ns.data + 4, prf_in->value, prf_in->length);
-+ i = 0;
-+ p = (unsigned char *)prf_out->value;
-+ while (desired_output_len > 0) {
-+ store_uint32_be(i, ns.data);
-+
-+ code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &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(&tmpMinor, prf_out);
-+ if (ns.data != NULL) {
-+ memset(ns.data, 0, ns.length);
-+ GSSEAP_FREE(ns.data);
-+ }
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_free_data_contents(krbContext, &t);
-+#else
-+ if (t.data != NULL) {
-+ memset(t.data, 0, t.length);
-+ GSSEAP_FREE(t.data);
-+ }
-+#endif
-+
-+ *minor = code;
-+
-+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_pseudo_random(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int prf_key,
-+ const gss_buffer_t prf_in,
-+ ssize_t desired_output_len,
-+ gss_buffer_t prf_out)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ prf_out->length = 0;
-+ prf_out->value = NULL;
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (CTX_IS_ESTABLISHED(ctx)) {
-+ major = gssEapPseudoRandom(minor, ctx, prf_key,
-+ prf_in, desired_output_len, prf_out);
-+ } else {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/query_mechanism_info.c b/mech_eap/query_mechanism_info.c
-new file mode 100644
-index 0000000..acd3115
---- /dev/null
-+++ b/mech_eap/query_mechanism_info.c
-@@ -0,0 +1,67 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32
-+gssQueryMechanismInfo(OM_uint32 *minor,
-+ gss_const_OID mech_oid,
-+ unsigned char auth_scheme[16])
-+{
-+ OM_uint32 major;
-+ krb5_enctype enctype;
-+
-+ major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /* the enctype is encoded in the increasing part of the GUID */
-+ memcpy(auth_scheme,
-+ "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16);
-+
-+ auth_scheme[3] = (unsigned char)enctype;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_query_mechanism_info(OM_uint32 *minor,
-+ gss_const_OID mech_oid,
-+ unsigned char auth_scheme[16])
-+{
-+ return gssQueryMechanismInfo(minor, mech_oid, auth_scheme);
-+}
-diff --git a/mech_eap/query_meta_data.c b/mech_eap/query_meta_data.c
-new file mode 100644
-index 0000000..abc7e71
---- /dev/null
-+++ b/mech_eap/query_meta_data.c
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32
-+gssEapQueryMetaData(OM_uint32 *minor,
-+ gss_const_OID mech GSSEAP_UNUSED,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t *context_handle,
-+ const gss_name_t name,
-+ OM_uint32 req_flags GSSEAP_UNUSED,
-+ gss_buffer_t meta_data)
-+{
-+ OM_uint32 major = GSS_S_COMPLETE;
-+ int isInitiator = (name != GSS_C_NO_NAME);
-+ gss_ctx_id_t ctx = *context_handle;
-+
-+ meta_data->length = 0;
-+ meta_data->value = NULL;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ major = gssEapAllocContext(minor, &ctx);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (isInitiator)
-+ ctx->flags |= CTX_FLAG_INITIATOR;
-+ }
-+
-+ if (ctx->cred == GSS_C_NO_CREDENTIAL) {
-+ if (isInitiator) {
-+ major = gssEapResolveInitiatorCred(minor, cred,
-+ name, &ctx->cred);
-+ } else {
-+ major = gssEapAcquireCred(minor,
-+ GSS_C_NO_NAME,
-+ GSS_C_INDEFINITE,
-+ GSS_C_NO_OID_SET,
-+ GSS_C_ACCEPT,
-+ &ctx->cred,
-+ NULL,
-+ NULL);
-+ }
-+ }
-+
-+ if (*context_handle == GSS_C_NO_CONTEXT)
-+ *context_handle = ctx;
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_query_meta_data(OM_uint32 *minor,
-+ gss_const_OID mech,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t *context_handle,
-+ const gss_name_t name,
-+ OM_uint32 req_flags,
-+ gss_buffer_t meta_data)
-+{
-+ gss_ctx_id_t ctx = *context_handle;
-+ OM_uint32 major;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ if (*context_handle != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapQueryMetaData(minor, mech, cred, &ctx,
-+ name, req_flags, meta_data);
-+
-+ if (*context_handle != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+ else
-+ *context_handle = ctx;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL)
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/radius_ad.exports b/mech_eap/radius_ad.exports
-new file mode 100644
-index 0000000..8d5d5c4
---- /dev/null
-+++ b/mech_eap/radius_ad.exports
-@@ -0,0 +1 @@
-+authdata_client_0
-diff --git a/mech_eap/radsec.conf b/mech_eap/radsec.conf
-new file mode 100644
-index 0000000..27f895a
---- /dev/null
-+++ b/mech_eap/radsec.conf
-@@ -0,0 +1,12 @@
-+dictionary = "/usr/local/etc/raddb/dictionary"
-+
-+realm gss-eap {
-+ type = "UDP"
-+ timeout = 5
-+ retries = 3
-+ server {
-+ hostname = "localhost"
-+ service = "1812"
-+ secret = "testing123"
-+ }
-+}
-diff --git a/mech_eap/radsec_err.et b/mech_eap/radsec_err.et
-new file mode 100644
-index 0000000..3b7fae2
---- /dev/null
-+++ b/mech_eap/radsec_err.et
-@@ -0,0 +1,38 @@
-+#
-+# Copyright (c) 2011, JANET(UK)
-+# 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 JANET(UK) nor the names of its contributors
-+# may be used to endorse or promote products derived from this software
-+# without specific prior written permission.
-+#
-+# THIS SOFTWARE IS PROVIDED BY THE 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.
-+#
-+
-+# Placeholders only
-+error_table rse
-+
-+error_code GSSEAP_RSE_OK, ""
-+
-+end
-diff --git a/mech_eap/release_any_name_mapping.c b/mech_eap/release_any_name_mapping.c
-new file mode 100644
-index 0000000..d68fb45
---- /dev/null
-+++ b/mech_eap/release_any_name_mapping.c
-@@ -0,0 +1,59 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_release_any_name_mapping(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t type_id,
-+ gss_any_t *input)
-+{
-+ OM_uint32 major;
-+
-+ *minor = 0;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapReleaseAnyNameMapping(minor, name, type_id, input);
-+
-+ *input = NULL;
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/release_cred.c b/mech_eap/release_cred.c
-new file mode 100644
-index 0000000..8bb7e54
---- /dev/null
-+++ b/mech_eap/release_cred.c
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Release a credential handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_release_cred(OM_uint32 *minor,
-+ gss_cred_id_t *cred_handle)
-+{
-+ return gssEapReleaseCred(minor, cred_handle);
-+}
-diff --git a/mech_eap/release_name.c b/mech_eap/release_name.c
-new file mode 100644
-index 0000000..3d527ce
---- /dev/null
-+++ b/mech_eap/release_name.c
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Release a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_release_name(OM_uint32 *minor,
-+ gss_name_t *name)
-+{
-+ return gssEapReleaseName(minor, name);
-+}
-diff --git a/mech_eap/release_oid.c b/mech_eap/release_oid.c
-new file mode 100644
-index 0000000..291da40
---- /dev/null
-+++ b/mech_eap/release_oid.c
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Mark an internalized OID as not required to be released.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_internal_release_oid(OM_uint32 *minor,
-+ gss_OID *oid)
-+{
-+ return gssEapReleaseOid(minor, oid);
-+}
-diff --git a/mech_eap/set_cred_option.c b/mech_eap/set_cred_option.c
-new file mode 100644
-index 0000000..7bb9b7b
---- /dev/null
-+++ b/mech_eap/set_cred_option.c
-@@ -0,0 +1,208 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Set an extended property on a credential handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static OM_uint32
-+setCredRadiusConfigFile(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_OID oid GSSEAP_UNUSED,
-+ const gss_buffer_t buffer)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
-+
-+ if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
-+ major = duplicateBuffer(minor, buffer, &configFileBuffer);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
-+ cred->radiusConfigFile = configFileBuffer;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+setCredRadiusConfigStanza(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_OID oid GSSEAP_UNUSED,
-+ const gss_buffer_t buffer)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER;
-+
-+ if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
-+ major = duplicateBuffer(minor, buffer, &configStanzaBuffer);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
-+ cred->radiusConfigStanza = configStanzaBuffer;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+setCredFlag(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_OID oid GSSEAP_UNUSED,
-+ const gss_buffer_t buffer)
-+{
-+ OM_uint32 flags;
-+ unsigned char *p;
-+
-+ if (buffer == GSS_C_NO_BUFFER) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
-+ }
-+
-+ if (buffer->length < 4) {
-+ *minor = GSSEAP_WRONG_SIZE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ p = (unsigned char *)buffer->value;
-+
-+ flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK;
-+
-+ if (buffer->length > 4 && p[4])
-+ cred->flags &= ~(flags);
-+ else
-+ cred->flags |= flags;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+setCredPassword(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_OID oid GSSEAP_UNUSED,
-+ const gss_buffer_t buffer)
-+{
-+ return gssEapSetCredPassword(minor, cred, buffer);
-+}
-+
-+static struct {
-+ gss_OID_desc oid;
-+ OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
-+ const gss_OID, const gss_buffer_t);
-+} setCredOps[] = {
-+ /* 1.3.6.1.4.1.5322.22.3.3.1 */
-+ {
-+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" },
-+ setCredRadiusConfigFile,
-+ },
-+ /* 1.3.6.1.4.1.5322.22.3.3.2 */
-+ {
-+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" },
-+ setCredRadiusConfigStanza,
-+ },
-+ /* 1.3.6.1.4.1.5322.22.3.3.3 */
-+ {
-+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" },
-+ setCredFlag,
-+ },
-+ /* 1.3.6.1.4.1.5322.22.3.3.4 */
-+ {
-+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" },
-+ setCredPassword,
-+ },
-+};
-+
-+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid;
-+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA = &setCredOps[1].oid;
-+gss_OID GSS_EAP_CRED_SET_CRED_FLAG = &setCredOps[2].oid;
-+gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD = &setCredOps[3].oid;
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gssspi_set_cred_option(OM_uint32 *minor,
-+ gss_cred_id_t *pCred,
-+ const gss_OID desired_object,
-+ const gss_buffer_t value)
-+{
-+ OM_uint32 major;
-+ gss_cred_id_t cred = *pCred;
-+ int i;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL) {
-+ *minor = EINVAL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_BAD_CRED_OPTION;
-+
-+ for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
-+ if (oidEqual(&setCredOps[i].oid, desired_object)) {
-+ major = (*setCredOps[i].setOption)(minor, cred,
-+ desired_object, value);
-+ break;
-+ }
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-+
-+#if 0
-+OM_uint32
-+gsseap_set_cred_flag(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ OM_uint32 flag,
-+ int clear)
-+{
-+ unsigned char buf[5];
-+ gss_buffer_desc value;
-+
-+ value.length = sizeof(buf);
-+ value.value = buf;
-+
-+ store_uint32_be(flag, buf);
-+ buf[4] = (clear != 0);
-+
-+ return gssspi_set_cred_option(minor, &cred,
-+ GSS_EAP_CRED_SET_CRED_FLAG, &value);
-+}
-+#endif
-diff --git a/mech_eap/set_name_attribute.c b/mech_eap/set_name_attribute.c
-new file mode 100644
-index 0000000..2ccf5d7
---- /dev/null
-+++ b/mech_eap/set_name_attribute.c
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Set an attribute on a name.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_set_name_attribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ int complete,
-+ gss_buffer_t attr,
-+ gss_buffer_t value)
-+{
-+ OM_uint32 major;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&name->mutex);
-+
-+ major = gssEapSetNameAttribute(minor, name, complete, attr, value);
-+
-+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/set_sec_context_option.c b/mech_eap/set_sec_context_option.c
-new file mode 100644
-index 0000000..f9fa3a6
---- /dev/null
-+++ b/mech_eap/set_sec_context_option.c
-@@ -0,0 +1,87 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Set an extended property on a context handle.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#if 0
-+static struct {
-+ gss_OID_desc oid;
-+ OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx,
-+ const gss_OID, const gss_buffer_t);
-+} setCtxOps[] = {
-+};
-+#endif
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_set_sec_context_option(OM_uint32 *minor,
-+ gss_ctx_id_t *pCtx,
-+ const gss_OID desired_object GSSEAP_UNUSED,
-+ const gss_buffer_t value GSSEAP_UNUSED)
-+{
-+ OM_uint32 major;
-+ gss_ctx_id_t ctx;
-+#if 0
-+ int i;
-+#endif
-+
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_BAD_CONTEXT_OPTION;
-+
-+ if (pCtx == NULL)
-+ ctx = GSS_C_NO_CONTEXT;
-+ else
-+ ctx = *pCtx;
-+
-+ if (ctx != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+#if 0
-+ for (i = 0; i < sizeof(setCtxOps) / sizeof(setCtxOps[0]); i++) {
-+ if (oidEqual(&setCtxOps[i].oid, desired_object)) {
-+ major = (*setCtxOps[i].setOption)(minor, &ctx,
-+ desired_object, value);
-+ break;
-+ }
-+ }
-+#endif
-+
-+ if (pCtx != NULL && *pCtx == NULL)
-+ *pCtx = ctx;
-+ else if (ctx != GSS_C_NO_CONTEXT)
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/store_cred.c b/mech_eap/store_cred.c
-new file mode 100644
-index 0000000..d17a3ac
---- /dev/null
-+++ b/mech_eap/store_cred.c
-@@ -0,0 +1,83 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_store_cred(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ gss_cred_usage_t input_usage,
-+ const gss_OID desired_mech GSSEAP_UNUSED,
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ OM_uint32 overwrite_cred,
-+ OM_uint32 default_cred,
-+#else
-+ OM_uint32 overwrite_cred GSSEAP_UNUSED,
-+ OM_uint32 default_cred GSSEAP_UNUSED,
-+#endif
-+ gss_OID_set *elements_stored,
-+ gss_cred_usage_t *cred_usage_stored)
-+{
-+ OM_uint32 major;
-+
-+ if (elements_stored != NULL)
-+ *elements_stored = GSS_C_NO_OID_SET;
-+ if (cred_usage_stored != NULL)
-+ *cred_usage_stored = input_usage;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
-+ }
-+
-+ GSSEAP_MUTEX_LOCK(&cred->mutex);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ if (cred->reauthCred != GSS_C_NO_CREDENTIAL) {
-+ major = gssStoreCred(minor,
-+ cred->reauthCred,
-+ input_usage,
-+ (gss_OID)gss_mech_krb5,
-+ overwrite_cred,
-+ default_cred,
-+ elements_stored,
-+ cred_usage_stored);
-+ }
-+#endif
-+
-+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/unwrap.c b/mech_eap/unwrap.c
-new file mode 100644
-index 0000000..a185035
---- /dev/null
-+++ b/mech_eap/unwrap.c
-@@ -0,0 +1,85 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Message protection services: unwrap.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_unwrap(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t input_message_buffer,
-+ gss_buffer_t output_message_buffer,
-+ int *conf_state,
-+ gss_qop_t *qop_state)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_iov_buffer_desc iov[2];
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
-+ iov[0].buffer = *input_message_buffer;
-+
-+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-+ iov[1].buffer.value = NULL;
-+ iov[1].buffer.length = 0;
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
-+ iov, 2, TOK_TYPE_WRAP);
-+ if (major == GSS_S_COMPLETE) {
-+ *output_message_buffer = iov[1].buffer;
-+ } else {
-+ if (iov[1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED)
-+ gss_release_buffer(&tmpMinor, &iov[1].buffer);
-+ }
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/unwrap_iov.c b/mech_eap/unwrap_iov.c
-new file mode 100644
-index 0000000..5ceefa2
---- /dev/null
-+++ b/mech_eap/unwrap_iov.c
-@@ -0,0 +1,572 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Message protection services: unwrap with scatter-gather API.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/*
-+ * 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)
-+ */
-+OM_uint32
-+unwrapToken(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *unused GSSEAP_UNUSED,
-+#endif
-+ int *conf_state,
-+ gss_qop_t *qop_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype)
-+{
-+ OM_uint32 major = GSS_S_FAILURE, code;
-+ gss_iov_buffer_t header;
-+ gss_iov_buffer_t padding;
-+ gss_iov_buffer_t trailer;
-+ unsigned char flags;
-+ unsigned char *ptr = NULL;
-+ int keyUsage;
-+ size_t rrc, ec;
-+ size_t dataLen, assocDataLen;
-+ uint64_t seqnum;
-+ int valid = 0;
-+ int conf_flag = 0;
-+ krb5_context krbContext;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ int freeCrypto = (krbCrypto == NULL);
-+#endif
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ *minor = 0;
-+
-+ if (qop_state != NULL)
-+ *qop_state = GSS_C_QOP_DEFAULT;
-+
-+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
-+ GSSEAP_ASSERT(header != NULL);
-+
-+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
-+ if (padding != NULL && padding->buffer.length != 0) {
-+ code = GSSEAP_BAD_PADDING_IOV;
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ goto cleanup;
-+ }
-+
-+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
-+
-+ flags = rfc4121Flags(ctx, TRUE);
-+
-+ if (toktype == TOK_TYPE_WRAP) {
-+ keyUsage = !CTX_IS_INITIATOR(ctx)
-+ ? KEY_USAGE_INITIATOR_SEAL
-+ : KEY_USAGE_ACCEPTOR_SEAL;
-+ } else {
-+ keyUsage = !CTX_IS_INITIATOR(ctx)
-+ ? KEY_USAGE_INITIATOR_SIGN
-+ : KEY_USAGE_ACCEPTOR_SIGN;
-+ }
-+
-+ gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
-+
-+ ptr = (unsigned char *)header->buffer.value;
-+
-+ if (header->buffer.length < 16) {
-+ code = GSSEAP_TOK_TRUNC;
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ goto cleanup;
-+ }
-+
-+ if ((ptr[2] & flags) != flags) {
-+ code = GSSEAP_BAD_DIRECTION;
-+ major = GSS_S_BAD_SIG;
-+ goto cleanup;
-+ }
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (krbCrypto == NULL) {
-+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key,
-+ ETYPE_NULL, &krbCrypto);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+#endif
-+
-+ if (toktype == TOK_TYPE_WRAP) {
-+ size_t krbTrailerLen;
-+
-+ if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
-+ goto defective;
-+ conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
-+ if (ptr[3] != 0xFF)
-+ goto defective;
-+ ec = load_uint16_be(ptr + 4);
-+ rrc = load_uint16_be(ptr + 6);
-+ seqnum = load_uint64_be(ptr + 8);
-+
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
-+ KRB5_CRYPTO_TYPE_CHECKSUM,
-+ &krbTrailerLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ /* Deal with RRC */
-+ if (trailer == NULL) {
-+ size_t desired_rrc = krbTrailerLen;
-+
-+ if (conf_flag) {
-+ desired_rrc += 16; /* E(Header) */
-+
-+ if ((ctx->gssFlags & 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) {
-+ goto defective;
-+ }
-+
-+ if (conf_flag) {
-+ unsigned char *althdr;
-+
-+ /* Decrypt */
-+ code = gssEapDecrypt(krbContext,
-+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
-+ ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage,
-+ iov, iov_count);
-+ if (code != 0) {
-+ major = GSS_S_BAD_SIG;
-+ goto cleanup;
-+ }
-+
-+ /* Validate header integrity */
-+ if (trailer == NULL)
-+ althdr = (unsigned char *)header->buffer.value + 16 + ec;
-+ else
-+ althdr = (unsigned char *)trailer->buffer.value + ec;
-+
-+ if (load_uint16_be(althdr) != TOK_TYPE_WRAP
-+ || althdr[2] != ptr[2]
-+ || althdr[3] != ptr[3]
-+ || memcmp(althdr + 8, ptr + 8, 8) != 0) {
-+ code = GSSEAP_BAD_WRAP_TOKEN;
-+ major = GSS_S_BAD_SIG;
-+ goto cleanup;
-+ }
-+ } else {
-+ /* Verify checksum: note EC is checksum size here, not padding */
-+ if (ec != krbTrailerLen)
-+ goto defective;
-+
-+ /* Zero EC, RRC before computing checksum */
-+ store_uint16_be(0, ptr + 4);
-+ store_uint16_be(0, ptr + 6);
-+
-+ code = gssEapVerify(krbContext, ctx->checksumType, rrc,
-+ KRB_CRYPTO_CONTEXT(ctx), keyUsage,
-+ iov, iov_count, &valid);
-+ if (code != 0 || valid == FALSE) {
-+ major = GSS_S_BAD_SIG;
-+ goto cleanup;
-+ }
-+ }
-+
-+ code = sequenceCheck(minor, &ctx->seqState, seqnum);
-+ } else if (toktype == TOK_TYPE_MIC) {
-+ if (load_uint16_be(ptr) != toktype)
-+ goto defective;
-+
-+ verify_mic_1:
-+ if (ptr[3] != 0xFF)
-+ goto defective;
-+ seqnum = load_uint64_be(ptr + 8);
-+
-+ /*
-+ * Although MIC tokens don't have a RRC, they are similarly
-+ * composed of a header and a checksum. So the verify_mic()
-+ * can be implemented with a single header buffer, fake the
-+ * RRC to the putative trailer length if no trailer buffer.
-+ */
-+ code = gssEapVerify(krbContext, ctx->checksumType,
-+ trailer != NULL ? 0 : header->buffer.length - 16,
-+ KRB_CRYPTO_CONTEXT(ctx), keyUsage,
-+ iov, iov_count, &valid);
-+ if (code != 0 || valid == FALSE) {
-+ major = GSS_S_BAD_SIG;
-+ goto cleanup;
-+ }
-+ code = sequenceCheck(minor, &ctx->seqState, seqnum);
-+ } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
-+ if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
-+ goto defective;
-+ goto verify_mic_1;
-+ } else {
-+ goto defective;
-+ }
-+
-+ if (conf_state != NULL)
-+ *conf_state = conf_flag;
-+
-+ code = 0;
-+ major = GSS_S_COMPLETE;
-+ goto cleanup;
-+
-+defective:
-+ code = GSSEAP_BAD_WRAP_TOKEN;
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+
-+cleanup:
-+ *minor = code;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (freeCrypto && krbCrypto != NULL)
-+ krb5_crypto_destroy(krbContext, krbCrypto);
-+#endif
-+
-+ return major;
-+}
-+
-+int
-+rotateLeft(void *ptr, size_t bufsiz, size_t rc)
-+{
-+ void *tbuf;
-+
-+ if (bufsiz == 0)
-+ return 0;
-+ rc = rc % bufsiz;
-+ if (rc == 0)
-+ return 0;
-+
-+ tbuf = GSSEAP_MALLOC(rc);
-+ if (tbuf == NULL)
-+ return ENOMEM;
-+
-+ memcpy(tbuf, ptr, rc);
-+ memmove(ptr, (char *)ptr + rc, bufsiz - rc);
-+ memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
-+ GSSEAP_FREE(tbuf);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Split a STREAM | SIGN_DATA | DATA into
-+ * HEADER | SIGN_DATA | DATA | PADDING | TRAILER
-+ */
-+static OM_uint32
-+unwrapStream(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int *conf_state,
-+ gss_qop_t *qop_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype)
-+{
-+ unsigned char *ptr;
-+ OM_uint32 code = 0, major = GSS_S_FAILURE;
-+ krb5_context krbContext;
-+ int conf_req_flag;
-+ 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;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto = NULL;
-+#endif
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ GSSEAP_ASSERT(toktype == TOK_TYPE_WRAP);
-+
-+ if (toktype != TOK_TYPE_WRAP) {
-+ code = GSSEAP_WRONG_TOK_ID;
-+ goto cleanup;
-+ }
-+
-+ stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
-+ GSSEAP_ASSERT(stream != NULL);
-+
-+ if (stream->buffer.length < 16) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ goto cleanup;
-+ }
-+
-+ ptr = (unsigned char *)stream->buffer.value;
-+ ptr += 2; /* skip token type */
-+
-+ tiov = (gss_iov_buffer_desc *)GSSEAP_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 = 16;
-+
-+ /* 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 = GSSEAP_BAD_STREAM_IOV;
-+ 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 = GSSEAP_BAD_STREAM_IOV;
-+ 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;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
-+ if (code != 0)
-+ goto cleanup;
-+#endif
-+
-+ {
-+ size_t ec, rrc;
-+ size_t krbHeaderLen = 0;
-+ size_t krbTrailerLen = 0;
-+
-+ conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
-+ ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
-+ rrc = load_uint16_be(ptr + 4);
-+
-+ if (rrc != 0) {
-+ code = rotateLeft((unsigned char *)stream->buffer.value + 16,
-+ stream->buffer.length - 16, rrc);
-+ if (code != 0)
-+ goto cleanup;
-+ store_uint16_be(0, ptr + 4); /* set RRC to zero */
-+ }
-+
-+ if (conf_req_flag) {
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
-+ if (code != 0)
-+ goto cleanup;
-+ theader->buffer.length += krbHeaderLen; /* length validated later */
-+ }
-+
-+ /* no PADDING for CFX, EC is used instead */
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ conf_req_flag
-+ ? KRB5_CRYPTO_TYPE_TRAILER
-+ : KRB5_CRYPTO_TYPE_CHECKSUM,
-+ &krbTrailerLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) +
-+ krbTrailerLen;
-+ ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
-+ stream->buffer.length - ttrailer->buffer.length;
-+ }
-+
-+ /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
-+ /* 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) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ code = GSSEAP_TOK_TRUNC;
-+ goto cleanup;
-+ }
-+
-+ /* setup data */
-+ tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
-+ tpadding->buffer.length - theader->buffer.length;
-+
-+ GSSEAP_ASSERT(data != NULL);
-+
-+ if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
-+ code = gssEapAllocIov(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;
-+ }
-+
-+ GSSEAP_ASSERT(i <= iov_count + 2);
-+
-+ major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx),
-+ conf_state, qop_state, tiov, i, toktype);
-+ if (major == GSS_S_COMPLETE) {
-+ *data = *tdata;
-+ } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
-+ OM_uint32 tmp;
-+
-+ gss_release_buffer(&tmp, &tdata->buffer);
-+ tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
-+ }
-+
-+cleanup:
-+ if (tiov != NULL)
-+ GSSEAP_FREE(tiov);
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (krbCrypto != NULL)
-+ krb5_crypto_destroy(krbContext, krbCrypto);
-+#endif
-+
-+ *minor = code;
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int *conf_state,
-+ gss_qop_t *qop_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx->encryptionType == ENCTYPE_NULL) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
-+ major = unwrapStream(minor, ctx, conf_state, qop_state,
-+ iov, iov_count, toktype);
-+ } else {
-+ major = unwrapToken(minor, ctx,
-+ NULL, /* krbCrypto */
-+ conf_state, qop_state,
-+ iov, iov_count, toktype);
-+ }
-+
-+ return major;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_unwrap_iov(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int *conf_state,
-+ gss_qop_t *qop_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
-+ iov, iov_count, TOK_TYPE_WRAP);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/util.h b/mech_eap/util.h
-new file mode 100644
-index 0000000..4f54d41
---- /dev/null
-+++ b/mech_eap/util.h
-@@ -0,0 +1,1032 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * Portions Copyright 2003-2010 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.
-+ *
-+ */
-+
-+/*
-+ * Utility functions.
-+ */
-+
-+#ifndef _UTIL_H_
-+#define _UTIL_H_ 1
-+
-+#ifdef HAVE_SYS_PARAM_H
-+#include <sys/param.h>
-+#endif
-+#ifdef HAVE_STDINT_H
-+#include <stdint.h>
-+#endif
-+#include <string.h>
-+#include <errno.h>
-+
-+#include <krb5.h>
-+
-+#ifdef WIN32
-+#define inline __inline
-+#define snprintf _snprintf
-+#endif
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef MIN
-+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
-+#endif
-+
-+#if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-+#define GSSEAP_UNUSED __attribute__ ((__unused__))
-+#else
-+#define GSSEAP_UNUSED
-+#endif
-+
-+/* util_buffer.c */
-+OM_uint32
-+makeStringBuffer(OM_uint32 *minor,
-+ const char *string,
-+ gss_buffer_t buffer);
-+
-+#define makeStringBufferOrCleanup(src, dst) \
-+ do { \
-+ major = makeStringBuffer((minor), (src), (dst));\
-+ if (GSS_ERROR(major)) \
-+ goto cleanup; \
-+ } while (0)
-+
-+OM_uint32
-+bufferToString(OM_uint32 *minor,
-+ const gss_buffer_t buffer,
-+ char **pString);
-+
-+OM_uint32
-+duplicateBuffer(OM_uint32 *minor,
-+ const gss_buffer_t src,
-+ gss_buffer_t dst);
-+
-+#define duplicateBufferOrCleanup(src, dst) \
-+ do { \
-+ major = duplicateBuffer((minor), (src), (dst)); \
-+ if (GSS_ERROR(major)) \
-+ goto cleanup; \
-+ } while (0)
-+
-+static inline int
-+bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
-+{
-+ return (b1->length == b2->length &&
-+ memcmp(b1->value, b2->value, b2->length) == 0);
-+}
-+
-+static inline int
-+bufferEqualString(const gss_buffer_t b1, const char *s)
-+{
-+ gss_buffer_desc b2;
-+
-+ b2.length = strlen(s);
-+ b2.value = (char *)s;
-+
-+ return bufferEqual(b1, &b2);
-+}
-+
-+/* util_cksum.c */
-+int
-+gssEapSign(krb5_context context,
-+ krb5_cksumtype type,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ krb5_keyusage sign_usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count);
-+
-+int
-+gssEapVerify(krb5_context context,
-+ krb5_cksumtype type,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ krb5_keyusage sign_usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ int *valid);
-+
-+#if 0
-+OM_uint32
-+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t encodedBindings);
-+#endif
-+
-+/* util_context.c */
-+#define EAP_EXPORT_CONTEXT_V1 1
-+
-+enum gss_eap_token_type {
-+ TOK_TYPE_NONE = 0x0000, /* no token */
-+ TOK_TYPE_MIC = 0x0404, /* RFC 4121 MIC token */
-+ TOK_TYPE_WRAP = 0x0504, /* RFC 4121 wrap token */
-+ TOK_TYPE_EXPORT_NAME = 0x0401, /* RFC 2743 exported name */
-+ TOK_TYPE_EXPORT_NAME_COMPOSITE = 0x0402, /* exported composite name */
-+ TOK_TYPE_DELETE_CONTEXT = 0x0405, /* RFC 2743 delete context */
-+ TOK_TYPE_INITIATOR_CONTEXT = 0x0601, /* initiator-sent context token */
-+ TOK_TYPE_ACCEPTOR_CONTEXT = 0x0602, /* acceptor-sent context token */
-+};
-+
-+/* inner token types and flags */
-+#define ITOK_TYPE_NONE 0x00000000
-+#define ITOK_TYPE_CONTEXT_ERR 0x00000001 /* critical */
-+#define ITOK_TYPE_ACCEPTOR_NAME_REQ 0x00000002 /* TBD */
-+#define ITOK_TYPE_ACCEPTOR_NAME_RESP 0x00000003 /* TBD */
-+#define ITOK_TYPE_EAP_RESP 0x00000004 /* critical, required, if not reauth */
-+#define ITOK_TYPE_EAP_REQ 0x00000005 /* critical, required, if not reauth */
-+#define ITOK_TYPE_GSS_CHANNEL_BINDINGS 0x00000006 /* critical, required, if not reauth */
-+#define ITOK_TYPE_REAUTH_CREDS 0x00000007 /* optional */
-+#define ITOK_TYPE_REAUTH_REQ 0x00000008 /* optional */
-+#define ITOK_TYPE_REAUTH_RESP 0x00000009 /* optional */
-+#define ITOK_TYPE_VERSION_INFO 0x0000000A /* optional */
-+#define ITOK_TYPE_VENDOR_INFO 0x0000000B /* optional */
-+#define ITOK_TYPE_GSS_FLAGS 0x0000000C /* optional */
-+#define ITOK_TYPE_INITIATOR_MIC 0x0000000D /* critical, required, if not reauth */
-+#define ITOK_TYPE_ACCEPTOR_MIC 0x0000000E /* TBD */
-+
-+#define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */
-+#define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */
-+
-+#define ITOK_TYPE_MASK (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
-+
-+#define GSSEAP_WIRE_FLAGS_MASK ( GSS_C_MUTUAL_FLAG | \
-+ GSS_C_DCE_STYLE | \
-+ GSS_C_IDENTIFY_FLAG | \
-+ GSS_C_EXTENDED_ERROR_FLAG )
-+
-+OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
-+OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
-+
-+OM_uint32
-+gssEapMakeToken(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t innerToken,
-+ enum gss_eap_token_type tokenType,
-+ gss_buffer_t outputToken);
-+
-+OM_uint32
-+gssEapVerifyToken(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t inputToken,
-+ enum gss_eap_token_type *tokenType,
-+ gss_buffer_t innerInputToken);
-+
-+OM_uint32
-+gssEapContextTime(OM_uint32 *minor,
-+ gss_ctx_id_t context_handle,
-+ OM_uint32 *time_rec);
-+
-+OM_uint32
-+gssEapMakeTokenMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t tokenMIC);
-+
-+OM_uint32
-+gssEapVerifyTokenMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t tokenMIC);
-+
-+/* util_cred.c */
-+OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
-+OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
-+
-+gss_OID
-+gssEapPrimaryMechForCred(gss_cred_id_t cred);
-+
-+OM_uint32
-+gssEapAcquireCred(OM_uint32 *minor,
-+ const gss_name_t desiredName,
-+ OM_uint32 timeReq,
-+ const gss_OID_set desiredMechs,
-+ int cred_usage,
-+ gss_cred_id_t *pCred,
-+ gss_OID_set *pActualMechs,
-+ OM_uint32 *timeRec);
-+
-+OM_uint32
-+gssEapSetCredPassword(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_buffer_t password);
-+
-+OM_uint32
-+gssEapSetCredService(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_name_t target);
-+
-+OM_uint32
-+gssEapResolveInitiatorCred(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ const gss_name_t target,
-+ gss_cred_id_t *resolvedCred);
-+
-+int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
-+
-+OM_uint32
-+gssEapInquireCred(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_name_t *name,
-+ OM_uint32 *pLifetime,
-+ gss_cred_usage_t *cred_usage,
-+ gss_OID_set *mechanisms);
-+
-+/* util_crypt.c */
-+int
-+gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ int usage,
-+ gss_iov_buffer_desc *iov, int iov_count);
-+
-+int
-+gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ int usage,
-+ gss_iov_buffer_desc *iov, int iov_count);
-+
-+int
-+gssEapMapCryptoFlag(OM_uint32 type);
-+
-+gss_iov_buffer_t
-+gssEapLocateIov(gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ OM_uint32 type);
-+
-+void
-+gssEapIovMessageLength(gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ size_t *data_length,
-+ size_t *assoc_data_length);
-+
-+void
-+gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
-+
-+int
-+gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
-+
-+int
-+gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
-+
-+OM_uint32
-+gssEapDeriveRfc3961Key(OM_uint32 *minor,
-+ const unsigned char *key,
-+ size_t keyLength,
-+ krb5_enctype enctype,
-+ krb5_keyblock *pKey);
-+
-+/* util_krb.c */
-+
-+#ifndef KRB_MALLOC
-+/*
-+ * If your Kerberos library uses a different allocator to your
-+ * GSS mechanism glue, then you might wish to define these in
-+ * config.h or elsewhere. This should eventually go away when
-+ * we no longer need to allocate memory that is freed by the
-+ * Kerberos library.
-+ */
-+#define KRB_CALLOC calloc
-+#define KRB_MALLOC malloc
-+#define KRB_FREE free
-+#define KRB_REALLOC realloc
-+#endif /* KRB_MALLOC */
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+
-+#define KRB_TIME_FOREVER ((time_t)~0L)
-+
-+#define KRB_KEY_TYPE(key) ((key)->keytype)
-+#define KRB_KEY_DATA(key) ((key)->keyvalue.data)
-+#define KRB_KEY_LENGTH(key) ((key)->keyvalue.length)
-+
-+#define KRB_PRINC_LENGTH(princ) ((princ)->name.name_string.len)
-+#define KRB_PRINC_TYPE(princ) ((princ)->name.name_type)
-+#define KRB_PRINC_NAME(princ) ((princ)->name.name_string.val)
-+#define KRB_PRINC_REALM(princ) ((princ)->realm)
-+
-+#define KRB_KT_ENT_KEYBLOCK(e) (&(e)->keyblock)
-+#define KRB_KT_ENT_FREE(c, e) krb5_kt_free_entry((c), (e))
-+
-+#define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto)
-+
-+#define KRB_DATA_INIT(d) krb5_data_zero((d))
-+
-+#else
-+
-+#define KRB_TIME_FOREVER KRB5_INT32_MAX
-+
-+#define KRB_KEY_TYPE(key) ((key)->enctype)
-+#define KRB_KEY_DATA(key) ((key)->contents)
-+#define KRB_KEY_LENGTH(key) ((key)->length)
-+
-+#define KRB_PRINC_LENGTH(princ) (krb5_princ_size(NULL, (princ)))
-+#define KRB_PRINC_TYPE(princ) (krb5_princ_type(NULL, (princ)))
-+#define KRB_PRINC_NAME(princ) (krb5_princ_name(NULL, (princ)))
-+#define KRB_PRINC_REALM(princ) (krb5_princ_realm(NULL, (princ)))
-+
-+#define KRB_KT_ENT_KEYBLOCK(e) (&(e)->key)
-+#define KRB_KT_ENT_FREE(c, e) krb5_free_keytab_entry_contents((c), (e))
-+
-+#define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key)
-+
-+#define KRB_DATA_INIT(d) do { \
-+ (d)->magic = KV5M_DATA; \
-+ (d)->length = 0; \
-+ (d)->data = NULL; \
-+ } while (0)
-+
-+#endif /* HAVE_HEIMDAL_VERSION */
-+
-+#define KRB_KEY_INIT(key) do { \
-+ KRB_KEY_TYPE(key) = ENCTYPE_NULL; \
-+ KRB_KEY_DATA(key) = NULL; \
-+ KRB_KEY_LENGTH(key) = 0; \
-+ } while (0)
-+
-+#define GSSEAP_KRB_INIT(ctx) do { \
-+ OM_uint32 tmpMajor; \
-+ \
-+ tmpMajor = gssEapKerberosInit(minor, ctx); \
-+ if (GSS_ERROR(tmpMajor)) { \
-+ return tmpMajor; \
-+ } \
-+ } while (0)
-+
-+OM_uint32
-+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
-+
-+OM_uint32
-+rfc3961ChecksumTypeForKey(OM_uint32 *minor,
-+ krb5_keyblock *key,
-+ krb5_cksumtype *cksumtype);
-+
-+krb5_error_code
-+krbCryptoLength(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ int type,
-+ size_t *length);
-+
-+krb5_error_code
-+krbPaddingLength(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ size_t dataLength,
-+ size_t *padLength);
-+
-+krb5_error_code
-+krbBlockSize(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ size_t *blockSize);
-+
-+krb5_error_code
-+krbEnctypeToString(krb5_context krbContext,
-+ krb5_enctype enctype,
-+ const char *prefix,
-+ gss_buffer_t string);
-+
-+krb5_error_code
-+krbMakeAuthDataKdcIssued(krb5_context context,
-+ const krb5_keyblock *key,
-+ krb5_const_principal issuer,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ const AuthorizationData *authdata,
-+ AuthorizationData *adKdcIssued
-+#else
-+ krb5_authdata *const *authdata,
-+ krb5_authdata ***adKdcIssued
-+#endif
-+ );
-+
-+krb5_error_code
-+krbMakeCred(krb5_context context,
-+ krb5_auth_context authcontext,
-+ krb5_creds *creds,
-+ krb5_data *data);
-+
-+/* util_lucid.c */
-+OM_uint32
-+gssEapExportLucidSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_OID desiredObject,
-+ gss_buffer_set_t *data_set);
-+
-+/* util_mech.c */
-+extern gss_OID GSS_EAP_MECHANISM;
-+
-+#define OID_FLAG_NULL_VALID 0x00000001
-+#define OID_FLAG_FAMILY_MECH_VALID 0x00000002
-+#define OID_FLAG_MAP_NULL_TO_DEFAULT_MECH 0x00000004
-+#define OID_FLAG_MAP_FAMILY_MECH_TO_NULL 0x00000008
-+
-+OM_uint32
-+gssEapCanonicalizeOid(OM_uint32 *minor,
-+ const gss_OID oid,
-+ OM_uint32 flags,
-+ gss_OID *pOid);
-+
-+OM_uint32
-+gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid);
-+
-+OM_uint32
-+gssEapDefaultMech(OM_uint32 *minor,
-+ gss_OID *oid);
-+
-+OM_uint32
-+gssEapIndicateMechs(OM_uint32 *minor,
-+ gss_OID_set *mechs);
-+
-+OM_uint32
-+gssEapEnctypeToOid(OM_uint32 *minor,
-+ krb5_enctype enctype,
-+ gss_OID *pOid);
-+
-+OM_uint32
-+gssEapOidToEnctype(OM_uint32 *minor,
-+ const gss_OID oid,
-+ krb5_enctype *enctype);
-+
-+int
-+gssEapIsMechanismOid(const gss_OID oid);
-+
-+int
-+gssEapIsConcreteMechanismOid(const gss_OID oid);
-+
-+OM_uint32
-+gssEapValidateMechs(OM_uint32 *minor,
-+ const gss_OID_set mechs);
-+
-+gss_buffer_t
-+gssEapOidToSaslName(const gss_OID oid);
-+
-+gss_OID
-+gssEapSaslNameToOid(const gss_buffer_t name);
-+
-+/* util_moonshot.c */
-+OM_uint32
-+libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ gss_name_t *pName);
-+
-+OM_uint32
-+libMoonshotResolveInitiatorCred(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_name_t targetName);
-+
-+/* util_name.c */
-+#define EXPORT_NAME_FLAG_OID 0x1
-+#define EXPORT_NAME_FLAG_COMPOSITE 0x2
-+#define EXPORT_NAME_FLAG_ALLOW_COMPOSITE 0x4
-+
-+OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
-+OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
-+OM_uint32 gssEapExportName(OM_uint32 *minor,
-+ const gss_name_t name,
-+ gss_buffer_t exportedName);
-+OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
-+ const gss_name_t name,
-+ gss_buffer_t exportedName,
-+ OM_uint32 flags);
-+OM_uint32 gssEapImportName(OM_uint32 *minor,
-+ const gss_buffer_t input_name_buffer,
-+ const gss_OID input_name_type,
-+ const gss_OID input_mech_type,
-+ gss_name_t *output_name);
-+OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
-+ const gss_buffer_t input_name_buffer,
-+ gss_name_t *output_name,
-+ OM_uint32 flags);
-+OM_uint32
-+gssEapDuplicateName(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ gss_name_t *dest_name);
-+
-+OM_uint32
-+gssEapCanonicalizeName(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ const gss_OID mech_type,
-+ gss_name_t *dest_name);
-+
-+OM_uint32
-+gssEapDisplayName(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t output_name_buffer,
-+ gss_OID *output_name_type);
-+
-+OM_uint32
-+gssEapCompareName(OM_uint32 *minor,
-+ gss_name_t name1,
-+ gss_name_t name2,
-+ int *name_equal);
-+
-+/* util_oid.c */
-+OM_uint32
-+composeOid(OM_uint32 *minor_status,
-+ const char *prefix,
-+ size_t prefix_len,
-+ int suffix,
-+ gss_OID_desc *oid);
-+
-+OM_uint32
-+decomposeOid(OM_uint32 *minor_status,
-+ const char *prefix,
-+ size_t prefix_len,
-+ gss_OID_desc *oid,
-+ int *suffix) ;
-+
-+OM_uint32
-+duplicateOid(OM_uint32 *minor_status,
-+ const gss_OID_desc * const oid,
-+ gss_OID *new_oid);
-+
-+OM_uint32
-+duplicateOidSet(OM_uint32 *minor,
-+ const gss_OID_set src,
-+ gss_OID_set *dst);
-+
-+static inline int
-+oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
-+{
-+ if (o1 == GSS_C_NO_OID)
-+ return (o2 == GSS_C_NO_OID);
-+ else if (o2 == GSS_C_NO_OID)
-+ return (o1 == GSS_C_NO_OID);
-+ else
-+ return (o1->length == o2->length &&
-+ memcmp(o1->elements, o2->elements, o1->length) == 0);
-+}
-+
-+/* util_ordering.c */
-+OM_uint32
-+sequenceInternalize(OM_uint32 *minor,
-+ void **vqueue,
-+ unsigned char **buf,
-+ size_t *lenremain);
-+
-+OM_uint32
-+sequenceExternalize(OM_uint32 *minor,
-+ void *vqueue,
-+ unsigned char **buf,
-+ size_t *lenremain);
-+
-+size_t
-+sequenceSize(void *vqueue);
-+
-+OM_uint32
-+sequenceFree(OM_uint32 *minor, void **vqueue);
-+
-+OM_uint32
-+sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum);
-+
-+OM_uint32
-+sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum,
-+ int do_replay, int do_sequence, int wide_nums);
-+
-+/* util_sm.c */
-+enum gss_eap_state {
-+ GSSEAP_STATE_INITIAL = 0x01, /* initial state */
-+ GSSEAP_STATE_AUTHENTICATE = 0x02, /* exchange EAP messages */
-+ GSSEAP_STATE_INITIATOR_EXTS = 0x04, /* initiator extensions */
-+ GSSEAP_STATE_ACCEPTOR_EXTS = 0x08, /* acceptor extensions */
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ GSSEAP_STATE_REAUTHENTICATE = 0x10, /* GSS reauthentication messages */
-+#endif
-+ GSSEAP_STATE_ESTABLISHED = 0x20, /* context established */
-+ GSSEAP_STATE_ALL = 0x3F
-+};
-+
-+#define GSSEAP_STATE_NEXT(s) ((s) << 1)
-+
-+#define GSSEAP_SM_STATE(ctx) ((ctx)->state)
-+
-+#ifdef GSSEAP_DEBUG
-+void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
-+#define GSSEAP_SM_TRANSITION(ctx, state) gssEapSmTransition((ctx), (state))
-+#else
-+#define GSSEAP_SM_TRANSITION(ctx, newstate) do { (ctx)->state = (newstate); } while (0)
-+#endif
-+
-+#define GSSEAP_SM_TRANSITION_NEXT(ctx) GSSEAP_SM_TRANSITION((ctx), GSSEAP_STATE_NEXT(GSSEAP_SM_STATE((ctx))))
-+
-+/* state machine entry */
-+struct gss_eap_sm {
-+ OM_uint32 inputTokenType;
-+ OM_uint32 outputTokenType;
-+ enum gss_eap_state validStates;
-+ OM_uint32 itokFlags;
-+ OM_uint32 (*processToken)(OM_uint32 *,
-+ gss_cred_id_t,
-+ gss_ctx_id_t,
-+ gss_name_t,
-+ gss_OID,
-+ OM_uint32,
-+ OM_uint32,
-+ gss_channel_bindings_t,
-+ gss_buffer_t,
-+ gss_buffer_t,
-+ OM_uint32 *);
-+};
-+
-+/* state machine flags, set by handler */
-+#define SM_FLAG_FORCE_SEND_TOKEN 0x00000001 /* send token even if no inner tokens */
-+#define SM_FLAG_OUTPUT_TOKEN_CRITICAL 0x00000002 /* output token is critical */
-+
-+/* state machine flags, set by state machine */
-+#define SM_FLAG_INPUT_TOKEN_CRITICAL 0x10000000 /* input token was critical */
-+
-+#define SM_ITOK_FLAG_REQUIRED 0x00000001 /* received tokens must be present */
-+
-+OM_uint32
-+gssEapSmStep(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target,
-+ gss_OID mech,
-+ OM_uint32 reqFlags,
-+ OM_uint32 timeReq,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ struct gss_eap_sm *sm,
-+ size_t smCount);
-+
-+void
-+gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
-+
-+/* util_token.c */
-+struct gss_eap_token_buffer_set {
-+ gss_buffer_set_desc buffers; /* pointers only */
-+ OM_uint32 *types;
-+};
-+
-+OM_uint32
-+gssEapEncodeInnerTokens(OM_uint32 *minor,
-+ struct gss_eap_token_buffer_set *tokens,
-+ gss_buffer_t buffer);
-+OM_uint32
-+gssEapDecodeInnerTokens(OM_uint32 *minor,
-+ const gss_buffer_t buffer,
-+ struct gss_eap_token_buffer_set *tokens);
-+
-+OM_uint32
-+gssEapReleaseInnerTokens(OM_uint32 *minor,
-+ struct gss_eap_token_buffer_set *tokens,
-+ int freeBuffers);
-+
-+OM_uint32
-+gssEapAllocInnerTokens(OM_uint32 *minor,
-+ size_t count,
-+ struct gss_eap_token_buffer_set *tokens);
-+
-+size_t
-+tokenSize(const gss_OID_desc *mech, size_t body_size);
-+
-+void
-+makeTokenHeader(const gss_OID_desc *mech,
-+ size_t body_size,
-+ unsigned char **buf,
-+ enum gss_eap_token_type tok_type);
-+
-+OM_uint32
-+verifyTokenHeader(OM_uint32 *minor,
-+ gss_OID mech,
-+ size_t *body_size,
-+ unsigned char **buf_in,
-+ size_t toksize_in,
-+ enum gss_eap_token_type *ret_tok_type);
-+
-+/* Helper macros */
-+
-+#ifndef GSSEAP_MALLOC
-+#define GSSEAP_CALLOC calloc
-+#define GSSEAP_MALLOC malloc
-+#define GSSEAP_FREE free
-+#define GSSEAP_REALLOC realloc
-+#endif
-+
-+#ifndef GSSAPI_CALLCONV
-+#define GSSAPI_CALLCONV KRB5_CALLCONV
-+#endif
-+
-+#ifndef GSSEAP_ASSERT
-+#include <assert.h>
-+#define GSSEAP_ASSERT(x) assert((x))
-+#endif /* !GSSEAP_ASSERT */
-+
-+#ifdef WIN32
-+#define GSSEAP_CONSTRUCTOR
-+#define GSSEAP_DESTRUCTOR
-+#else
-+#define GSSEAP_CONSTRUCTOR __attribute__((constructor))
-+#define GSSEAP_DESTRUCTOR __attribute__((destructor))
-+#endif
-+
-+#define GSSEAP_NOT_IMPLEMENTED do { \
-+ GSSEAP_ASSERT(0 && "not implemented"); \
-+ *minor = ENOSYS; \
-+ return GSS_S_FAILURE; \
-+ } while (0)
-+
-+#ifdef WIN32
-+
-+#include <winbase.h>
-+
-+#define GSSEAP_GET_LAST_ERROR() (GetLastError()) /* XXX FIXME */
-+
-+#define GSSEAP_MUTEX CRITICAL_SECTION
-+#define GSSEAP_MUTEX_INIT(m) (InitializeCriticalSection((m)), 0)
-+#define GSSEAP_MUTEX_DESTROY(m) DeleteCriticalSection((m))
-+#define GSSEAP_MUTEX_LOCK(m) EnterCriticalSection((m))
-+#define GSSEAP_MUTEX_UNLOCK(m) LeaveCriticalSection((m))
-+#define GSSEAP_ONCE_LEAVE do { return TRUE; } while (0)
-+
-+/* Thread-local is handled separately */
-+
-+#define GSSEAP_THREAD_ONCE INIT_ONCE
-+#define GSSEAP_ONCE_CALLBACK(cb) BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
-+#define GSSEAP_ONCE(o, i) InitOnceExecuteOnce((o), (i), NULL, NULL)
-+#define GSSEAP_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT
-+
-+#else
-+
-+#include <pthread.h>
-+
-+#define GSSEAP_GET_LAST_ERROR() (errno)
-+
-+#define GSSEAP_MUTEX pthread_mutex_t
-+#define GSSEAP_MUTEX_INIT(m) pthread_mutex_init((m), NULL)
-+#define GSSEAP_MUTEX_DESTROY(m) pthread_mutex_destroy((m))
-+#define GSSEAP_MUTEX_LOCK(m) pthread_mutex_lock((m))
-+#define GSSEAP_MUTEX_UNLOCK(m) pthread_mutex_unlock((m))
-+
-+#define GSSEAP_THREAD_KEY pthread_key_t
-+#define GSSEAP_KEY_CREATE(k, d) pthread_key_create((k), (d))
-+#define GSSEAP_GETSPECIFIC(k) pthread_getspecific((k))
-+#define GSSEAP_SETSPECIFIC(k, d) pthread_setspecific((k), (d))
-+
-+#define GSSEAP_THREAD_ONCE pthread_once_t
-+#define GSSEAP_ONCE_CALLBACK(cb) void cb(void)
-+#define GSSEAP_ONCE(o, i) pthread_once((o), (i))
-+#define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT
-+#define GSSEAP_ONCE_LEAVE do { } while (0)
-+
-+#endif /* WIN32 */
-+
-+/* Helper functions */
-+static inline void
-+store_uint16_be(uint16_t val, void *vp)
-+{
-+ unsigned char *p = (unsigned char *)vp;
-+
-+ p[0] = (val >> 8) & 0xff;
-+ p[1] = (val ) & 0xff;
-+}
-+
-+static inline uint16_t
-+load_uint16_be(const void *cvp)
-+{
-+ const unsigned char *p = (const unsigned char *)cvp;
-+
-+ return (p[1] | (p[0] << 8));
-+}
-+
-+static inline void
-+store_uint32_be(uint32_t val, void *vp)
-+{
-+ unsigned char *p = (unsigned char *)vp;
-+
-+ p[0] = (val >> 24) & 0xff;
-+ p[1] = (val >> 16) & 0xff;
-+ p[2] = (val >> 8) & 0xff;
-+ p[3] = (val ) & 0xff;
-+}
-+
-+static inline uint32_t
-+load_uint32_be(const void *cvp)
-+{
-+ const unsigned char *p = (const unsigned char *)cvp;
-+
-+ return (p[3] | (p[2] << 8)
-+ | ((uint32_t) p[1] << 16)
-+ | ((uint32_t) p[0] << 24));
-+}
-+
-+static inline void
-+store_uint64_be(uint64_t val, void *vp)
-+{
-+ unsigned char *p = (unsigned char *)vp;
-+
-+ p[0] = (unsigned char)((val >> 56) & 0xff);
-+ p[1] = (unsigned char)((val >> 48) & 0xff);
-+ p[2] = (unsigned char)((val >> 40) & 0xff);
-+ p[3] = (unsigned char)((val >> 32) & 0xff);
-+ p[4] = (unsigned char)((val >> 24) & 0xff);
-+ p[5] = (unsigned char)((val >> 16) & 0xff);
-+ p[6] = (unsigned char)((val >> 8) & 0xff);
-+ p[7] = (unsigned char)((val ) & 0xff);
-+}
-+
-+static inline uint64_t
-+load_uint64_be(const void *cvp)
-+{
-+ const unsigned char *p = (const unsigned char *)cvp;
-+
-+ return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
-+}
-+
-+static inline unsigned char *
-+store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
-+{
-+ unsigned char *p = (unsigned char *)vp;
-+
-+ if (wide_nums) {
-+ store_uint64_be(buffer->length, p);
-+ p += 8;
-+ } else {
-+ store_uint32_be(buffer->length, p);
-+ p += 4;
-+ }
-+
-+ if (buffer->value != NULL) {
-+ memcpy(p, buffer->value, buffer->length);
-+ p += buffer->length;
-+ }
-+
-+ return p;
-+}
-+
-+static inline unsigned char *
-+load_buffer(const void *cvp, size_t length, gss_buffer_t buffer)
-+{
-+ buffer->length = 0;
-+ buffer->value = GSSEAP_MALLOC(length);
-+ if (buffer->value == NULL)
-+ return NULL;
-+ buffer->length = length;
-+ memcpy(buffer->value, cvp, length);
-+ return (unsigned char *)cvp + length;
-+}
-+
-+static inline unsigned char *
-+store_oid(gss_OID oid, void *vp)
-+{
-+ gss_buffer_desc buf;
-+
-+ if (oid != GSS_C_NO_OID) {
-+ buf.length = oid->length;
-+ buf.value = oid->elements;
-+ } else {
-+ buf.length = 0;
-+ buf.value = NULL;
-+ }
-+
-+ return store_buffer(&buf, vp, FALSE);
-+}
-+
-+static inline void
-+krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer)
-+{
-+ buffer->value = (void *)data->data;
-+ buffer->length = data->length;
-+}
-+
-+static inline void
-+krbPrincComponentToGssBuffer(krb5_principal krbPrinc,
-+ int index, gss_buffer_t buffer)
-+{
-+#ifdef HAVE_HEIMDAL_VERSION
-+ buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
-+ buffer->length = strlen((char *)buffer->value);
-+#else
-+ buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
-+ buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
-+#endif /* HAVE_HEIMDAL_VERSION */
-+}
-+
-+static inline void
-+krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer)
-+{
-+#ifdef HAVE_HEIMDAL_VERSION
-+ buffer->value = (void *)KRB_PRINC_REALM(krbPrinc);
-+ buffer->length = strlen((char *)buffer->value);
-+#else
-+ krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer);
-+#endif
-+}
-+
-+static inline void
-+gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
-+{
-+ data->data = (char *)buffer->value;
-+ data->length = buffer->length;
-+}
-+
-+/* util_tld.c */
-+struct gss_eap_status_info;
-+
-+struct gss_eap_thread_local_data {
-+ krb5_context krbContext;
-+ struct gss_eap_status_info *statusInfo;
-+};
-+
-+struct gss_eap_thread_local_data *
-+gssEapGetThreadLocalData(void);
-+
-+void
-+gssEapDestroyStatusInfo(struct gss_eap_status_info *status);
-+
-+void
-+gssEapDestroyKrbContext(krb5_context context);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+#include "util_json.h"
-+#include "util_attr.h"
-+#include "util_base64.h"
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+#ifdef GSSEAP_ENABLE_REAUTH
-+#include "util_reauth.h"
-+#endif
-+
-+#endif /* _UTIL_H_ */
-diff --git a/mech_eap/util_adshim.c b/mech_eap/util_adshim.c
-new file mode 100644
-index 0000000..513a1a8
---- /dev/null
-+++ b/mech_eap/util_adshim.c
-@@ -0,0 +1,242 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+#include "authdata_plugin.h"
-+
-+/*
-+ * This rubbish is necessary because MIT doesn't provide another way
-+ * to access verified AD-KDCIssued elements. We can't verify them
-+ * ourselves because they're signed in the ticket session key, which
-+ * is destroyed immediately after the AP-REQ is processed.
-+ */
-+
-+struct radius_ad_context {
-+ krb5_data avpdata;
-+ krb5_boolean verified;
-+};
-+
-+static krb5_data radius_ad_attr = {
-+ KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
-+
-+static krb5_error_code
-+radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
-+ void **plugin_context)
-+{
-+ *plugin_context = 0;
-+ return 0;
-+}
-+
-+static void
-+radius_ad_flags(krb5_context kcontext GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ krb5_authdatatype ad_type GSSEAP_UNUSED,
-+ krb5_flags *flags)
-+{
-+ *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
-+}
-+
-+static void
-+radius_ad_fini(krb5_context kcontext GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED)
-+{
-+ return;
-+}
-+
-+static krb5_error_code
-+radius_ad_request_init(krb5_context kcontext GSSEAP_UNUSED,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void **request_context)
-+{
-+ struct radius_ad_context *ctx;
-+
-+ ctx = GSSEAP_CALLOC(1, sizeof(*ctx));
-+ if (ctx == NULL)
-+ return ENOMEM;
-+
-+ *request_context = ctx;
-+
-+ return 0;
-+}
-+
-+static krb5_error_code
-+radius_ad_export_authdata(krb5_context kcontext,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void *request_context,
-+ krb5_flags usage GSSEAP_UNUSED,
-+ krb5_authdata ***out_authdata)
-+{
-+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
-+ krb5_authdata *data[2];
-+ krb5_authdata datum;
-+
-+ datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
-+ datum.length = radius_ad->avpdata.length;
-+ datum.contents = (krb5_octet *)radius_ad->avpdata.data;
-+
-+ data[0] = &datum;
-+ data[1] = NULL;
-+
-+ return krb5_copy_authdata(kcontext, data, out_authdata);
-+}
-+
-+static krb5_error_code
-+radius_ad_import_authdata(krb5_context kcontext,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void *request_context,
-+ krb5_authdata **authdata,
-+ krb5_boolean kdc_issued_flag,
-+ krb5_const_principal issuer GSSEAP_UNUSED)
-+{
-+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
-+
-+ krb5_free_data_contents(kcontext, &radius_ad->avpdata);
-+ radius_ad->verified = FALSE;
-+
-+ GSSEAP_ASSERT(authdata[0] != NULL);
-+
-+ radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length);
-+ if (radius_ad->avpdata.data == NULL)
-+ return ENOMEM;
-+
-+ memcpy(radius_ad->avpdata.data, authdata[0]->contents,
-+ authdata[0]->length);
-+ radius_ad->avpdata.length = authdata[0]->length;
-+
-+ radius_ad->verified = kdc_issued_flag;
-+
-+ return 0;
-+}
-+
-+static void
-+radius_ad_request_fini(krb5_context kcontext,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void *request_context)
-+{
-+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
-+
-+ if (radius_ad != NULL) {
-+ krb5_free_data_contents(kcontext, &radius_ad->avpdata);
-+ GSSEAP_FREE(radius_ad);
-+ }
-+}
-+
-+static krb5_error_code
-+radius_ad_get_attribute(krb5_context kcontext GSSEAP_UNUSED,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void *request_context,
-+ const krb5_data *attribute,
-+ krb5_boolean *authenticated,
-+ krb5_boolean *complete,
-+ krb5_data *value,
-+ krb5_data *display_value GSSEAP_UNUSED,
-+ int *more)
-+{
-+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
-+
-+ if (attribute->length != radius_ad_attr.length ||
-+ memcmp(attribute->data, radius_ad_attr.data,
-+ radius_ad_attr.length) != 0)
-+ return ENOENT;
-+
-+ if (radius_ad->avpdata.length == 0)
-+ return ENOENT;
-+
-+ *authenticated = radius_ad->verified;
-+ *complete = TRUE;
-+ *more = 0;
-+
-+ value->data = GSSEAP_MALLOC(radius_ad->avpdata.length);
-+ if (value->data == NULL)
-+ return ENOMEM;
-+
-+ memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length);
-+ value->length = radius_ad->avpdata.length;
-+
-+ return 0;
-+}
-+
-+static krb5_error_code
-+radius_ad_copy(krb5_context kcontext GSSEAP_UNUSED,
-+ struct _krb5_authdata_context *context GSSEAP_UNUSED,
-+ void *plugin_context GSSEAP_UNUSED,
-+ void *request_context,
-+ void *dst_plugin_context GSSEAP_UNUSED,
-+ void *dst_request_context)
-+{
-+ struct radius_ad_context *radius_ad_src =
-+ (struct radius_ad_context *)request_context;
-+ struct radius_ad_context *radius_ad_dst =
-+ (struct radius_ad_context *)dst_request_context;
-+
-+ radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length);
-+ if (radius_ad_dst->avpdata.data == NULL)
-+ return ENOMEM;
-+
-+ memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data,
-+ radius_ad_src->avpdata.length);
-+ radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length;
-+ radius_ad_dst->verified = radius_ad_src->verified;
-+
-+ return 0;
-+}
-+
-+static krb5_authdatatype radius_ad_ad_types[] =
-+ { KRB5_AUTHDATA_RADIUS_AVP, 0 };
-+
-+krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
-+ "radius_ad",
-+ radius_ad_ad_types,
-+ radius_ad_init,
-+ radius_ad_fini,
-+ radius_ad_flags,
-+ radius_ad_request_init,
-+ radius_ad_request_fini,
-+ NULL,
-+ radius_ad_get_attribute,
-+ NULL,
-+ NULL,
-+ radius_ad_export_authdata,
-+ radius_ad_import_authdata,
-+ NULL,
-+ NULL,
-+ NULL,
-+ NULL,
-+ NULL,
-+ NULL,
-+ radius_ad_copy
-+};
-diff --git a/mech_eap/util_attr.cpp b/mech_eap/util_attr.cpp
-new file mode 100644
-index 0000000..3bfe785
---- /dev/null
-+++ b/mech_eap/util_attr.cpp
-@@ -0,0 +1,1191 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Attribute provider mechanism.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#include <typeinfo>
-+#include <string>
-+#include <sstream>
-+#include <exception>
-+#include <new>
-+
-+/* lazy initialisation */
-+static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
-+static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
-+
-+GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal)
-+{
-+ OM_uint32 major, minor;
-+
-+ GSSEAP_ASSERT(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
-+
-+ json_set_alloc_funcs(GSSEAP_MALLOC, GSSEAP_FREE);
-+
-+ major = gssEapRadiusAttrProviderInit(&minor);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+#ifdef HAVE_OPENSAML
-+ major = gssEapSamlAttrProvidersInit(&minor);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+#endif
-+
-+#ifdef HAVE_SHIBRESOLVER
-+ /* Allow Shibboleth initialization failure to be non-fatal */
-+ gssEapLocalAttrProviderInit(&minor);
-+#endif
-+
-+cleanup:
-+#ifdef GSSEAP_DEBUG
-+ GSSEAP_ASSERT(major == GSS_S_COMPLETE);
-+#endif
-+
-+ gssEapAttrProvidersInitStatus = major;
-+
-+ GSSEAP_ONCE_LEAVE;
-+}
-+
-+static OM_uint32
-+gssEapAttrProvidersInit(OM_uint32 *minor)
-+{
-+ GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInitStatus))
-+ *minor = GSSEAP_NO_ATTR_PROVIDERS;
-+
-+ return gssEapAttrProvidersInitStatus;
-+}
-+
-+OM_uint32
-+gssEapAttrProvidersFinalize(OM_uint32 *minor)
-+{
-+ if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
-+#ifdef HAVE_SHIBRESOLVER
-+ gssEapLocalAttrProviderFinalize(minor);
-+#endif
-+#ifdef HAVE_OPENSAML
-+ gssEapSamlAttrProvidersFinalize(minor);
-+#endif
-+ gssEapRadiusAttrProviderFinalize(minor);
-+
-+ gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
-+
-+/*
-+ * Register a provider for a particular type and prefix
-+ */
-+void
-+gss_eap_attr_ctx::registerProvider(unsigned int type,
-+ gss_eap_attr_create_provider factory)
-+{
-+ GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
-+
-+ GSSEAP_ASSERT(gssEapAttrFactories[type] == NULL);
-+
-+ gssEapAttrFactories[type] = factory;
-+}
-+
-+/*
-+ * Unregister a provider
-+ */
-+void
-+gss_eap_attr_ctx::unregisterProvider(unsigned int type)
-+{
-+ GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
-+
-+ gssEapAttrFactories[type] = NULL;
-+}
-+
-+/*
-+ * Create an attribute context, that manages instances of providers
-+ */
-+gss_eap_attr_ctx::gss_eap_attr_ctx(void)
-+{
-+ m_flags = 0;
-+
-+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider;
-+
-+ if (gssEapAttrFactories[i] != NULL) {
-+ provider = (gssEapAttrFactories[i])();
-+ } else {
-+ provider = NULL;
-+ }
-+
-+ m_providers[i] = provider;
-+ }
-+}
-+
-+/*
-+ * Convert an attribute prefix to a type
-+ */
-+unsigned int
-+gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
-+{
-+ unsigned int i;
-+
-+ for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
-+ const char *pprefix;
-+
-+ if (!providerEnabled(i))
-+ continue;
-+
-+ pprefix = m_providers[i]->prefix();
-+ if (pprefix == NULL)
-+ continue;
-+
-+ if (strlen(pprefix) == prefix->length &&
-+ memcmp(pprefix, prefix->value, prefix->length) == 0)
-+ return i;
-+ }
-+
-+ return ATTR_TYPE_LOCAL;
-+}
-+
-+/*
-+ * Convert a type to an attribute prefix
-+ */
-+gss_buffer_desc
-+gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
-+{
-+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
-+
-+ if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
-+ return prefix;
-+
-+ if (!providerEnabled(type))
-+ return prefix;
-+
-+ prefix.value = (void *)m_providers[type]->prefix();
-+ if (prefix.value != NULL)
-+ prefix.length = strlen((char *)prefix.value);
-+
-+ return prefix;
-+}
-+
-+bool
-+gss_eap_attr_ctx::providerEnabled(unsigned int type) const
-+{
-+ if (type == ATTR_TYPE_LOCAL &&
-+ (m_flags & ATTR_FLAG_DISABLE_LOCAL))
-+ return false;
-+
-+ if (m_providers[type] == NULL)
-+ return false;
-+
-+ return true;
-+}
-+
-+void
-+gss_eap_attr_ctx::releaseProvider(unsigned int type)
-+{
-+ delete m_providers[type];
-+ m_providers[type] = NULL;
-+}
-+
-+/*
-+ * Initialize a context from an existing context.
-+ */
-+bool
-+gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
-+{
-+ bool ret = true;
-+
-+ m_flags = manager->m_flags;
-+
-+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider;
-+
-+ if (!providerEnabled(i)) {
-+ releaseProvider(i);
-+ continue;
-+ }
-+
-+ provider = m_providers[i];
-+
-+ ret = provider->initWithExistingContext(this,
-+ manager->m_providers[i]);
-+ if (ret == false) {
-+ releaseProvider(i);
-+ break;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Initialize a context from a GSS credential and context.
-+ */
-+bool
-+gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
-+ const gss_ctx_id_t ctx)
-+{
-+ bool ret = true;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL &&
-+ (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
-+ m_flags |= ATTR_FLAG_DISABLE_LOCAL;
-+ }
-+
-+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider;
-+
-+ if (!providerEnabled(i)) {
-+ releaseProvider(i);
-+ continue;
-+ }
-+
-+ provider = m_providers[i];
-+
-+ ret = provider->initWithGssContext(this, cred, ctx);
-+ if (ret == false) {
-+ releaseProvider(i);
-+ break;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+bool
-+gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
-+{
-+ bool ret = false;
-+ bool foundSource[ATTR_TYPE_MAX + 1];
-+ unsigned int type;
-+
-+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
-+ foundSource[type] = false;
-+
-+ if (obj["version"].integer() != 1)
-+ return false;
-+
-+ m_flags = obj["flags"].integer();
-+
-+ JSONObject sources = obj["sources"];
-+
-+ /* Initialize providers from serialized state */
-+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
-+ gss_eap_attr_provider *provider;
-+ const char *key;
-+
-+ if (!providerEnabled(type)) {
-+ releaseProvider(type);
-+ continue;
-+ }
-+
-+ provider = m_providers[type];
-+ key = provider->name();
-+ if (key == NULL)
-+ continue;
-+
-+ JSONObject source = sources.get(key);
-+ if (!source.isNull() &&
-+ !provider->initWithJsonObject(this, source)) {
-+ releaseProvider(type);
-+ return false;
-+ }
-+
-+ foundSource[type] = true;
-+ }
-+
-+ /* Initialize remaining providers from initialized providers */
-+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
-+ gss_eap_attr_provider *provider;
-+
-+ if (foundSource[type] || !providerEnabled(type))
-+ continue;
-+
-+ provider = m_providers[type];
-+
-+ ret = provider->initWithGssContext(this,
-+ GSS_C_NO_CREDENTIAL,
-+ GSS_C_NO_CONTEXT);
-+ if (ret == false) {
-+ releaseProvider(type);
-+ return false;
-+ }
-+ }
-+
-+ return true;
-+}
-+
-+JSONObject
-+gss_eap_attr_ctx::jsonRepresentation(void) const
-+{
-+ JSONObject obj, sources;
-+ unsigned int i;
-+
-+ obj.set("version", 1);
-+ obj.set("flags", m_flags);
-+
-+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider;
-+ const char *key;
-+
-+ provider = m_providers[i];
-+ if (provider == NULL)
-+ continue; /* provider not initialised */
-+
-+ key = provider->name();
-+ if (key == NULL)
-+ continue; /* provider does not have state */
-+
-+ JSONObject source = provider->jsonRepresentation();
-+ sources.set(key, source);
-+ }
-+
-+ obj.set("sources", sources);
-+
-+ return obj;
-+}
-+
-+/*
-+ * Initialize a context from an exported context or name token
-+ */
-+bool
-+gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
-+{
-+ OM_uint32 major, minor;
-+ bool ret;
-+ char *s;
-+ json_error_t error;
-+
-+ major = bufferToString(&minor, buffer, &s);
-+ if (GSS_ERROR(major))
-+ return false;
-+
-+ JSONObject obj = JSONObject::load(s, 0, &error);
-+ if (!obj.isNull()) {
-+ ret = initWithJsonObject(obj);
-+ } else
-+ ret = false;
-+
-+ GSSEAP_FREE(s);
-+
-+ return ret;
-+}
-+
-+gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
-+{
-+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
-+ delete m_providers[i];
-+}
-+
-+/*
-+ * Locate provider for a given type
-+ */
-+gss_eap_attr_provider *
-+gss_eap_attr_ctx::getProvider(unsigned int type) const
-+{
-+ GSSEAP_ASSERT(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
-+ return m_providers[type];
-+}
-+
-+/*
-+ * Get primary provider. Only the primary provider is serialised when
-+ * gss_export_sec_context() or gss_export_name_composite() is called.
-+ */
-+gss_eap_attr_provider *
-+gss_eap_attr_ctx::getPrimaryProvider(void) const
-+{
-+ return m_providers[ATTR_TYPE_MIN];
-+}
-+
-+/*
-+ * Set an attribute
-+ */
-+bool
-+gss_eap_attr_ctx::setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value)
-+{
-+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
-+ unsigned int type;
-+ gss_eap_attr_provider *provider;
-+ bool ret = false;
-+
-+ decomposeAttributeName(attr, &type, &suffix);
-+
-+ provider = m_providers[type];
-+ if (provider != NULL) {
-+ ret = provider->setAttribute(complete,
-+ (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
-+ value);
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Delete an attrbiute
-+ */
-+bool
-+gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
-+{
-+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
-+ unsigned int type;
-+ gss_eap_attr_provider *provider;
-+ bool ret = false;
-+
-+ decomposeAttributeName(attr, &type, &suffix);
-+
-+ provider = m_providers[type];
-+ if (provider != NULL) {
-+ ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Enumerate attribute types with callback
-+ */
-+bool
-+gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
-+{
-+ bool ret = false;
-+ size_t i;
-+
-+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider = m_providers[i];
-+
-+ if (provider == NULL)
-+ continue;
-+
-+ ret = provider->getAttributeTypes(cb, data);
-+ if (ret == false)
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+struct eap_gss_get_attr_types_args {
-+ unsigned int type;
-+ gss_buffer_set_t attrs;
-+};
-+
-+static bool
-+addAttribute(const gss_eap_attr_ctx *manager,
-+ const gss_eap_attr_provider *provider GSSEAP_UNUSED,
-+ const gss_buffer_t attribute,
-+ void *data)
-+{
-+ eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
-+ gss_buffer_desc qualified;
-+ OM_uint32 major, minor;
-+
-+ if (args->type != ATTR_TYPE_LOCAL) {
-+ manager->composeAttributeName(args->type, attribute, &qualified);
-+ major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
-+ gss_release_buffer(&minor, &qualified);
-+ } else {
-+ major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
-+ }
-+
-+ return GSS_ERROR(major) == false;
-+}
-+
-+/*
-+ * Enumerate attribute types, output is buffer set
-+ */
-+bool
-+gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
-+{
-+ eap_gss_get_attr_types_args args;
-+ OM_uint32 major, minor;
-+ bool ret = false;
-+ unsigned int i;
-+
-+ major = gss_create_empty_buffer_set(&minor, attrs);
-+ if (GSS_ERROR(major))
-+ throw std::bad_alloc();
-+
-+ args.attrs = *attrs;
-+
-+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider = m_providers[i];
-+
-+ args.type = i;
-+
-+ if (provider == NULL)
-+ continue;
-+
-+ ret = provider->getAttributeTypes(addAttribute, (void *)&args);
-+ if (ret == false)
-+ break;
-+ }
-+
-+ if (ret == false)
-+ gss_release_buffer_set(&minor, attrs);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Get attribute with given name
-+ */
-+bool
-+gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
-+ unsigned int type;
-+ gss_eap_attr_provider *provider;
-+ bool ret;
-+
-+ decomposeAttributeName(attr, &type, &suffix);
-+
-+ provider = m_providers[type];
-+ if (provider == NULL)
-+ return false;
-+
-+ ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
-+ authenticated, complete,
-+ value, display_value, more);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Map attribute context to C++ object
-+ */
-+gss_any_t
-+gss_eap_attr_ctx::mapToAny(int authenticated,
-+ gss_buffer_t type_id) const
-+{
-+ unsigned int type;
-+ gss_eap_attr_provider *provider;
-+ gss_buffer_desc suffix;
-+
-+ decomposeAttributeName(type_id, &type, &suffix);
-+
-+ provider = m_providers[type];
-+ if (provider == NULL)
-+ return (gss_any_t)NULL;
-+
-+ return provider->mapToAny(authenticated, &suffix);
-+}
-+
-+/*
-+ * Release mapped context
-+ */
-+void
-+gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const
-+{
-+ unsigned int type;
-+ gss_eap_attr_provider *provider;
-+ gss_buffer_desc suffix;
-+
-+ decomposeAttributeName(type_id, &type, &suffix);
-+
-+ provider = m_providers[type];
-+ if (provider != NULL)
-+ provider->releaseAnyNameMapping(&suffix, input);
-+}
-+
-+/*
-+ * Export attribute context to buffer
-+ */
-+void
-+gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
-+{
-+ OM_uint32 minor;
-+ char *s;
-+
-+ JSONObject obj = jsonRepresentation();
-+
-+#if 0
-+ obj.dump(stdout);
-+#endif
-+
-+ s = obj.dump(JSON_COMPACT);
-+
-+ if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
-+ throw std::bad_alloc();
-+}
-+
-+/*
-+ * Return soonest expiry time of providers
-+ */
-+time_t
-+gss_eap_attr_ctx::getExpiryTime(void) const
-+{
-+ unsigned int i;
-+ time_t expiryTime = 0;
-+
-+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider = m_providers[i];
-+ time_t providerExpiryTime;
-+
-+ if (provider == NULL)
-+ continue;
-+
-+ providerExpiryTime = provider->getExpiryTime();
-+ if (providerExpiryTime == 0)
-+ continue;
-+
-+ if (expiryTime == 0 || providerExpiryTime < expiryTime)
-+ expiryTime = providerExpiryTime;
-+ }
-+
-+ return expiryTime;
-+}
-+
-+OM_uint32
-+gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
-+{
-+ unsigned int i;
-+ OM_uint32 major;
-+
-+ /* Errors we handle ourselves */
-+ if (typeid(e) == typeid(std::bad_alloc)) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ } else if (typeid(e) == typeid(JSONException)) {
-+ major = GSS_S_BAD_NAME;
-+ *minor = GSSEAP_BAD_ATTR_TOKEN;
-+ gssEapSaveStatusInfo(*minor, "%s", e.what());
-+ goto cleanup;
-+ }
-+
-+ /* Errors we delegate to providers */
-+ major = GSS_S_CONTINUE_NEEDED;
-+
-+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-+ gss_eap_attr_provider *provider = m_providers[i];
-+
-+ if (provider == NULL)
-+ continue;
-+
-+ major = provider->mapException(minor, e);
-+ if (major != GSS_S_CONTINUE_NEEDED)
-+ break;
-+ }
-+
-+ if (major == GSS_S_CONTINUE_NEEDED) {
-+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
-+ major = GSS_S_FAILURE;
-+ }
-+
-+cleanup:
-+ GSSEAP_ASSERT(GSS_ERROR(major));
-+
-+ return major;
-+}
-+
-+/*
-+ * Decompose attribute name into prefix and suffix
-+ */
-+void
-+gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
-+ gss_buffer_t prefix,
-+ gss_buffer_t suffix)
-+{
-+ char *p = NULL;
-+ size_t i;
-+
-+ for (i = 0; i < attribute->length; i++) {
-+ if (((char *)attribute->value)[i] == ' ') {
-+ p = (char *)attribute->value + i + 1;
-+ break;
-+ }
-+ }
-+
-+ prefix->value = attribute->value;
-+ prefix->length = i;
-+
-+ if (p != NULL && *p != '\0') {
-+ suffix->length = attribute->length - 1 - prefix->length;
-+ suffix->value = p;
-+ } else {
-+ suffix->length = 0;
-+ suffix->value = NULL;
-+ }
-+}
-+
-+/*
-+ * Decompose attribute name into type and suffix
-+ */
-+void
-+gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
-+ unsigned int *type,
-+ gss_buffer_t suffix) const
-+{
-+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
-+
-+ decomposeAttributeName(attribute, &prefix, suffix);
-+ *type = attributePrefixToType(&prefix);
-+}
-+
-+/*
-+ * Compose attribute name from prefix, suffix; returns C++ string
-+ */
-+std::string
-+gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
-+ const gss_buffer_t suffix)
-+{
-+ std::string str;
-+
-+ if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
-+ return str;
-+
-+ str.append((const char *)prefix->value, prefix->length);
-+
-+ if (suffix != GSS_C_NO_BUFFER) {
-+ str.append(" ");
-+ str.append((const char *)suffix->value, suffix->length);
-+ }
-+
-+ return str;
-+}
-+
-+/*
-+ * Compose attribute name from type, suffix; returns C++ string
-+ */
-+std::string
-+gss_eap_attr_ctx::composeAttributeName(unsigned int type,
-+ const gss_buffer_t suffix)
-+{
-+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
-+
-+ return composeAttributeName(&prefix, suffix);
-+}
-+
-+/*
-+ * Compose attribute name from prefix, suffix; returns GSS buffer
-+ */
-+void
-+gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
-+ const gss_buffer_t suffix,
-+ gss_buffer_t attribute)
-+{
-+ std::string str = composeAttributeName(prefix, suffix);
-+
-+ if (str.length() != 0) {
-+ return duplicateBuffer(str, attribute);
-+ } else {
-+ attribute->length = 0;
-+ attribute->value = NULL;
-+ }
-+}
-+
-+/*
-+ * Compose attribute name from type, suffix; returns GSS buffer
-+ */
-+void
-+gss_eap_attr_ctx::composeAttributeName(unsigned int type,
-+ const gss_buffer_t suffix,
-+ gss_buffer_t attribute) const
-+{
-+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
-+
-+ return composeAttributeName(&prefix, suffix, attribute);
-+}
-+
-+/*
-+ * C wrappers
-+ */
-+OM_uint32
-+gssEapInquireName(OM_uint32 *minor,
-+ gss_name_t name,
-+ int *name_is_MN,
-+ gss_OID *MN_mech,
-+ gss_buffer_set_t *attrs)
-+{
-+ OM_uint32 major;
-+
-+ if (name_is_MN != NULL)
-+ *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
-+
-+ if (MN_mech != NULL) {
-+ major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
-+ OID_FLAG_NULL_VALID, MN_mech);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ try {
-+ if (!name->attrCtx->getAttributeTypes(attrs)) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapGetNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more)
-+{
-+ if (authenticated != NULL)
-+ *authenticated = 0;
-+ if (complete != NULL)
-+ *complete = 0;
-+
-+ if (value != NULL) {
-+ value->length = 0;
-+ value->value = NULL;
-+ }
-+
-+ if (display_value != NULL) {
-+ display_value->length = 0;
-+ display_value->value = NULL;
-+ }
-+
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ try {
-+ if (!name->attrCtx->getAttribute(attr, authenticated, complete,
-+ value, display_value, more)) {
-+ *minor = GSSEAP_NO_SUCH_ATTR;
-+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
-+ (int)attr->length, (char *)attr->value);
-+ return GSS_S_UNAVAILABLE;
-+ }
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapDeleteNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t attr)
-+{
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ if (!name->attrCtx->deleteAttribute(attr)) {
-+ *minor = GSSEAP_NO_SUCH_ATTR;
-+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
-+ (int)attr->length, (char *)attr->value);
-+ return GSS_S_UNAVAILABLE;
-+ }
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapSetNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ int complete,
-+ gss_buffer_t attr,
-+ gss_buffer_t value)
-+{
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ if (!name->attrCtx->setAttribute(complete, attr, value)) {
-+ *minor = GSSEAP_NO_SUCH_ATTR;
-+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
-+ (int)attr->length, (char *)attr->value);
-+ return GSS_S_UNAVAILABLE;
-+ }
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapExportAttrContext(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t buffer)
-+{
-+ if (name->attrCtx == NULL) {
-+ buffer->length = 0;
-+ buffer->value = NULL;
-+
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ name->attrCtx->exportToBuffer(buffer);
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapImportAttrContext(OM_uint32 *minor,
-+ gss_buffer_t buffer,
-+ gss_name_t name)
-+{
-+ gss_eap_attr_ctx *ctx = NULL;
-+ OM_uint32 major = GSS_S_FAILURE;
-+
-+ GSSEAP_ASSERT(name->attrCtx == NULL);
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ if (buffer->length == 0)
-+ return GSS_S_COMPLETE;
-+
-+ try {
-+ ctx = new gss_eap_attr_ctx();
-+
-+ if (ctx->initWithBuffer(buffer)) {
-+ name->attrCtx = ctx;
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+ } else {
-+ major = GSS_S_BAD_NAME;
-+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
-+ }
-+ } catch (std::exception &e) {
-+ if (ctx != NULL)
-+ major = ctx->mapException(minor, e);
-+ }
-+
-+ GSSEAP_ASSERT(major == GSS_S_COMPLETE || name->attrCtx == NULL);
-+
-+ if (GSS_ERROR(major))
-+ delete ctx;
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapDuplicateAttrContext(OM_uint32 *minor,
-+ gss_name_t in,
-+ gss_name_t out)
-+{
-+ gss_eap_attr_ctx *ctx = NULL;
-+ OM_uint32 major = GSS_S_FAILURE;
-+
-+ GSSEAP_ASSERT(out->attrCtx == NULL);
-+
-+ if (in->attrCtx == NULL) {
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ ctx = new gss_eap_attr_ctx();
-+
-+ if (ctx->initWithExistingContext(in->attrCtx)) {
-+ out->attrCtx = ctx;
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+ } else {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
-+ }
-+ } catch (std::exception &e) {
-+ major = in->attrCtx->mapException(minor, e);
-+ }
-+
-+ GSSEAP_ASSERT(major == GSS_S_COMPLETE || out->attrCtx == NULL);
-+
-+ if (GSS_ERROR(major))
-+ delete ctx;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapMapNameToAny(OM_uint32 *minor,
-+ gss_name_t name,
-+ int authenticated,
-+ gss_buffer_t type_id,
-+ gss_any_t *output)
-+{
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ *output = name->attrCtx->mapToAny(authenticated, type_id);
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapReleaseAnyNameMapping(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t type_id,
-+ gss_any_t *input)
-+{
-+ if (name->attrCtx == NULL) {
-+ *minor = GSSEAP_NO_ATTR_CONTEXT;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
-+ return GSS_S_UNAVAILABLE;
-+
-+ try {
-+ if (*input != NULL)
-+ name->attrCtx->releaseAnyNameMapping(type_id, *input);
-+ *input = NULL;
-+ } catch (std::exception &e) {
-+ return name->attrCtx->mapException(minor, e);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapReleaseAttrContext(OM_uint32 *minor,
-+ gss_name_t name)
-+{
-+ if (name->attrCtx != NULL)
-+ delete name->attrCtx;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * Public accessor for initialisng a context from a GSS context. Also
-+ * sets expiry time on GSS context as a side-effect.
-+ */
-+OM_uint32
-+gssEapCreateAttrContext(OM_uint32 *minor,
-+ gss_cred_id_t gssCred,
-+ gss_ctx_id_t gssCtx,
-+ struct gss_eap_attr_ctx **pAttrContext,
-+ time_t *pExpiryTime)
-+{
-+ gss_eap_attr_ctx *ctx = NULL;
-+ OM_uint32 major;
-+
-+ GSSEAP_ASSERT(gssCtx != GSS_C_NO_CONTEXT);
-+
-+ *pAttrContext = NULL;
-+
-+ major = gssEapAttrProvidersInit(minor);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ try {
-+ /* Set *pAttrContext here to for reentrancy */
-+ *pAttrContext = ctx = new gss_eap_attr_ctx();
-+
-+ if (ctx->initWithGssContext(gssCred, gssCtx)) {
-+ *pExpiryTime = ctx->getExpiryTime();
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+ } else {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
-+ }
-+ } catch (std::exception &e) {
-+ if (ctx != NULL)
-+ major = ctx->mapException(minor, e);
-+ }
-+
-+ if (GSS_ERROR(major)) {
-+ delete ctx;
-+ *pAttrContext = NULL;
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/util_attr.h b/mech_eap/util_attr.h
-new file mode 100644
-index 0000000..2af0850
---- /dev/null
-+++ b/mech_eap/util_attr.h
-@@ -0,0 +1,389 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Attribute provider interface.
-+ */
-+
-+#ifndef _UTIL_ATTR_H_
-+#define _UTIL_ATTR_H_ 1
-+
-+#ifdef __cplusplus
-+#include <string>
-+#include <new>
-+
-+using namespace gss_eap_util;
-+
-+struct gss_eap_attr_provider;
-+struct gss_eap_attr_ctx;
-+
-+typedef bool
-+(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_ctx *ctx,
-+ const gss_eap_attr_provider *source,
-+ const gss_buffer_t attribute,
-+ void *data);
-+
-+#define ATTR_TYPE_RADIUS 0U /* RADIUS AVPs */
-+#ifdef HAVE_OPENSAML
-+#define ATTR_TYPE_SAML_ASSERTION 1U /* SAML assertion */
-+#define ATTR_TYPE_SAML 2U /* SAML attributes */
-+#endif
-+#define ATTR_TYPE_LOCAL 3U /* Local attributes */
-+#define ATTR_TYPE_MIN ATTR_TYPE_RADIUS
-+#define ATTR_TYPE_MAX ATTR_TYPE_LOCAL
-+
-+#define ATTR_FLAG_DISABLE_LOCAL 0x00000001
-+
-+/*
-+ * Attribute provider: this represents a source of attributes derived
-+ * from the security context.
-+ */
-+struct gss_eap_attr_provider
-+{
-+public:
-+ gss_eap_attr_provider(void) {}
-+ virtual ~gss_eap_attr_provider(void) {}
-+
-+ bool initWithManager(const gss_eap_attr_ctx *manager)
-+ {
-+ m_manager = manager;
-+ return true;
-+ }
-+
-+ virtual bool initWithExistingContext(const gss_eap_attr_ctx *manager,
-+ const gss_eap_attr_provider *ctx GSSEAP_UNUSED)
-+ {
-+ return initWithManager(manager);
-+ }
-+
-+ virtual bool initWithGssContext(const gss_eap_attr_ctx *manager,
-+ const gss_cred_id_t cred GSSEAP_UNUSED,
-+ const gss_ctx_id_t ctx GSSEAP_UNUSED)
-+ {
-+ return initWithManager(manager);
-+ }
-+
-+ virtual bool getAttributeTypes(gss_eap_attr_enumeration_cb GSSEAP_UNUSED,
-+ void *data GSSEAP_UNUSED) const
-+ {
-+ return false;
-+ }
-+
-+ virtual bool setAttribute(int complete GSSEAP_UNUSED,
-+ const gss_buffer_t attr GSSEAP_UNUSED,
-+ const gss_buffer_t value GSSEAP_UNUSED)
-+ {
-+ return false;
-+ }
-+
-+ virtual bool deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
-+ {
-+ return false;
-+ }
-+
-+ virtual bool getAttribute(const gss_buffer_t attr GSSEAP_UNUSED,
-+ int *authenticated GSSEAP_UNUSED,
-+ int *complete GSSEAP_UNUSED,
-+ gss_buffer_t value GSSEAP_UNUSED,
-+ gss_buffer_t display_value GSSEAP_UNUSED,
-+ int *more GSSEAP_UNUSED) const
-+ {
-+ return false;
-+ }
-+
-+ virtual gss_any_t mapToAny(int authenticated GSSEAP_UNUSED,
-+ gss_buffer_t type_id GSSEAP_UNUSED) const
-+ {
-+ return NULL;
-+ }
-+
-+ virtual void releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
-+ gss_any_t input GSSEAP_UNUSED) const
-+ {
-+ }
-+
-+ /* prefix to be prepended to attributes emitted by gss_get_name_attribute */
-+ virtual const char *prefix(void) const
-+ {
-+ return NULL;
-+ }
-+
-+ /* optional key for storing JSON dictionary */
-+ virtual const char *name(void) const
-+ {
-+ return NULL;
-+ }
-+
-+ virtual bool initWithJsonObject(const gss_eap_attr_ctx *manager,
-+ JSONObject &object GSSEAP_UNUSED)
-+ {
-+ return initWithManager(manager);
-+ }
-+
-+
-+ virtual JSONObject jsonRepresentation(void) const
-+ {
-+ return JSONObject::null();
-+ }
-+
-+ virtual time_t getExpiryTime(void) const { return 0; }
-+
-+ virtual OM_uint32 mapException(OM_uint32 *minor GSSEAP_UNUSED,
-+ std::exception &e GSSEAP_UNUSED) const
-+ {
-+ return GSS_S_CONTINUE_NEEDED;
-+ }
-+
-+ static bool init(void) { return true; }
-+ static void finalize(void) {}
-+
-+ static gss_eap_attr_provider *createAttrContext(void) { return NULL; }
-+
-+protected:
-+ const gss_eap_attr_ctx *m_manager;
-+
-+private:
-+ /* make non-copyable */
-+ gss_eap_attr_provider(const gss_eap_attr_provider&);
-+ gss_eap_attr_provider& operator=(const gss_eap_attr_provider&);
-+};
-+
-+typedef gss_eap_attr_provider *(*gss_eap_attr_create_provider)(void);
-+
-+/*
-+ * Attribute context: this manages a set of providers for a given
-+ * security context.
-+ */
-+struct gss_eap_attr_ctx
-+{
-+public:
-+ gss_eap_attr_ctx(void);
-+ ~gss_eap_attr_ctx(void);
-+
-+ bool initWithExistingContext(const gss_eap_attr_ctx *manager);
-+ bool initWithGssContext(const gss_cred_id_t cred,
-+ const gss_ctx_id_t ctx);
-+
-+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
-+ bool getAttributeTypes(gss_buffer_set_t *attrs);
-+
-+ bool setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(const gss_buffer_t value);
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ gss_any_t mapToAny(int authenticated,
-+ gss_buffer_t type_id) const;
-+ void releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const;
-+
-+ void exportToBuffer(gss_buffer_t buffer) const;
-+ bool initWithBuffer(const gss_buffer_t buffer);
-+
-+ static std::string
-+ composeAttributeName(const gss_buffer_t prefix,
-+ const gss_buffer_t suffix);
-+ static void
-+ decomposeAttributeName(const gss_buffer_t attribute,
-+ gss_buffer_t prefix,
-+ gss_buffer_t suffix);
-+ static void
-+ composeAttributeName(const gss_buffer_t prefix,
-+ const gss_buffer_t suffix,
-+ gss_buffer_t attribute);
-+
-+ std::string
-+ composeAttributeName(unsigned int type,
-+ const gss_buffer_t suffix);
-+ void
-+ decomposeAttributeName(const gss_buffer_t attribute,
-+ unsigned int *type,
-+ gss_buffer_t suffix) const;
-+ void
-+ composeAttributeName(unsigned int type,
-+ const gss_buffer_t suffix,
-+ gss_buffer_t attribute) const;
-+
-+ gss_eap_attr_provider *getProvider(unsigned int type) const;
-+
-+ static void
-+ registerProvider(unsigned int type,
-+ gss_eap_attr_create_provider factory);
-+ static void
-+ unregisterProvider(unsigned int type);
-+
-+ time_t getExpiryTime(void) const;
-+ OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
-+
-+private:
-+ bool providerEnabled(unsigned int type) const;
-+ void releaseProvider(unsigned int type);
-+
-+ unsigned int attributePrefixToType(const gss_buffer_t prefix) const;
-+ gss_buffer_desc attributeTypeToPrefix(unsigned int type) const;
-+
-+ bool initWithJsonObject(JSONObject &object);
-+ JSONObject jsonRepresentation(void) const;
-+
-+ gss_eap_attr_provider *getPrimaryProvider(void) const;
-+
-+ /* make non-copyable */
-+ gss_eap_attr_ctx(const gss_eap_attr_ctx&);
-+ gss_eap_attr_ctx& operator=(const gss_eap_attr_ctx&);
-+
-+ uint32_t m_flags;
-+ gss_eap_attr_provider *m_providers[ATTR_TYPE_MAX + 1];
-+};
-+
-+#endif /* __cplusplus */
-+
-+#include "util_radius.h"
-+#include "util_saml.h"
-+#include "util_shib.h"
-+
-+#ifdef __cplusplus
-+
-+static inline void
-+duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
-+{
-+ OM_uint32 minor;
-+
-+ if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
-+ throw std::bad_alloc();
-+}
-+
-+static inline void
-+duplicateBuffer(std::string &str, gss_buffer_t buffer)
-+{
-+ gss_buffer_desc tmp;
-+
-+ tmp.length = str.length();
-+ tmp.value = (char *)str.c_str();
-+
-+ duplicateBuffer(tmp, buffer);
-+}
-+
-+#else
-+struct gss_eap_attr_ctx;
-+#endif
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * C wrappers for attribute context functions. These match their
-+ * GSS naming extension equivalents. The caller is required to
-+ * obtain the name mutex.
-+ */
-+
-+OM_uint32
-+gssEapCreateAttrContext(OM_uint32 *minor,
-+ gss_cred_id_t acceptorCred,
-+ gss_ctx_id_t acceptorCtx,
-+ struct gss_eap_attr_ctx **pAttrCtx,
-+ time_t *pExpiryTime);
-+
-+OM_uint32
-+gssEapInquireName(OM_uint32 *minor,
-+ gss_name_t name,
-+ int *name_is_MN,
-+ gss_OID *MN_mech,
-+ gss_buffer_set_t *attrs);
-+
-+OM_uint32
-+gssEapGetNameAttribute(OM_uint32 *minor,
-+ 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
-+gssEapDeleteNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t attr);
-+
-+OM_uint32
-+gssEapSetNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ int complete,
-+ gss_buffer_t attr,
-+ gss_buffer_t value);
-+
-+OM_uint32
-+gssEapExportAttrContext(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t buffer);
-+
-+OM_uint32
-+gssEapImportAttrContext(OM_uint32 *minor,
-+ gss_buffer_t buffer,
-+ gss_name_t name);
-+
-+OM_uint32
-+gssEapDuplicateAttrContext(OM_uint32 *minor,
-+ gss_name_t in,
-+ gss_name_t out);
-+
-+OM_uint32
-+gssEapMapNameToAny(OM_uint32 *minor,
-+ gss_name_t name,
-+ int authenticated,
-+ gss_buffer_t type_id,
-+ gss_any_t *output);
-+
-+OM_uint32
-+gssEapReleaseAnyNameMapping(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t type_id,
-+ gss_any_t *input);
-+
-+OM_uint32
-+gssEapReleaseAttrContext(OM_uint32 *minor,
-+ gss_name_t name);
-+
-+OM_uint32
-+gssEapAttrProvidersFinalize(OM_uint32 *minor);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _UTIL_ATTR_H_ */
-diff --git a/mech_eap/util_base64.c b/mech_eap/util_base64.c
-new file mode 100644
-index 0000000..aaa1ea8
---- /dev/null
-+++ b/mech_eap/util_base64.c
-@@ -0,0 +1,161 @@
-+/*
-+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
-+ * (Royal Institute of Technology, Stockholm, Sweden).
-+ * All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ *
-+ * 3. Neither the name of the Institute nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
-+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
-+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-+ * SUCH DAMAGE.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static const char base64_chars[] =
-+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-+
-+static int
-+pos(char c)
-+{
-+ const char *p;
-+ for (p = base64_chars; *p; p++)
-+ if (*p == c)
-+ return p - base64_chars;
-+ return -1;
-+}
-+
-+ssize_t
-+base64Encode(const void *data, int size, char **str)
-+{
-+ char *s, *p;
-+ int i;
-+ int c;
-+ const unsigned char *q;
-+
-+ if (size > INT_MAX/4 || size < 0) {
-+ *str = NULL;
-+ return -1;
-+ }
-+
-+ p = s = (char *)GSSEAP_MALLOC(BASE64_EXPAND(size));
-+ if (p == NULL) {
-+ *str = NULL;
-+ return -1;
-+ }
-+ q = (const unsigned char *) data;
-+
-+ for (i = 0; i < size;) {
-+ c = q[i++];
-+ c *= 256;
-+ if (i < size)
-+ c += q[i];
-+ i++;
-+ c *= 256;
-+ if (i < size)
-+ c += q[i];
-+ i++;
-+ p[0] = base64_chars[(c & 0x00fc0000) >> 18];
-+ p[1] = base64_chars[(c & 0x0003f000) >> 12];
-+ p[2] = base64_chars[(c & 0x00000fc0) >> 6];
-+ p[3] = base64_chars[(c & 0x0000003f) >> 0];
-+ if (i > size)
-+ p[3] = '=';
-+ if (i > size + 1)
-+ p[2] = '=';
-+ p += 4;
-+ }
-+ *p = 0;
-+ *str = s;
-+ return strlen(s);
-+}
-+
-+#define DECODE_ERROR 0xffffffff
-+
-+static unsigned int
-+token_decode(const char *token)
-+{
-+ int i;
-+ unsigned int val = 0;
-+ int marker = 0;
-+ if (strlen(token) < 4)
-+ return DECODE_ERROR;
-+ for (i = 0; i < 4; i++) {
-+ val *= 64;
-+ if (token[i] == '=')
-+ marker++;
-+ else if (marker > 0)
-+ return DECODE_ERROR;
-+ else
-+ val += pos(token[i]);
-+ }
-+ if (marker > 2)
-+ return DECODE_ERROR;
-+ return (marker << 24) | val;
-+}
-+
-+ssize_t
-+base64Decode(const char *str, void *data)
-+{
-+ const char *p;
-+ unsigned char *q;
-+
-+ q = data;
-+ p = str;
-+
-+ while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
-+ unsigned int val = token_decode(p);
-+ unsigned int marker = (val >> 24) & 0xff;
-+ if (val == DECODE_ERROR)
-+ return -1;
-+ *q++ = (val >> 16) & 0xff;
-+ if (marker < 2)
-+ *q++ = (val >> 8) & 0xff;
-+ if (marker < 1)
-+ *q++ = val & 0xff;
-+ p += 4;
-+ if (*p == '\n')
-+ p++;
-+ }
-+ return q - (unsigned char *) data;
-+}
-+
-+int
-+base64Valid(const char *str)
-+{
-+ const char *p = str;
-+ int valid = 1;
-+
-+ while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
-+ unsigned int val = token_decode(p);
-+ if (val == DECODE_ERROR) {
-+ valid = 0;
-+ break;
-+ }
-+ p += 4;
-+ if (*p == '\n')
-+ p++;
-+ }
-+ return valid;
-+}
-diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h
-new file mode 100644
-index 0000000..d015efe
---- /dev/null
-+++ b/mech_eap/util_base64.h
-@@ -0,0 +1,58 @@
-+/*
-+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
-+ * (Royal Institute of Technology, Stockholm, Sweden).
-+ * All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ *
-+ * 3. Neither the name of the Institute nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
-+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
-+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-+ * SUCH DAMAGE.
-+ */
-+
-+/* $Id$ */
-+
-+#ifndef _UTIL_BASE64_H_
-+#define _UTIL_BASE64_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+ssize_t
-+base64Encode(const void *, int, char **);
-+
-+ssize_t
-+base64Decode(const char *, void *);
-+
-+int
-+base64Valid(const char *str);
-+
-+#define BASE64_EXPAND(n) (n * 4 / 3 + 4)
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-diff --git a/mech_eap/util_buffer.c b/mech_eap/util_buffer.c
-new file mode 100644
-index 0000000..e135db9
---- /dev/null
-+++ b/mech_eap/util_buffer.c
-@@ -0,0 +1,103 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Buffer handling helpers.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+makeStringBuffer(OM_uint32 *minor,
-+ const char *string,
-+ gss_buffer_t buffer)
-+{
-+ size_t len = strlen(string);
-+
-+ buffer->value = GSSEAP_MALLOC(len + 1);
-+ if (buffer->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+ memcpy(buffer->value, string, len + 1);
-+ buffer->length = len;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+bufferToString(OM_uint32 *minor,
-+ const gss_buffer_t buffer,
-+ char **pString)
-+{
-+ char *s;
-+
-+ s = GSSEAP_MALLOC(buffer->length + 1);
-+ if (s == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+ memcpy(s, buffer->value, buffer->length);
-+ s[buffer->length] = '\0';
-+
-+ *pString = s;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+duplicateBuffer(OM_uint32 *minor,
-+ const gss_buffer_t src,
-+ gss_buffer_t dst)
-+{
-+ dst->length = 0;
-+ dst->value = NULL;
-+
-+ if (src == GSS_C_NO_BUFFER)
-+ return GSS_S_COMPLETE;
-+
-+ dst->value = GSSEAP_MALLOC(src->length + 1);
-+ if (dst->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ dst->length = src->length;
-+ memcpy(dst->value, src->value, dst->length);
-+
-+ ((unsigned char *)dst->value)[dst->length] = '\0';
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/util_cksum.c b/mech_eap/util_cksum.c
-new file mode 100644
-index 0000000..aedc93e
---- /dev/null
-+++ b/mech_eap/util_cksum.c
-@@ -0,0 +1,242 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Message protection services: checksum helpers.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static int
-+gssEapChecksum(krb5_context context,
-+ krb5_cksumtype type,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ krb5_keyusage sign_usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ int verify,
-+ int *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;
-+ size_t k5_checksumlen;
-+
-+ if (verify)
-+ *valid = FALSE;
-+
-+ code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
-+ if (code != 0)
-+ return code;
-+
-+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
-+ GSSEAP_ASSERT(header != NULL);
-+
-+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
-+ GSSEAP_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 *)GSSEAP_MALLOC(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 = gssEapMapCryptoFlag(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++;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (verify) {
-+ code = krb5_verify_checksum_iov(context, crypto, sign_usage,
-+ kiov, kiov_count, &type);
-+ *valid = (code == 0);
-+ } else {
-+ code = krb5_create_checksum_iov(context, crypto, sign_usage,
-+ kiov, kiov_count, &type);
-+ }
-+#else
-+ if (verify) {
-+ krb5_boolean kvalid = FALSE;
-+
-+ code = krb5_c_verify_checksum_iov(context, type, crypto,
-+ sign_usage, kiov, kiov_count, &kvalid);
-+
-+ *valid = kvalid;
-+ } else {
-+ code = krb5_c_make_checksum_iov(context, type, crypto,
-+ sign_usage, kiov, kiov_count);
-+ }
-+#endif /* HAVE_HEIMDAL_VERSION */
-+
-+ GSSEAP_FREE(kiov);
-+
-+ return code;
-+}
-+
-+int
-+gssEapSign(krb5_context context,
-+ krb5_cksumtype type,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ krb5_keyusage sign_usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ return gssEapChecksum(context, type, rrc, crypto,
-+ sign_usage, iov, iov_count, 0, NULL);
-+}
-+
-+int
-+gssEapVerify(krb5_context context,
-+ krb5_cksumtype type,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ krb5_keyusage sign_usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ int *valid)
-+{
-+ return gssEapChecksum(context, type, rrc, crypto,
-+ sign_usage, iov, iov_count, 1, valid);
-+}
-+
-+#if 0
-+OM_uint32
-+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t encodedBindings)
-+{
-+ OM_uint32 major, tmpMinor;
-+ size_t length;
-+ unsigned char *p;
-+
-+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
-+ length = 24;
-+ length += chanBindings->initiator_address.length;
-+ length += chanBindings->acceptor_address.length;
-+ length += chanBindings->application_data.length;
-+
-+ encodedBindings->value = GSSEAP_MALLOC(length);
-+ if (encodedBindings->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ encodedBindings->length = length;
-+ p = (unsigned char *)encodedBindings->value;
-+
-+ store_uint32_be(chanBindings->initiator_addrtype, p);
-+ store_buffer(&chanBindings->initiator_address, p + 4, 0);
-+ p += 4 + chanBindings->initiator_address.length;
-+
-+ store_uint32_be(chanBindings->acceptor_addrtype, p);
-+ store_buffer(&chanBindings->acceptor_address, p + 4, 0);
-+ p += 4 + chanBindings->acceptor_address.length;
-+
-+ store_buffer(&chanBindings->application_data, p, 1);
-+ p += chanBindings->application_data.length;
-+ } else {
-+ encodedBindings->length = 0;
-+ encodedBindings->value = NULL;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+#endif
-diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c
-new file mode 100644
-index 0000000..e18edc5
---- /dev/null
-+++ b/mech_eap/util_context.c
-@@ -0,0 +1,377 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Utility routines for context handles.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+gssEapAllocContext(OM_uint32 *minor,
-+ gss_ctx_id_t *pCtx)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_ctx_id_t ctx;
-+
-+ GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT);
-+
-+ ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
-+ if (ctx == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
-+ *minor = GSSEAP_GET_LAST_ERROR();
-+ gssEapReleaseContext(&tmpMinor, &ctx);
-+ return GSS_S_FAILURE;
-+ }
-+
-+ ctx->state = GSSEAP_STATE_INITIAL;
-+ ctx->mechanismUsed = GSS_C_NO_OID;
-+
-+ /*
-+ * Integrity, confidentiality, sequencing and replay detection are
-+ * always available. Regardless of what flags are requested in
-+ * GSS_Init_sec_context, implementations MUST set the flag corresponding
-+ * to these services in the output of GSS_Init_sec_context and
-+ * GSS_Accept_sec_context.
-+ */
-+ ctx->gssFlags = GSS_C_TRANS_FLAG | /* exporting contexts */
-+ GSS_C_INTEG_FLAG | /* integrity */
-+ GSS_C_CONF_FLAG | /* confidentiality */
-+ GSS_C_SEQUENCE_FLAG | /* sequencing */
-+ GSS_C_REPLAY_FLAG; /* replay detection */
-+
-+ *pCtx = ctx;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static void
-+releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
-+{
-+ eap_peer_sm_deinit(ctx->eap);
-+}
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+static void
-+releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
-+{
-+ OM_uint32 tmpMinor;
-+
-+ if (ctx->radConn != NULL)
-+ rs_conn_destroy(ctx->radConn);
-+ if (ctx->radContext != NULL)
-+ rs_context_destroy(ctx->radContext);
-+ if (ctx->radServer != NULL)
-+ GSSEAP_FREE(ctx->radServer);
-+ gss_release_buffer(&tmpMinor, &ctx->state);
-+ if (ctx->vps != NULL)
-+ gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
-+}
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+OM_uint32
-+gssEapReleaseContext(OM_uint32 *minor,
-+ gss_ctx_id_t *pCtx)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_ctx_id_t ctx = *pCtx;
-+ krb5_context krbContext = NULL;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ gssEapKerberosInit(&tmpMinor, &krbContext);
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
-+ gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
-+ } else
-+#endif /* GSSEAP_ENABLE_REAUTH */
-+ if (CTX_IS_INITIATOR(ctx)) {
-+ releaseInitiatorContext(&ctx->initiatorCtx);
-+ }
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ else {
-+ releaseAcceptorContext(&ctx->acceptorCtx);
-+ }
-+#endif /* GSSEAP_ENABLE_ACCEPTOR */
-+
-+ krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
-+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
-+ gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
-+ gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
-+ sequenceFree(&tmpMinor, &ctx->seqState);
-+ gssEapReleaseCred(&tmpMinor, &ctx->cred);
-+
-+ GSSEAP_MUTEX_DESTROY(&ctx->mutex);
-+
-+ memset(ctx, 0, sizeof(*ctx));
-+ GSSEAP_FREE(ctx);
-+ *pCtx = GSS_C_NO_CONTEXT;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapMakeToken(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t innerToken,
-+ enum gss_eap_token_type tokenType,
-+ gss_buffer_t outputToken)
-+{
-+ unsigned char *p;
-+
-+ GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
-+
-+ outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
-+ outputToken->value = GSSEAP_MALLOC(outputToken->length);
-+ if (outputToken->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ p = (unsigned char *)outputToken->value;
-+ makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType);
-+ memcpy(p, innerToken->value, innerToken->length);
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapVerifyToken(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t inputToken,
-+ enum gss_eap_token_type *actualToken,
-+ gss_buffer_t innerInputToken)
-+{
-+ OM_uint32 major;
-+ size_t bodySize;
-+ unsigned char *p = (unsigned char *)inputToken->value;
-+ gss_OID_desc oidBuf;
-+ gss_OID oid;
-+
-+ if (ctx->mechanismUsed != GSS_C_NO_OID) {
-+ oid = ctx->mechanismUsed;
-+ } else {
-+ oidBuf.elements = NULL;
-+ oidBuf.length = 0;
-+ oid = &oidBuf;
-+ }
-+
-+ major = verifyTokenHeader(minor, oid, &bodySize, &p,
-+ inputToken->length, actualToken);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ if (ctx->mechanismUsed == GSS_C_NO_OID) {
-+ major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed);
-+ if (GSS_ERROR(major))
-+ return major;
-+ }
-+
-+ innerInputToken->length = bodySize;
-+ innerInputToken->value = p;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapContextTime(OM_uint32 *minor,
-+ gss_ctx_id_t context_handle,
-+ OM_uint32 *time_rec)
-+{
-+ *minor = 0;
-+
-+ if (context_handle->expiryTime == 0) {
-+ *time_rec = GSS_C_INDEFINITE;
-+ } else {
-+ time_t now, lifetime;
-+
-+ time(&now);
-+ lifetime = context_handle->expiryTime - now;
-+ if (lifetime <= 0) {
-+ *time_rec = 0;
-+ return GSS_S_CONTEXT_EXPIRED;
-+ }
-+ *time_rec = lifetime;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t tokenMIC,
-+ int verifyMIC)
-+{
-+ OM_uint32 major;
-+ gss_iov_buffer_desc *iov = NULL;
-+ size_t i = 0, j;
-+ enum gss_eap_token_type tokType;
-+ OM_uint32 micTokType;
-+ unsigned char wireTokType[2];
-+ unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
-+ const struct gss_eap_token_buffer_set *tokens;
-+
-+ tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
-+
-+ GSSEAP_ASSERT(tokens != NULL);
-+
-+ iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
-+ if (iov == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
-+ if (innerTokTypes == NULL) {
-+ *minor = ENOMEM;
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+
-+ innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
-+ if (innerTokLengths == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ /* Mechanism OID */
-+ GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[i].buffer.length = ctx->mechanismUsed->length;
-+ iov[i].buffer.value = ctx->mechanismUsed->elements;
-+ i++;
-+
-+ /* Token type */
-+ if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
-+ tokType = TOK_TYPE_INITIATOR_CONTEXT;
-+ micTokType = ITOK_TYPE_INITIATOR_MIC;
-+ } else {
-+ tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
-+ micTokType = ITOK_TYPE_ACCEPTOR_MIC;
-+ }
-+ store_uint16_be(tokType, wireTokType);
-+
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[i].buffer.length = sizeof(wireTokType);
-+ iov[i].buffer.value = wireTokType;
-+ i++;
-+
-+ for (j = 0; j < tokens->buffers.count; j++) {
-+ if (verifyMIC &&
-+ (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
-+ continue; /* will use this slot for trailer */
-+
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[i].buffer.length = 4;
-+ iov[i].buffer.value = &innerTokTypes[j * 4];
-+ store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
-+ iov[i].buffer.value);
-+ i++;
-+
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[i].buffer.length = 4;
-+ iov[i].buffer.value = &innerTokLengths[j * 4];
-+ store_uint32_be(tokens->buffers.elements[j].length,
-+ iov[i].buffer.value);
-+ i++;
-+
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[i].buffer = tokens->buffers.elements[j];
-+ i++;
-+ }
-+
-+ if (verifyMIC) {
-+ GSSEAP_ASSERT(tokenMIC->length >= 16);
-+
-+ GSSEAP_ASSERT(i < 2 + (3 * tokens->buffers.count));
-+
-+ iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
-+ iov[i].buffer = *tokenMIC;
-+ i++;
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-+ iov, i, TOK_TYPE_MIC);
-+ } else {
-+ iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-+ major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
-+ iov, i, TOK_TYPE_MIC);
-+ if (!GSS_ERROR(major))
-+ *tokenMIC = iov[i - 1].buffer;
-+ }
-+
-+cleanup:
-+ if (iov != NULL)
-+ gssEapReleaseIov(iov, tokens->buffers.count);
-+ if (innerTokTypes != NULL)
-+ GSSEAP_FREE(innerTokTypes);
-+ if (innerTokLengths != NULL)
-+ GSSEAP_FREE(innerTokLengths);
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapMakeTokenMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t tokenMIC)
-+{
-+ tokenMIC->length = 0;
-+ tokenMIC->value = NULL;
-+
-+ return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE);
-+}
-+
-+OM_uint32
-+gssEapVerifyTokenMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_buffer_t tokenMIC)
-+{
-+ if (tokenMIC->length < 16) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_BAD_SIG;
-+ }
-+
-+ return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
-+}
-diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c
-new file mode 100644
-index 0000000..746bd61
---- /dev/null
-+++ b/mech_eap/util_cred.c
-@@ -0,0 +1,756 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Utility routines for credential handles.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#ifdef WIN32
-+# include <shlobj.h> /* may need to use ShFolder.h instead */
-+# include <stdio.h>
-+#else
-+# include <pwd.h>
-+#endif
-+
-+OM_uint32
-+gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_cred_id_t cred;
-+
-+ *pCred = GSS_C_NO_CREDENTIAL;
-+
-+ cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
-+ if (cred == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
-+ *minor = GSSEAP_GET_LAST_ERROR();
-+ gssEapReleaseCred(&tmpMinor, &cred);
-+ return GSS_S_FAILURE;
-+ }
-+
-+ *pCred = cred;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static void
-+zeroAndReleasePassword(gss_buffer_t password)
-+{
-+ if (password->value != NULL) {
-+ memset(password->value, 0, password->length);
-+ GSSEAP_FREE(password->value);
-+ }
-+
-+ password->value = NULL;
-+ password->length = 0;
-+}
-+
-+OM_uint32
-+gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_cred_id_t cred = *pCred;
-+ krb5_context krbContext = NULL;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL) {
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ gssEapReleaseName(&tmpMinor, &cred->name);
-+ gssEapReleaseName(&tmpMinor, &cred->target);
-+
-+ zeroAndReleasePassword(&cred->password);
-+
-+ gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
-+ gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
-+ gss_release_buffer(&tmpMinor, &cred->caCertificate);
-+ gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
-+ gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ if (cred->krbCredCache != NULL) {
-+ if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
-+ krb5_cc_close(krbContext, cred->krbCredCache);
-+ else
-+ krb5_cc_destroy(krbContext, cred->krbCredCache);
-+ }
-+ if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
-+ gssReleaseCred(&tmpMinor, &cred->reauthCred);
-+#endif
-+
-+ GSSEAP_MUTEX_DESTROY(&cred->mutex);
-+ memset(cred, 0, sizeof(*cred));
-+ GSSEAP_FREE(cred);
-+ *pCred = NULL;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+readStaticIdentityFile(OM_uint32 *minor,
-+ gss_buffer_t defaultIdentity,
-+ gss_buffer_t defaultPassword)
-+{
-+ OM_uint32 major, tmpMinor;
-+ FILE *fp = NULL;
-+ char buf[BUFSIZ];
-+ char *ccacheName;
-+ int i = 0;
-+#ifndef WIN32
-+ struct passwd *pw = NULL, pwd;
-+ char pwbuf[BUFSIZ];
-+#endif
-+
-+ defaultIdentity->length = 0;
-+ defaultIdentity->value = NULL;
-+
-+ if (defaultPassword != GSS_C_NO_BUFFER) {
-+ defaultPassword->length = 0;
-+ defaultPassword->value = NULL;
-+ }
-+
-+ ccacheName = getenv("GSSEAP_IDENTITY");
-+ if (ccacheName == NULL) {
-+#ifdef WIN32
-+ TCHAR szPath[MAX_PATH];
-+
-+ if (!SUCCEEDED(SHGetFolderPath(NULL,
-+ CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
-+ NULL, /* User access token */
-+ 0, /* SHGFP_TYPE_CURRENT */
-+ szPath))) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
-+ goto cleanup;
-+ }
-+
-+ snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
-+#else
-+ if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
-+ pw == NULL || pw->pw_dir == NULL) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_GET_LAST_ERROR();
-+ goto cleanup;
-+ }
-+
-+ snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
-+#endif /* WIN32 */
-+ ccacheName = buf;
-+ }
-+
-+ fp = fopen(ccacheName, "r");
-+ if (fp == NULL) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_NO_DEFAULT_CRED;
-+ goto cleanup;
-+ }
-+
-+ while (fgets(buf, sizeof(buf), fp) != NULL) {
-+ gss_buffer_desc src, *dst;
-+
-+ src.length = strlen(buf);
-+ src.value = buf;
-+
-+ if (src.length == 0)
-+ break;
-+
-+ if (buf[src.length - 1] == '\n') {
-+ buf[src.length - 1] = '\0';
-+ if (--src.length == 0)
-+ break;
-+ }
-+
-+ if (i == 0)
-+ dst = defaultIdentity;
-+ else if (i == 1)
-+ dst = defaultPassword;
-+ else
-+ break;
-+
-+ if (dst != GSS_C_NO_BUFFER) {
-+ major = duplicateBuffer(minor, &src, dst);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ i++;
-+ }
-+
-+ if (defaultIdentity->length == 0) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_NO_DEFAULT_CRED;
-+ goto cleanup;
-+ }
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (fp != NULL)
-+ fclose(fp);
-+
-+ if (GSS_ERROR(major)) {
-+ gss_release_buffer(&tmpMinor, defaultIdentity);
-+ zeroAndReleasePassword(defaultPassword);
-+ }
-+
-+ memset(buf, 0, sizeof(buf));
-+
-+ return major;
-+}
-+
-+gss_OID
-+gssEapPrimaryMechForCred(gss_cred_id_t cred)
-+{
-+ gss_OID nameMech = GSS_C_NO_OID;
-+
-+ if (cred->mechanisms != GSS_C_NO_OID_SET &&
-+ cred->mechanisms->count == 1)
-+ nameMech = &cred->mechanisms->elements[0];
-+
-+ return nameMech;
-+}
-+
-+OM_uint32
-+gssEapAcquireCred(OM_uint32 *minor,
-+ const gss_name_t desiredName,
-+ OM_uint32 timeReq GSSEAP_UNUSED,
-+ const gss_OID_set desiredMechs,
-+ int credUsage,
-+ gss_cred_id_t *pCred,
-+ gss_OID_set *pActualMechs,
-+ OM_uint32 *timeRec)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_cred_id_t cred;
-+
-+ /* XXX TODO validate with changed set_cred_option API */
-+ *pCred = GSS_C_NO_CREDENTIAL;
-+
-+ major = gssEapAllocCred(minor, &cred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ switch (credUsage) {
-+ case GSS_C_BOTH:
-+ cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
-+ break;
-+ case GSS_C_INITIATE:
-+ cred->flags |= CRED_FLAG_INITIATE;
-+ break;
-+ case GSS_C_ACCEPT:
-+ cred->flags |= CRED_FLAG_ACCEPT;
-+ break;
-+ default:
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_BAD_USAGE;
-+ goto cleanup;
-+ break;
-+ }
-+
-+ major = gssEapValidateMechs(minor, desiredMechs);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (desiredName != GSS_C_NO_NAME) {
-+ GSSEAP_MUTEX_LOCK(&desiredName->mutex);
-+
-+ major = gssEapDuplicateName(minor, desiredName, &cred->name);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
-+ goto cleanup;
-+ }
-+
-+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
-+ }
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ if (cred->flags & CRED_FLAG_ACCEPT) {
-+ struct rs_context *radContext;
-+
-+ major = gssEapCreateRadiusContext(minor, cred, &radContext);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ rs_context_destroy(radContext);
-+ }
-+#endif
-+
-+ if (pActualMechs != NULL) {
-+ major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (timeRec != NULL)
-+ *timeRec = GSS_C_INDEFINITE;
-+
-+ *pCred = cred;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gssEapReleaseCred(&tmpMinor, &cred);
-+
-+ return major;
-+}
-+
-+/*
-+ * Return TRUE if cred available for mechanism. Caller need no acquire
-+ * lock because mechanisms list is immutable.
-+ */
-+int
-+gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
-+{
-+ OM_uint32 minor;
-+ int present = 0;
-+
-+ GSSEAP_ASSERT(mech != GSS_C_NO_OID);
-+
-+ if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
-+ return TRUE;
-+
-+ gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
-+
-+ return present;
-+}
-+
-+static OM_uint32
-+staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_OID nameMech = gssEapPrimaryMechForCred(cred);
-+ gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
-+
-+ *pName = GSS_C_NO_NAME;
-+
-+ major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
-+ if (major == GSS_S_COMPLETE) {
-+ major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
-+ nameMech, pName);
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &defaultIdentity);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+gssEapResolveCredIdentity(OM_uint32 *minor,
-+ gss_cred_id_t cred)
-+{
-+ OM_uint32 major;
-+ gss_OID nameMech = gssEapPrimaryMechForCred(cred);
-+
-+ if (cred->name != GSS_C_NO_NAME) {
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ if (cred->flags & CRED_FLAG_ACCEPT) {
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+ char serviceName[5 + MAXHOSTNAMELEN];
-+
-+ /* default host-based service is host@localhost */
-+ memcpy(serviceName, "host@", 5);
-+ if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
-+ *minor = GSSEAP_NO_HOSTNAME;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ nameBuf.value = serviceName;
-+ nameBuf.length = strlen((char *)nameBuf.value);
-+
-+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
-+ nameMech, &cred->name);
-+ if (GSS_ERROR(major))
-+ return major;
-+ } else if (cred->flags & CRED_FLAG_INITIATE) {
-+#ifdef HAVE_MOONSHOT_GET_IDENTITY
-+ major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
-+ if (major == GSS_S_CRED_UNAVAIL)
-+#endif
-+ major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
-+ if (major != GSS_S_CRED_UNAVAIL)
-+ return major;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapInquireCred(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_name_t *name,
-+ OM_uint32 *pLifetime,
-+ gss_cred_usage_t *cred_usage,
-+ gss_OID_set *mechanisms)
-+{
-+ OM_uint32 major;
-+ time_t now, lifetime;
-+
-+ if (name != NULL) {
-+ major = gssEapResolveCredIdentity(minor, cred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (cred->name != GSS_C_NO_NAME) {
-+ major = gssEapDuplicateName(minor, cred->name, name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ } else
-+ *name = GSS_C_NO_NAME;
-+ }
-+
-+ if (cred_usage != NULL) {
-+ OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
-+
-+ switch (flags) {
-+ case CRED_FLAG_INITIATE:
-+ *cred_usage = GSS_C_INITIATE;
-+ break;
-+ case CRED_FLAG_ACCEPT:
-+ *cred_usage = GSS_C_ACCEPT;
-+ break;
-+ default:
-+ *cred_usage = GSS_C_BOTH;
-+ break;
-+ }
-+ }
-+
-+ if (mechanisms != NULL) {
-+ if (cred->mechanisms != GSS_C_NO_OID_SET)
-+ major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
-+ else
-+ major = gssEapIndicateMechs(minor, mechanisms);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (cred->expiryTime == 0) {
-+ lifetime = GSS_C_INDEFINITE;
-+ } else {
-+ now = time(NULL);
-+ lifetime = now - cred->expiryTime;
-+ if (lifetime < 0)
-+ lifetime = 0;
-+ }
-+
-+ if (pLifetime != NULL) {
-+ *pLifetime = lifetime;
-+ }
-+
-+ if (lifetime == 0) {
-+ major = GSS_S_CREDENTIALS_EXPIRED;
-+ *minor = GSSEAP_CRED_EXPIRED;
-+ goto cleanup;
-+ }
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapSetCredPassword(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_buffer_t password)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
-+
-+ if (cred->flags & CRED_FLAG_RESOLVED) {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_CRED_RESOLVED;
-+ goto cleanup;
-+ }
-+
-+ if (password != GSS_C_NO_BUFFER) {
-+ major = duplicateBuffer(minor, password, &newPassword);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ cred->flags |= CRED_FLAG_PASSWORD;
-+ } else {
-+ cred->flags &= ~(CRED_FLAG_PASSWORD);
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &cred->password);
-+ cred->password = newPassword;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapSetCredService(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_name_t target)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_name_t newTarget = GSS_C_NO_NAME;
-+
-+ if (cred->flags & CRED_FLAG_RESOLVED) {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_CRED_RESOLVED;
-+ goto cleanup;
-+ }
-+
-+ if (target != GSS_C_NO_NAME) {
-+ major = gssEapDuplicateName(minor, target, &newTarget);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ cred->flags |= CRED_FLAG_TARGET;
-+ } else {
-+ cred->flags &= ~(CRED_FLAG_TARGET);
-+ }
-+
-+ gssEapReleaseName(&tmpMinor, &cred->target);
-+ cred->target = newTarget;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ return major;
-+}
-+
-+static OM_uint32
-+gssEapDuplicateCred(OM_uint32 *minor,
-+ const gss_cred_id_t src,
-+ gss_cred_id_t *pDst)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
-+
-+ *pDst = GSS_C_NO_CREDENTIAL;
-+
-+ major = gssEapAllocCred(minor, &dst);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ dst->flags = src->flags;
-+
-+ if (src->name != GSS_C_NO_NAME) {
-+ major = gssEapDuplicateName(minor, src->name, &dst->name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (src->target != GSS_C_NO_NAME) {
-+ major = gssEapDuplicateName(minor, src->target, &dst->target);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (src->password.value != NULL) {
-+ major = duplicateBuffer(minor, &src->password, &dst->password);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ dst->expiryTime = src->expiryTime;
-+
-+ if (src->radiusConfigFile.value != NULL)
-+ duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
-+ if (src->radiusConfigStanza.value != NULL)
-+ duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
-+ if (src->caCertificate.value != NULL)
-+ duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
-+ if (src->subjectNameConstraint.value != NULL)
-+ duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
-+ if (src->subjectAltNameConstraint.value != NULL)
-+ duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
-+
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ /* XXX krbCredCache, reauthCred */
-+#endif
-+
-+ *pDst = dst;
-+ dst = GSS_C_NO_CREDENTIAL;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ gssEapReleaseCred(&tmpMinor, &dst);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
-+ gss_name_t defaultIdentityName = GSS_C_NO_NAME;
-+ gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
-+ int isDefaultIdentity = FALSE;
-+
-+ major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
-+ gssEapPrimaryMechForCred(cred), &defaultIdentityName);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (defaultIdentityName == GSS_C_NO_NAME) {
-+ if (cred->name == GSS_C_NO_NAME) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_NO_DEFAULT_IDENTITY;
-+ goto cleanup;
-+ }
-+ } else {
-+ if (cred->name == GSS_C_NO_NAME) {
-+ cred->name = defaultIdentityName;
-+ defaultIdentityName = GSS_C_NO_NAME;
-+ isDefaultIdentity = TRUE;
-+ } else {
-+ major = gssEapCompareName(minor, cred->name,
-+ defaultIdentityName, &isDefaultIdentity);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+ }
-+
-+ if (isDefaultIdentity &&
-+ (cred->flags & CRED_FLAG_PASSWORD) == 0) {
-+ major = gssEapSetCredPassword(minor, cred, &defaultPassword);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+cleanup:
-+ gssEapReleaseName(&tmpMinor, &defaultIdentityName);
-+ zeroAndReleasePassword(&defaultPassword);
-+ gss_release_buffer(&tmpMinor, &defaultIdentity);
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapResolveInitiatorCred(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ const gss_name_t targetName
-+#ifndef HAVE_MOONSHOT_GET_IDENTITY
-+ GSSEAP_UNUSED
-+#endif
-+ ,
-+ gss_cred_id_t *pResolvedCred)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL) {
-+ major = gssEapAcquireCred(minor,
-+ GSS_C_NO_NAME,
-+ GSS_C_INDEFINITE,
-+ GSS_C_NO_OID_SET,
-+ GSS_C_INITIATE,
-+ &resolvedCred,
-+ NULL,
-+ NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ } else {
-+ if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
-+ major = GSS_S_NO_CRED;
-+ *minor = GSSEAP_CRED_USAGE_MISMATCH;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapDuplicateCred(minor, cred, &resolvedCred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
-+#ifdef HAVE_MOONSHOT_GET_IDENTITY
-+ major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
-+ if (major == GSS_S_CRED_UNAVAIL)
-+#endif
-+ major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
-+ if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
-+ goto cleanup;
-+
-+ /* If we have a caller-supplied password, the credential is resolved. */
-+ if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_NO_DEFAULT_CRED;
-+ goto cleanup;
-+ }
-+
-+ resolvedCred->flags |= CRED_FLAG_RESOLVED;
-+ }
-+
-+ *pResolvedCred = resolvedCred;
-+ resolvedCred = GSS_C_NO_CREDENTIAL;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ gssEapReleaseCred(&tmpMinor, &resolvedCred);
-+
-+ return major;
-+}
-diff --git a/mech_eap/util_crypt.c b/mech_eap/util_crypt.c
-new file mode 100644
-index 0000000..b6e203e
---- /dev/null
-+++ b/mech_eap/util_crypt.c
-@@ -0,0 +1,397 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Message protection services: cryptography helpers.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/*
-+ * 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
-+mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ 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;
-+ size_t k5_headerlen = 0, k5_trailerlen = 0;
-+ size_t gss_headerlen, gss_trailerlen;
-+ krb5_error_code code;
-+
-+ *pkiov = NULL;
-+ *pkiov_count = 0;
-+
-+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
-+ GSSEAP_ASSERT(header != NULL);
-+
-+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
-+ GSSEAP_ASSERT(trailer == NULL || rrc == 0);
-+
-+ code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
-+ if (code != 0)
-+ return code;
-+
-+ code = krbCryptoLength(context, crypto, 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 *)GSSEAP_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 = gssEapMapCryptoFlag(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 = (char *)kiov[i - 1].data.data + ec + 16; /* E(Header) */
-+ i++;
-+
-+ *pkiov = kiov;
-+ *pkiov_count = i;
-+
-+ return 0;
-+}
-+
-+int
-+gssEapEncrypt(krb5_context context,
-+ int dce_style,
-+ size_t ec,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ int usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ krb5_error_code code;
-+ size_t kiov_count;
-+ krb5_crypto_iov *kiov = NULL;
-+
-+ code = mapIov(context, dce_style, ec, rrc, crypto,
-+ iov, iov_count, &kiov, &kiov_count);
-+ if (code != 0)
-+ goto cleanup;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_encrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
-+#else
-+ code = krb5_c_encrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
-+#endif
-+ if (code != 0)
-+ goto cleanup;
-+
-+cleanup:
-+ if (kiov != NULL)
-+ GSSEAP_FREE(kiov);
-+
-+ return code;
-+}
-+
-+int
-+gssEapDecrypt(krb5_context context,
-+ int dce_style,
-+ size_t ec,
-+ size_t rrc,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto crypto,
-+#else
-+ krb5_keyblock *crypto,
-+#endif
-+ int usage,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ krb5_error_code code;
-+ size_t kiov_count;
-+ krb5_crypto_iov *kiov;
-+
-+ code = mapIov(context, dce_style, ec, rrc, crypto,
-+ iov, iov_count, &kiov, &kiov_count);
-+ if (code != 0)
-+ goto cleanup;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_decrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
-+#else
-+ code = krb5_c_decrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
-+#endif
-+
-+cleanup:
-+ if (kiov != NULL)
-+ GSSEAP_FREE(kiov);
-+
-+ return code;
-+}
-+
-+int
-+gssEapMapCryptoFlag(OM_uint32 type)
-+{
-+ int 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
-+gssEapLocateIov(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;
-+}
-+
-+void
-+gssEapIovMessageLength(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;
-+
-+ GSSEAP_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
-+gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count)
-+{
-+ int i;
-+ OM_uint32 min_stat;
-+
-+ GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
-+
-+ for (i = 0; i < iov_count; i++) {
-+ if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
-+ gss_release_buffer(&min_stat, &iov[i].buffer);
-+ iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
-+ }
-+ }
-+}
-+
-+int
-+gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count)
-+{
-+ int i;
-+ krb5_boolean has_conf_data = FALSE;
-+
-+ GSSEAP_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);
-+}
-+
-+int
-+gssEapAllocIov(gss_iov_buffer_t iov, size_t size)
-+{
-+ GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
-+ GSSEAP_ASSERT(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
-+
-+ iov->buffer.length = size;
-+ iov->buffer.value = GSSEAP_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/mech_eap/util_json.cpp b/mech_eap/util_json.cpp
-new file mode 100644
-index 0000000..97eb1ed
---- /dev/null
-+++ b/mech_eap/util_json.cpp
-@@ -0,0 +1,513 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * JSONObject utilities.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#include <typeinfo>
-+#include <string>
-+#include <sstream>
-+#include <exception>
-+#include <new>
-+
-+#define JSON_INIT(obj) do { \
-+ if ((obj) == NULL) \
-+ throw std::bad_alloc(); \
-+ m_obj = (obj); \
-+ } while (0)
-+
-+#define JSON_CHECK_CONTAINER() do { \
-+ if (!json_is_object(m_obj) && !json_is_array(m_obj)) { \
-+ std::string s("JSONObject is not a container"); \
-+ throw JSONException(m_obj); \
-+ } \
-+ } while (0)
-+
-+#define JSON_CHECK_OBJECT() do { \
-+ if (!json_is_object(m_obj)) { \
-+ std::string s("JSONObject is not a dictionary"); \
-+ throw JSONException(m_obj, JSON_OBJECT); \
-+ } \
-+ } while (0)
-+
-+#define JSON_CHECK_ARRAY() do { \
-+ if (!json_is_array(m_obj)) { \
-+ throw JSONException(m_obj, JSON_ARRAY); \
-+ } \
-+ } while (0)
-+
-+#define JSON_CHECK(s) do { \
-+ if ((s) != 0) \
-+ throw JSONException(); \
-+ } while (0)
-+
-+JSONObject
-+JSONObject::load(const char *input, size_t flags, json_error_t *error)
-+{
-+ json_t *obj;
-+
-+ obj = json_loads(input, flags, error);
-+
-+ return JSONObject(obj, false);
-+}
-+
-+JSONObject
-+JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
-+{
-+ json_t *obj;
-+
-+ obj = json_loadf(fp, flags, error);
-+
-+ return JSONObject(obj, false);
-+}
-+
-+char *
-+JSONObject::dump(size_t flags) const
-+{
-+ char *s = json_dumps(m_obj, flags);
-+
-+ if (s == NULL)
-+ throw std::bad_alloc();
-+
-+ return s;
-+}
-+
-+void
-+JSONObject::dump(FILE *fp, size_t flags) const
-+{
-+ int r = json_dumpf(m_obj, fp, flags);
-+
-+ if (r != 0)
-+ throw std::bad_alloc();
-+}
-+
-+size_t
-+JSONObject::size(void) const
-+{
-+ if (json_is_object(m_obj))
-+ return json_object_size(m_obj);
-+ else if (json_is_array(m_obj))
-+ return json_array_size(m_obj);
-+ else
-+ return 0;
-+}
-+
-+JSONObject::JSONObject(json_t *obj, bool retain)
-+{
-+ if (retain)
-+ json_incref(obj);
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject::JSONObject(const char *value)
-+{
-+ json_t *obj = json_string(value);
-+
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject::JSONObject(json_int_t value)
-+{
-+ json_t *obj = json_integer(value);
-+
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject::JSONObject(double value)
-+{
-+ json_t *obj = json_real(value);
-+
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject::JSONObject(bool value)
-+{
-+ json_t *obj = value ? json_true() : json_false();
-+
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject::JSONObject(void)
-+{
-+ json_t *obj = json_object();
-+
-+ JSON_INIT(obj);
-+}
-+
-+JSONObject
-+JSONObject::object(void)
-+{
-+ return JSONObject();
-+}
-+
-+JSONObject
-+JSONObject::null(void)
-+{
-+ return JSONObject(json_null(), false);
-+}
-+
-+JSONObject
-+JSONObject::array(void)
-+{
-+ return JSONObject(json_array(), false);
-+}
-+
-+void
-+JSONObject::set(const char *key, JSONObject &value)
-+{
-+ JSON_CHECK_OBJECT();
-+ JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
-+}
-+
-+void
-+JSONObject::set(const char *key, const char *value)
-+{
-+ JSONObject jobj(value);
-+ set(key, jobj);
-+}
-+
-+void
-+JSONObject::set(const char *key, json_int_t value)
-+{
-+ JSONObject jobj(value);
-+ set(key, jobj);
-+}
-+
-+void
-+JSONObject::del(const char *key)
-+{
-+ json_object_del(m_obj, key);
-+}
-+
-+JSONObject
-+JSONObject::get(const char *key) const
-+{
-+ json_t *obj;
-+
-+ obj = json_object_get(m_obj, key);
-+ if (obj == NULL)
-+ return JSONObject::null();
-+
-+ return JSONObject(obj, true);
-+}
-+
-+JSONObject
-+JSONObject::get(size_t index) const
-+{
-+ json_t *obj;
-+
-+ obj = json_array_get(m_obj, index);
-+ if (obj == NULL)
-+ return JSONObject::null();
-+
-+ return JSONObject(obj, true);
-+}
-+
-+void
-+JSONObject::update(JSONObject &value)
-+{
-+ JSON_CHECK_OBJECT();
-+ json_t *other = value.get();
-+ JSON_CHECK(json_object_update(m_obj, other));
-+ json_decref(other);
-+}
-+
-+JSONObject
-+JSONObject::operator[](size_t index) const
-+{
-+ return get(index);
-+}
-+
-+JSONObject
-+JSONObject::operator[](const char *key) const
-+{
-+ return get(key);
-+}
-+
-+void
-+JSONObject::append(JSONObject &value)
-+{
-+ JSON_CHECK_ARRAY();
-+ JSON_CHECK(json_array_append_new(m_obj, value.get()));
-+}
-+
-+void
-+JSONObject::insert(size_t index, JSONObject &value)
-+{
-+ JSON_CHECK_ARRAY();
-+ JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
-+}
-+
-+void
-+JSONObject::remove(size_t index)
-+{
-+ JSON_CHECK_ARRAY();
-+ JSON_CHECK(json_array_remove(m_obj, index));
-+}
-+
-+void
-+JSONObject::clear(void)
-+{
-+ JSON_CHECK_CONTAINER();
-+
-+ if (json_is_object(m_obj)) {
-+ JSON_CHECK(json_object_clear(m_obj));
-+ } else if (json_is_array(m_obj)) {
-+ JSON_CHECK(json_array_clear(m_obj));
-+ }
-+}
-+
-+void
-+JSONObject::extend(JSONObject &value)
-+{
-+ JSON_CHECK_ARRAY();
-+ json_t *other = value.get();
-+ JSON_CHECK(json_array_extend(m_obj, other));
-+ json_decref(other);
-+}
-+
-+const char *
-+JSONObject::string(void) const
-+{
-+ return json_string_value(m_obj);
-+}
-+
-+json_int_t
-+JSONObject::integer(void) const
-+{
-+ return json_integer_value(m_obj);
-+}
-+
-+double
-+JSONObject::real(void) const
-+{
-+ return json_real_value(m_obj);
-+}
-+
-+double
-+JSONObject::number(void) const
-+{
-+ return json_number_value(m_obj);
-+}
-+
-+#ifdef HAVE_SHIBRESOLVER
-+JSONObject
-+JSONObject::ddf(DDF &ddf)
-+{
-+ if (ddf.isstruct()) {
-+ DDF elem = ddf.first();
-+ JSONObject jobj = JSONObject::object();
-+
-+ while (!elem.isnull()) {
-+ JSONObject jtmp = JSONObject::ddf(elem);
-+ jobj.set(elem.name(), jtmp);
-+ elem = ddf.next();
-+ }
-+
-+ return jobj;
-+ } else if (ddf.islist()) {
-+ DDF elem = ddf.first();
-+ JSONObject jobj = JSONObject::array();
-+
-+ while (!elem.isnull()) {
-+ JSONObject jtmp = JSONObject::ddf(elem);
-+ jobj.append(jtmp);
-+ elem = ddf.next();
-+ }
-+
-+ return jobj;
-+ } else if (ddf.isstring()) {
-+ return JSONObject(ddf.string());
-+ } else if (ddf.isint()) {
-+ return JSONObject((json_int_t)ddf.integer());
-+ } else if (ddf.isfloat()) {
-+ return JSONObject(ddf.floating());
-+ } else if (ddf.isempty() || ddf.ispointer()) {
-+ return JSONObject::object();
-+ } else if (ddf.isnull()) {
-+ return JSONObject::null();
-+ }
-+
-+ std::string s("Unbridgeable DDF object");
-+ throw JSONException();
-+}
-+
-+DDF
-+JSONObject::ddf(void) const
-+{
-+ DDF ddf(NULL);
-+
-+ switch (type()) {
-+ case JSON_OBJECT: {
-+ JSONIterator iter = iterator();
-+
-+ do {
-+ const char *key = iter.key();
-+ DDF value = iter.value().ddf();
-+ ddf.addmember(key).swap(value);
-+ } while (iter.next());
-+ break;
-+ }
-+ case JSON_ARRAY: {
-+ size_t i, nelems = size();
-+
-+ for (i = 0; i < nelems; i++) {
-+ DDF value = get(i).ddf();
-+ ddf.add(value);
-+ }
-+ break;
-+ }
-+ case JSON_STRING:
-+ ddf.string(string());
-+ break;
-+ case JSON_INTEGER:
-+ ddf.integer(integer());
-+ break;
-+ case JSON_REAL:
-+ ddf.floating(real());
-+ break;
-+ case JSON_TRUE:
-+ ddf.integer(1L);
-+ break;
-+ case JSON_FALSE:
-+ ddf.integer(0L);
-+ break;
-+ case JSON_NULL:
-+ break;
-+ }
-+
-+ return ddf;
-+}
-+#endif /* HAVE_SHIBRESOLVER */
-+
-+bool JSONObject::isObject(void) const
-+{
-+ return json_is_object(m_obj);
-+}
-+
-+bool JSONObject::isArray(void) const
-+{
-+ return json_is_array(m_obj);
-+}
-+
-+bool JSONObject::isString(void) const
-+{
-+ return json_is_string(m_obj);
-+}
-+
-+bool JSONObject::isInteger(void) const
-+{
-+ return json_is_integer(m_obj);
-+}
-+
-+bool JSONObject::isNumber(void) const
-+{
-+ return json_is_number(m_obj);
-+}
-+
-+bool JSONObject::isBoolean(void) const
-+{
-+ return json_is_boolean(m_obj);
-+}
-+
-+bool JSONObject::isNull(void) const
-+{
-+ return json_is_null(m_obj);
-+}
-+
-+JSONIterator::JSONIterator(const JSONObject &obj)
-+{
-+ m_obj = obj.get();
-+ m_iter = json_object_iter(m_obj);
-+}
-+
-+JSONIterator::~JSONIterator(void)
-+{
-+ json_decref(m_obj);
-+}
-+
-+const char *
-+JSONIterator::key(void) const
-+{
-+ return json_object_iter_key(m_iter);
-+}
-+
-+JSONObject
-+JSONIterator::value(void) const
-+{
-+ return JSONObject(json_object_iter_value(m_iter));
-+}
-+
-+bool
-+JSONIterator::next(void)
-+{
-+ m_iter = json_object_iter_next(m_obj, m_iter);
-+ return m_iter != NULL;
-+}
-+
-+JSONException::JSONException(json_t *obj, json_type type)
-+{
-+ char *s = NULL;
-+ const char *t;
-+
-+ m_obj = json_incref(obj);
-+ m_type = type;
-+
-+ if (obj != NULL)
-+ s = json_dumps(m_obj, 0);
-+
-+ switch (type) {
-+ case JSON_OBJECT: t = "OBJECT"; break;
-+ case JSON_ARRAY: t = "ARRAY"; break;
-+ case JSON_STRING: t = "STRING"; break;
-+ case JSON_INTEGER: t = "INTEGER"; break;
-+ case JSON_REAL: t = "REAL"; break;
-+ case JSON_TRUE: t = "TRUE"; break;
-+ case JSON_FALSE: t = "FALSE"; break;
-+ case JSON_NULL: t = "NULL"; break;
-+ default: t = "UNKNOWN"; break;
-+ }
-+
-+ if (obj != NULL) {
-+ m_reason = "Invalid JSON object: " + std::string(s);
-+ if (type != JSON_NULL)
-+ m_reason += " (excepted type " + std::string(t) + ")";
-+ } else {
-+ m_reason = "Internal JSON error";
-+ }
-+
-+ if (s != NULL)
-+ GSSEAP_FREE(s);
-+}
-diff --git a/mech_eap/util_json.h b/mech_eap/util_json.h
-new file mode 100644
-index 0000000..4ffecc8
---- /dev/null
-+++ b/mech_eap/util_json.h
-@@ -0,0 +1,182 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * JSON object wrapper with not-entirely-toll-free DDF bridging.
-+ */
-+
-+#ifndef _UTIL_JSON_H_
-+#define _UTIL_JSON_H_ 1
-+
-+#ifdef __cplusplus
-+#include <string>
-+#include <new>
-+
-+#include <jansson.h>
-+
-+#ifdef HAVE_SHIBRESOLVER
-+#include <shibsp/remoting/ddf.h>
-+using namespace shibsp;
-+#endif
-+
-+namespace gss_eap_util {
-+ class JSONObject;
-+
-+ class JSONException : public std::exception {
-+ public:
-+ JSONException(json_t *obj = NULL, json_type type = JSON_NULL);
-+
-+ ~JSONException(void) throw() {
-+ json_decref(m_obj);
-+ }
-+
-+ virtual const char *what(void) const throw() {
-+ return m_reason.c_str();
-+ }
-+
-+ private:
-+ json_t *m_obj;
-+ json_type m_type;
-+ std::string m_reason;
-+ };
-+
-+ class JSONIterator {
-+ public:
-+ JSONIterator(const JSONObject &obj);
-+ ~JSONIterator(void);
-+ const char *key(void) const;
-+ JSONObject value(void) const;
-+ bool next(void);
-+
-+ private:
-+ json_t *m_obj;
-+ void *m_iter;
-+ };
-+
-+ class JSONObject {
-+ public:
-+ static JSONObject load(const char *input, size_t flags, json_error_t *error);
-+ static JSONObject load(FILE *, size_t flags, json_error_t *error);
-+
-+ static JSONObject object(void);
-+ static JSONObject array(void);
-+ static JSONObject null(void);
-+#ifdef HAVE_SHIBRESOLVER
-+ static JSONObject ddf(DDF &value);
-+#endif
-+
-+ char *dump(size_t flags = 0) const;
-+ void dump(FILE *fp, size_t flags = JSON_INDENT(4)) const;
-+
-+ json_type type(void) const { return json_typeof(m_obj); }
-+ size_t size(void) const;
-+
-+ JSONObject(void);
-+ JSONObject(const char *value);
-+ JSONObject(json_int_t value);
-+ JSONObject(double value);
-+ JSONObject(bool value);
-+
-+ void set(const char *key, JSONObject &value);
-+ void set(const char *key, const char *value);
-+ void set(const char *key, json_int_t value);
-+ void del(const char *key);
-+ void update(JSONObject &value);
-+ JSONIterator iterator(void) const { return JSONIterator(*this); }
-+ JSONObject get(const char *key) const;
-+ JSONObject operator[](const char *key) const;
-+
-+ JSONObject get(size_t index) const;
-+ JSONObject operator[](size_t index) const;
-+ void append(JSONObject &value);
-+ void insert(size_t index, JSONObject &value);
-+ void remove(size_t index);
-+ void clear(void);
-+ void extend(JSONObject &value);
-+
-+ const char *string(void) const;
-+ json_int_t integer(void) const;
-+ double real(void) const;
-+ double number(void) const;
-+#ifdef HAVE_SHIBRESOLVER
-+ DDF ddf(void) const;
-+#endif
-+
-+ bool isObject(void) const;
-+ bool isArray(void) const;
-+ bool isString(void) const;
-+ bool isInteger(void) const;
-+ bool isNumber(void) const;
-+ bool isBoolean(void) const;
-+ bool isNull(void) const;
-+
-+ ~JSONObject(void)
-+ {
-+ if (m_obj != NULL)
-+ json_decref(m_obj);
-+ }
-+
-+ JSONObject(const JSONObject &obj)
-+ {
-+ m_obj = json_incref(obj.m_obj);
-+ }
-+
-+ JSONObject& operator=(const JSONObject &obj)
-+ {
-+ if (this != &obj)
-+ set(obj.m_obj);
-+ return *this;
-+ }
-+
-+ private:
-+ friend class JSONIterator;
-+
-+ json_t *get(void) const {
-+ return json_incref(m_obj);
-+ }
-+
-+ void set(json_t *obj) {
-+ if (m_obj != obj) {
-+ json_decref(m_obj);
-+ m_obj = json_incref(m_obj);
-+ }
-+ }
-+
-+ JSONObject(json_t *obj, bool retain = true);
-+
-+ json_t *m_obj;
-+ };
-+}
-+
-+#endif /* __cplusplus */
-+
-+#endif /* _UTIL_JSON_H_ */
-diff --git a/mech_eap/util_krb.c b/mech_eap/util_krb.c
-new file mode 100644
-index 0000000..5eaa31e
---- /dev/null
-+++ b/mech_eap/util_krb.c
-@@ -0,0 +1,632 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Kerberos 5 helpers.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+void
-+gssEapDestroyKrbContext(krb5_context context)
-+{
-+ if (context != NULL)
-+ krb5_free_context(context);
-+}
-+
-+static krb5_error_code
-+initKrbContext(krb5_context *pKrbContext)
-+{
-+ krb5_context krbContext;
-+ krb5_error_code code;
-+ char *defaultRealm = NULL;
-+
-+ *pKrbContext = NULL;
-+
-+ code = krb5_init_context(&krbContext);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ krb5_appdefault_string(krbContext, "eap_gss",
-+ NULL, "default_realm", "", &defaultRealm);
-+
-+ if (defaultRealm != NULL && defaultRealm[0] != '\0') {
-+ code = krb5_set_default_realm(krbContext, defaultRealm);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+
-+ *pKrbContext = krbContext;
-+
-+cleanup:
-+ krb5_free_default_realm(krbContext, defaultRealm);
-+
-+ if (code != 0 && krbContext != NULL)
-+ krb5_free_context(krbContext);
-+
-+ return code;
-+}
-+
-+OM_uint32
-+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
-+{
-+ struct gss_eap_thread_local_data *tld;
-+
-+ *minor = 0;
-+ *context = NULL;
-+
-+ tld = gssEapGetThreadLocalData();
-+ if (tld != NULL) {
-+ if (tld->krbContext == NULL) {
-+ *minor = initKrbContext(&tld->krbContext);
-+ if (*minor != 0)
-+ tld->krbContext = NULL;
-+ }
-+ *context = tld->krbContext;
-+ } else {
-+ *minor = GSSEAP_GET_LAST_ERROR();
-+ }
-+
-+ GSSEAP_ASSERT(*context != NULL || *minor != 0);
-+
-+ return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
-+}
-+
-+/*
-+ * Derive a key K for RFC 4121 use by using the following
-+ * derivation function (based on RFC 4402);
-+ *
-+ * KMSK = random-to-key(MSK)
-+ * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
-+ * L = output key size
-+ * K = truncate(L, T1 || T2 || .. || Tn)
-+ *
-+ * The output must be freed by krb5_free_keyblock_contents(),
-+ * not GSSEAP_FREE().
-+ */
-+OM_uint32
-+gssEapDeriveRfc3961Key(OM_uint32 *minor,
-+ const unsigned char *inputKey,
-+ size_t inputKeyLength,
-+ krb5_enctype encryptionType,
-+ krb5_keyblock *pKey)
-+{
-+ krb5_context krbContext;
-+#ifndef HAVE_HEIMDAL_VERSION
-+ krb5_data data;
-+#endif
-+ krb5_data ns, t, derivedKeyData;
-+ krb5_keyblock kd;
-+ krb5_error_code code;
-+ size_t randomLength, keyLength, prfLength;
-+ unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
-+ ssize_t i, remain;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+ GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL);
-+
-+ KRB_KEY_INIT(pKey);
-+ KRB_KEY_INIT(&kd);
-+ KRB_KEY_TYPE(&kd) = encryptionType;
-+
-+ KRB_DATA_INIT(&ns);
-+ KRB_DATA_INIT(&t);
-+ KRB_DATA_INIT(&derivedKeyData);
-+
-+ code = krb5_c_keylengths(krbContext, encryptionType,
-+ &randomLength, &keyLength);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ /* Convert EAP MSK into a Kerberos key */
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_random_to_key(krbContext, encryptionType, inputKey,
-+ MIN(inputKeyLength, randomLength), &kd);
-+#else
-+ data.length = MIN(inputKeyLength, randomLength);
-+ data.data = (char *)inputKey;
-+
-+ KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength);
-+ if (KRB_KEY_DATA(&kd) == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+ KRB_KEY_LENGTH(&kd) = keyLength;
-+
-+ code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
-+#endif /* HAVE_HEIMDAL_VERSION */
-+ if (code != 0)
-+ goto cleanup;
-+
-+ memset(&constant[0], 0, 4);
-+ memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
-+
-+ ns.length = sizeof(constant);
-+ ns.data = (char *)constant;
-+
-+ /* Plug derivation constant and key into PRF */
-+ code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
-+ if (code != 0)
-+ goto cleanup;
-+
-+#ifndef HAVE_HEIMDAL_VERSION
-+ /* Same API, but different allocation rules, unfortunately. */
-+ t.length = prfLength;
-+ t.data = GSSEAP_MALLOC(t.length);
-+ if (t.data == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+#endif
-+
-+ derivedKeyData.length = randomLength;
-+ derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length);
-+ if (derivedKeyData.data == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength;
-+ remain > 0;
-+ p += t.length, remain -= t.length, i++)
-+ {
-+ store_uint32_be(i, ns.data);
-+
-+ code = krb5_c_prf(krbContext, &kd, &ns, &t);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ memcpy(p, t.data, MIN(t.length, remain));
-+ }
-+
-+ /* Finally, convert PRF output into a new key which we will return */
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_free_keyblock_contents(krbContext, &kd);
-+ KRB_KEY_INIT(&kd);
-+
-+ code = krb5_random_to_key(krbContext, encryptionType,
-+ derivedKeyData.data, derivedKeyData.length, &kd);
-+#else
-+ code = krb5_c_random_to_key(krbContext, encryptionType,
-+ &derivedKeyData, &kd);
-+#endif
-+ if (code != 0)
-+ goto cleanup;
-+
-+ *pKey = kd;
-+
-+cleanup:
-+ if (code != 0)
-+ krb5_free_keyblock_contents(krbContext, &kd);
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_free_data_contents(krbContext, &t);
-+#else
-+ if (t.data != NULL) {
-+ memset(t.data, 0, t.length);
-+ GSSEAP_FREE(t.data);
-+ }
-+#endif
-+ if (derivedKeyData.data != NULL) {
-+ memset(derivedKeyData.data, 0, derivedKeyData.length);
-+ GSSEAP_FREE(derivedKeyData.data);
-+ }
-+
-+ *minor = code;
-+
-+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
-+}
-+
-+#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
-+extern krb5_error_code
-+krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
-+#endif
-+
-+OM_uint32
-+rfc3961ChecksumTypeForKey(OM_uint32 *minor,
-+ krb5_keyblock *key,
-+ krb5_cksumtype *cksumtype)
-+{
-+ krb5_context krbContext;
-+#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
-+ krb5_data data;
-+ krb5_checksum cksum;
-+#endif
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
-+ *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
-+ cksumtype);
-+ if (*minor != 0)
-+ return GSS_S_FAILURE;
-+#else
-+ KRB_DATA_INIT(&data);
-+
-+ memset(&cksum, 0, sizeof(cksum));
-+
-+ /*
-+ * This is a complete hack but it's the only way to work with
-+ * MIT Kerberos pre-1.9 without using private API, as it does
-+ * not support passing in zero as the checksum type.
-+ */
-+ *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
-+ if (*minor != 0)
-+ return GSS_S_FAILURE;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ *cksumtype = cksum.cksumtype;
-+#else
-+ *cksumtype = cksum.checksum_type;
-+#endif
-+
-+ krb5_free_checksum_contents(krbContext, &cksum);
-+#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
-+
-+ if (!krb5_c_is_keyed_cksum(*cksumtype)) {
-+ *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+krb5_error_code
-+krbCryptoLength(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ int type,
-+ size_t *length)
-+{
-+#ifdef HAVE_HEIMDAL_VERSION
-+ return krb5_crypto_length(krbContext, krbCrypto, type, length);
-+#else
-+ unsigned int len;
-+ krb5_error_code code;
-+
-+ code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len);
-+ if (code == 0)
-+ *length = (size_t)len;
-+
-+ return code;
-+#endif
-+}
-+
-+krb5_error_code
-+krbPaddingLength(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ size_t dataLength,
-+ size_t *padLength)
-+{
-+ krb5_error_code code;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ size_t headerLength, paddingLength;
-+
-+ code = krbCryptoLength(krbContext, krbCrypto,
-+ KRB5_CRYPTO_TYPE_HEADER, &headerLength);
-+ if (code != 0)
-+ return code;
-+
-+ dataLength += headerLength;
-+
-+ code = krb5_crypto_length(krbContext, krbCrypto,
-+ KRB5_CRYPTO_TYPE_PADDING, &paddingLength);
-+ if (code != 0)
-+ return code;
-+
-+ if (paddingLength != 0 && (dataLength % paddingLength) != 0)
-+ *padLength = paddingLength - (dataLength % paddingLength);
-+ else
-+ *padLength = 0;
-+
-+ return 0;
-+#else
-+ unsigned int pad;
-+
-+ code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad);
-+ if (code == 0)
-+ *padLength = (size_t)pad;
-+
-+ return code;
-+#endif /* HAVE_HEIMDAL_VERSION */
-+}
-+
-+krb5_error_code
-+krbBlockSize(krb5_context krbContext,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto,
-+#else
-+ krb5_keyblock *key,
-+#endif
-+ size_t *blockSize)
-+{
-+#ifdef HAVE_HEIMDAL_VERSION
-+ return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize);
-+#else
-+ return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize);
-+#endif
-+}
-+
-+krb5_error_code
-+krbEnctypeToString(
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_context krbContext,
-+#else
-+ krb5_context krbContext GSSEAP_UNUSED,
-+#endif
-+ krb5_enctype enctype,
-+ const char *prefix,
-+ gss_buffer_t string)
-+{
-+ krb5_error_code code;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ char *enctypeBuf = NULL;
-+#else
-+ char enctypeBuf[128];
-+#endif
-+ size_t prefixLength, enctypeLength;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf);
-+#else
-+ code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf));
-+#endif
-+ if (code != 0)
-+ return code;
-+
-+ prefixLength = (prefix != NULL) ? strlen(prefix) : 0;
-+ enctypeLength = strlen(enctypeBuf);
-+
-+ string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1);
-+ if (string->value == NULL) {
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_xfree(enctypeBuf);
-+#endif
-+ return ENOMEM;
-+ }
-+
-+ if (prefixLength != 0)
-+ memcpy(string->value, prefix, prefixLength);
-+ memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength);
-+
-+ string->length = prefixLength + enctypeLength;
-+ ((char *)string->value)[string->length] = '\0';
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_xfree(enctypeBuf);
-+#endif
-+
-+ return 0;
-+}
-+
-+krb5_error_code
-+krbMakeAuthDataKdcIssued(krb5_context context,
-+ const krb5_keyblock *key,
-+ krb5_const_principal issuer,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ const AuthorizationData *authdata,
-+ AuthorizationData *adKdcIssued
-+#else
-+ krb5_authdata *const *authdata,
-+ krb5_authdata ***adKdcIssued
-+#endif
-+ )
-+{
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_error_code code;
-+ AD_KDCIssued kdcIssued;
-+ AuthorizationDataElement adDatum;
-+ unsigned char *buf;
-+ size_t buf_size, len;
-+ krb5_crypto crypto = NULL;
-+
-+ memset(&kdcIssued, 0, sizeof(kdcIssued));
-+ memset(adKdcIssued, 0, sizeof(*adKdcIssued));
-+
-+ kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL;
-+ kdcIssued.i_sname = (PrincipalName *)&issuer->name;
-+ kdcIssued.elements = *authdata;
-+
-+ ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_crypto_init(context, key, 0, &crypto);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED,
-+ 0, buf, buf_size, &kdcIssued.ad_checksum);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ free(buf); /* match ASN1_MALLOC_ENCODE */
-+ buf = NULL;
-+
-+ ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED;
-+ adDatum.ad_data.length = buf_size;
-+ adDatum.ad_data.data = buf;
-+
-+ code = add_AuthorizationData(adKdcIssued, &adDatum);
-+ if (code != 0)
-+ goto cleanup;
-+
-+cleanup:
-+ if (buf != NULL)
-+ free(buf); /* match ASN1_MALLOC_ENCODE */
-+ if (crypto != NULL)
-+ krb5_crypto_destroy(context, crypto);
-+ free_Checksum(&kdcIssued.ad_checksum);
-+
-+ return code;
-+#else
-+ return krb5_make_authdata_kdc_issued(context, key, issuer, authdata,
-+ adKdcIssued);
-+#endif /* HAVE_HEIMDAL_VERSION */
-+}
-+
-+krb5_error_code
-+krbMakeCred(krb5_context krbContext,
-+ krb5_auth_context authContext,
-+ krb5_creds *creds,
-+ krb5_data *data)
-+{
-+ krb5_error_code code;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ KRB_CRED krbCred;
-+ KrbCredInfo krbCredInfo;
-+ EncKrbCredPart encKrbCredPart;
-+ krb5_keyblock *key;
-+ krb5_crypto krbCrypto = NULL;
-+ krb5_data encKrbCredPartData;
-+ krb5_replay_data rdata;
-+ size_t len;
-+#else
-+ krb5_data *d = NULL;
-+#endif
-+
-+ memset(data, 0, sizeof(*data));
-+#ifdef HAVE_HEIMDAL_VERSION
-+ memset(&krbCred, 0, sizeof(krbCred));
-+ memset(&krbCredInfo, 0, sizeof(krbCredInfo));
-+ memset(&encKrbCredPart, 0, sizeof(encKrbCredPart));
-+ memset(&rdata, 0, sizeof(rdata));
-+
-+ if (authContext->local_subkey)
-+ key = authContext->local_subkey;
-+ else if (authContext->remote_subkey)
-+ key = authContext->remote_subkey;
-+ else
-+ key = authContext->keyblock;
-+
-+ krbCred.pvno = 5;
-+ krbCred.msg_type = krb_cred;
-+ krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket));
-+ if (krbCred.tickets.val == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+ krbCred.tickets.len = 1;
-+
-+ code = decode_Ticket(creds->ticket.data,
-+ creds->ticket.length,
-+ krbCred.tickets.val, &len);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ krbCredInfo.key = creds->session;
-+ krbCredInfo.prealm = &creds->client->realm;
-+ krbCredInfo.pname = &creds->client->name;
-+ krbCredInfo.flags = &creds->flags.b;
-+ krbCredInfo.authtime = &creds->times.authtime;
-+ krbCredInfo.starttime = &creds->times.starttime;
-+ krbCredInfo.endtime = &creds->times.endtime;
-+ krbCredInfo.renew_till = &creds->times.renew_till;
-+ krbCredInfo.srealm = &creds->server->realm;
-+ krbCredInfo.sname = &creds->server->name;
-+ krbCredInfo.caddr = creds->addresses.len ? &creds->addresses : NULL;
-+
-+ encKrbCredPart.ticket_info.len = 1;
-+ encKrbCredPart.ticket_info.val = &krbCredInfo;
-+ if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
-+ rdata.seq = authContext->local_seqnumber;
-+ encKrbCredPart.nonce = (int32_t *)&rdata.seq;
-+ } else {
-+ encKrbCredPart.nonce = NULL;
-+ }
-+ if (authContext->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
-+ krb5_us_timeofday(krbContext, &rdata.timestamp, &rdata.usec);
-+ encKrbCredPart.timestamp = &rdata.timestamp;
-+ encKrbCredPart.usec = &rdata.usec;
-+ } else {
-+ encKrbCredPart.timestamp = NULL;
-+ encKrbCredPart.usec = NULL;
-+ }
-+ encKrbCredPart.s_address = authContext->local_address;
-+ encKrbCredPart.r_address = authContext->remote_address;
-+
-+ ASN1_MALLOC_ENCODE(EncKrbCredPart, encKrbCredPartData.data,
-+ encKrbCredPartData.length, &encKrbCredPart,
-+ &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_encrypt_EncryptedData(krbContext,
-+ krbCrypto,
-+ KRB5_KU_KRB_CRED,
-+ encKrbCredPartData.data,
-+ encKrbCredPartData.length,
-+ 0,
-+ &krbCred.enc_part);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length,
-+ &krbCred, &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
-+ authContext->local_seqnumber++;
-+
-+cleanup:
-+ if (krbCrypto != NULL)
-+ krb5_crypto_destroy(krbContext, krbCrypto);
-+ free_KRB_CRED(&krbCred);
-+ krb5_data_free(&encKrbCredPartData);
-+
-+ return code;
-+#else
-+ code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL);
-+ if (code == 0) {
-+ *data = *d;
-+ GSSEAP_FREE(d);
-+ }
-+
-+ return code;
-+#endif /* HAVE_HEIMDAL_VERSION */
-+}
-diff --git a/mech_eap/util_lucid.c b/mech_eap/util_lucid.c
-new file mode 100644
-index 0000000..f9e9941
---- /dev/null
-+++ b/mech_eap/util_lucid.c
-@@ -0,0 +1,183 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * "Lucid" security context export routine (called by MIT Kerberos mechanism).
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+gssEapExportLucidSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ const gss_OID desiredObject GSSEAP_UNUSED,
-+ gss_buffer_set_t *data_set)
-+{
-+ OM_uint32 major = GSS_S_COMPLETE;
-+ int haveAcceptorSubkey =
-+ ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0);
-+ gss_buffer_desc rep;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_error_code code;
-+ krb5_storage *sp;
-+ krb5_data data = { 0 };
-+
-+ sp = krb5_storage_emem();
-+ if (sp == NULL) {
-+ code = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ code = krb5_store_int32(sp, 1); /* version */
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, CTX_IS_INITIATOR(ctx));
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, ctx->expiryTime);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, 0);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, ctx->sendSeq);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, 0);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, ctx->recvSeq);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, 1); /* is_cfx */
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_int32(sp, haveAcceptorSubkey);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_store_keyblock(sp, ctx->rfc3961Key);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ if (haveAcceptorSubkey) {
-+ code = krb5_store_keyblock(sp, ctx->rfc3961Key);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+
-+ code = krb5_storage_to_data(sp, &data);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ rep.length = data.length;
-+ rep.value = data.data;
-+
-+ major = gss_add_buffer_set_member(minor, &rep, data_set);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ krb5_data_free(&data);
-+
-+ if (major == GSS_S_COMPLETE) {
-+ *minor = code;
-+ major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
-+ }
-+
-+ return major;
-+#else
-+ gss_krb5_lucid_context_v1_t *lctx;
-+ gss_krb5_lucid_key_t *lkey = NULL;
-+
-+ lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx));
-+ if (lctx == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ lctx->version = 1;
-+ lctx->initiate = CTX_IS_INITIATOR(ctx);
-+ if (ctx->expiryTime == 0)
-+ lctx->endtime = KRB_TIME_FOREVER;
-+ else
-+ lctx->endtime = ctx->expiryTime;
-+ lctx->send_seq = ctx->sendSeq;
-+ lctx->recv_seq = ctx->recvSeq;
-+ lctx->protocol = 1;
-+
-+ lctx->cfx_kd.have_acceptor_subkey = haveAcceptorSubkey;
-+
-+ lkey = haveAcceptorSubkey
-+ ? &lctx->cfx_kd.acceptor_subkey
-+ : &lctx->cfx_kd.ctx_key;
-+
-+ lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key);
-+ lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key));
-+ if (lkey->data == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
-+ memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length);
-+
-+ rep.value = &lctx;
-+ rep.length = sizeof(void *);
-+
-+ major = gss_add_buffer_set_member(minor, &rep, data_set);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ if (lctx != NULL) {
-+ if (lkey != NULL && lkey->data != NULL) {
-+ memset(lkey->data, 0, lkey->length);
-+ GSSEAP_FREE(lkey->data);
-+ }
-+ GSSEAP_FREE(lctx);
-+ }
-+ }
-+
-+ return major;
-+#endif /* HAVE_HEIMDAL_VERSION */
-+}
-diff --git a/mech_eap/util_mech.c b/mech_eap/util_mech.c
-new file mode 100644
-index 0000000..958e43d
---- /dev/null
-+++ b/mech_eap/util_mech.c
-@@ -0,0 +1,380 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * General mechanism utility routines.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/*
-+ * 1.3.6.1.4.1.5322(padl)
-+ * gssEap(22)
-+ * mechanisms(1)
-+ * eap-aes128-cts-hmac-sha1-96(17)
-+ * eap-aes256-cts-hmac-sha1-96(18)
-+ * nameTypes(2)
-+ * apiExtensions(3)
-+ * inquireSecContextByOid(1)
-+ * inquireCredByOid(2)
-+ * setSecContextOption(3)
-+ * setCredOption(4)
-+ * mechInvoke(5)
-+ */
-+
-+/*
-+ * Note: the enctype-less OID is used as the mechanism OID in non-
-+ * canonicalized exported names.
-+ */
-+static gss_OID_desc gssEapMechOids[] = {
-+ /* 1.3.6.1.4.1.5322.22.1 */
-+ { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
-+ /* 1.3.6.1.4.1.5322.22.1.17 */
-+ { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
-+ /* 1.3.6.1.4.1.5322.22.1.18 */
-+ { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
-+};
-+
-+gss_OID GSS_EAP_MECHANISM = &gssEapMechOids[0];
-+gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[1];
-+gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[2];
-+
-+static int
-+internalizeOid(const gss_OID oid,
-+ gss_OID *const pInternalizedOid);
-+
-+/*
-+ * Returns TRUE is the OID is a concrete mechanism OID, that is, one
-+ * with a Kerberos enctype as the last element.
-+ */
-+int
-+gssEapIsConcreteMechanismOid(const gss_OID oid)
-+{
-+ return oid->length > GSS_EAP_MECHANISM->length &&
-+ memcmp(oid->elements, GSS_EAP_MECHANISM->elements,
-+ GSS_EAP_MECHANISM->length) == 0;
-+}
-+
-+int
-+gssEapIsMechanismOid(const gss_OID oid)
-+{
-+ return oid == GSS_C_NO_OID ||
-+ oidEqual(oid, GSS_EAP_MECHANISM) ||
-+ gssEapIsConcreteMechanismOid(oid);
-+}
-+
-+/*
-+ * Validate that all elements are concrete mechanism OIDs.
-+ */
-+OM_uint32
-+gssEapValidateMechs(OM_uint32 *minor,
-+ const gss_OID_set mechs)
-+{
-+ int i;
-+
-+ *minor = 0;
-+
-+ if (mechs == GSS_C_NO_OID_SET) {
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ for (i = 0; i < mechs->count; i++) {
-+ gss_OID oid = &mechs->elements[i];
-+
-+ if (!gssEapIsConcreteMechanismOid(oid)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapOidToEnctype(OM_uint32 *minor,
-+ const gss_OID oid,
-+ krb5_enctype *enctype)
-+{
-+ OM_uint32 major;
-+ int suffix;
-+
-+ major = decomposeOid(minor,
-+ GSS_EAP_MECHANISM->elements,
-+ GSS_EAP_MECHANISM->length,
-+ oid,
-+ &suffix);
-+ if (major == GSS_S_COMPLETE)
-+ *enctype = suffix;
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapEnctypeToOid(OM_uint32 *minor,
-+ krb5_enctype enctype,
-+ gss_OID *pOid)
-+{
-+ OM_uint32 major;
-+ gss_OID oid;
-+
-+ *pOid = NULL;
-+
-+ oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid));
-+ if (oid == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ oid->length = GSS_EAP_MECHANISM->length + 1;
-+ oid->elements = GSSEAP_MALLOC(oid->length);
-+ if (oid->elements == NULL) {
-+ *minor = ENOMEM;
-+ GSSEAP_FREE(oid);
-+ return GSS_S_FAILURE;
-+ }
-+
-+ major = composeOid(minor,
-+ GSS_EAP_MECHANISM->elements,
-+ GSS_EAP_MECHANISM->length,
-+ enctype,
-+ oid);
-+ if (major == GSS_S_COMPLETE) {
-+ internalizeOid(oid, pOid);
-+ *pOid = oid;
-+ } else {
-+ GSSEAP_FREE(oid->elements);
-+ GSSEAP_FREE(oid);
-+ }
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapIndicateMechs(OM_uint32 *minor,
-+ gss_OID_set *mechs)
-+{
-+ krb5_context krbContext;
-+ OM_uint32 major;
-+ krb5_enctype *etypes;
-+ int i;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ *minor = krb5_get_permitted_enctypes(krbContext, &etypes);
-+ if (*minor != 0) {
-+ return GSS_S_FAILURE;
-+ }
-+
-+ major = gss_create_empty_oid_set(minor, mechs);
-+ if (GSS_ERROR(major)) {
-+ GSSEAP_FREE(etypes);
-+ return major;
-+ }
-+
-+ for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
-+ gss_OID mechOid;
-+#ifndef HAVE_HEIMDAL_VERSION
-+ OM_uint32 tmpMinor;
-+#endif
-+
-+ /* XXX currently we aren't equipped to encode these enctypes */
-+ if (etypes[i] < 0 || etypes[i] > 127)
-+ continue;
-+
-+ major = gssEapEnctypeToOid(minor, etypes[i], &mechOid);
-+ if (GSS_ERROR(major))
-+ break;
-+
-+ major = gss_add_oid_set_member(minor, mechOid, mechs);
-+ if (GSS_ERROR(major))
-+ break;
-+
-+#ifndef HAVE_HEIMDAL_VERSION
-+ gss_release_oid(&tmpMinor, &mechOid);
-+#endif
-+ }
-+
-+ GSSEAP_FREE(etypes);
-+
-+ *minor = 0;
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapDefaultMech(OM_uint32 *minor,
-+ gss_OID *oid)
-+{
-+ gss_OID_set mechs;
-+ OM_uint32 major, tmpMinor;
-+
-+ major = gssEapIndicateMechs(minor, &mechs);
-+ if (GSS_ERROR(major)) {
-+ return major;
-+ }
-+
-+ if (mechs->count == 0) {
-+ gss_release_oid_set(&tmpMinor, &mechs);
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (!internalizeOid(&mechs->elements[0], oid)) {
-+ /* don't double-free if we didn't internalize it */
-+ mechs->elements[0].length = 0;
-+ mechs->elements[0].elements = NULL;
-+ }
-+
-+ gss_release_oid_set(&tmpMinor, &mechs);
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static int
-+internalizeOid(const gss_OID oid,
-+ gss_OID *const pInternalizedOid)
-+{
-+ int i;
-+
-+ *pInternalizedOid = GSS_C_NO_OID;
-+
-+ for (i = 0;
-+ i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]);
-+ i++) {
-+ if (oidEqual(oid, &gssEapMechOids[i])) {
-+ *pInternalizedOid = (const gss_OID)&gssEapMechOids[i];
-+ break;
-+ }
-+ }
-+
-+ if (*pInternalizedOid == GSS_C_NO_OID) {
-+ if (oidEqual(oid, GSS_EAP_NT_EAP_NAME))
-+ *pInternalizedOid = (const gss_OID)GSS_EAP_NT_EAP_NAME;
-+ }
-+
-+ if (*pInternalizedOid == GSS_C_NO_OID) {
-+ *pInternalizedOid = oid;
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+OM_uint32
-+gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid)
-+{
-+ gss_OID internalizedOid = GSS_C_NO_OID;
-+
-+ *minor = 0;
-+
-+ if (internalizeOid(*oid, &internalizedOid)) {
-+ /* OID was internalized, so we can mark it as "freed" */
-+ *oid = GSS_C_NO_OID;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ /* we don't know about this OID */
-+ return GSS_S_CONTINUE_NEEDED;
-+}
-+
-+OM_uint32
-+gssEapCanonicalizeOid(OM_uint32 *minor,
-+ const gss_OID oid,
-+ OM_uint32 flags,
-+ gss_OID *pOid)
-+{
-+ OM_uint32 major;
-+ int mapToNull = 0;
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+ *pOid = GSS_C_NULL_OID;
-+
-+ if (oid == GSS_C_NULL_OID) {
-+ if ((flags & OID_FLAG_NULL_VALID) == 0) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ } else if (flags & OID_FLAG_MAP_NULL_TO_DEFAULT_MECH) {
-+ return gssEapDefaultMech(minor, pOid);
-+ } else {
-+ mapToNull = 1;
-+ }
-+ } else if (oidEqual(oid, GSS_EAP_MECHANISM)) {
-+ if ((flags & OID_FLAG_FAMILY_MECH_VALID) == 0) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ } else if (flags & OID_FLAG_MAP_FAMILY_MECH_TO_NULL) {
-+ mapToNull = 1;
-+ }
-+ } else if (!gssEapIsConcreteMechanismOid(oid)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (!mapToNull) {
-+ if (!internalizeOid(oid, pOid))
-+ major = duplicateOid(minor, oid, pOid);
-+ }
-+
-+ return major;
-+}
-+
-+static gss_buffer_desc gssEapSaslMechs[] = {
-+ { sizeof("EAP") - 1, "EAP", }, /* not used */
-+ { sizeof("EAP-AES128") - 1, "EAP-AES128" },
-+ { sizeof("EAP-AES256") - 1, "EAP-AES256" },
-+};
-+
-+gss_buffer_t
-+gssEapOidToSaslName(const gss_OID oid)
-+{
-+ size_t i;
-+
-+ for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) {
-+ if (oidEqual(&gssEapMechOids[i], oid))
-+ return &gssEapSaslMechs[i];
-+ }
-+
-+ return GSS_C_NO_BUFFER;
-+}
-+
-+gss_OID
-+gssEapSaslNameToOid(const gss_buffer_t name)
-+{
-+ size_t i;
-+
-+ for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) {
-+ if (bufferEqual(&gssEapSaslMechs[i], name))
-+ return &gssEapMechOids[i];
-+ }
-+
-+ return GSS_C_NO_OID;
-+}
-diff --git a/mech_eap/util_moonshot.c b/mech_eap/util_moonshot.c
-new file mode 100644
-index 0000000..dc0c35e
---- /dev/null
-+++ b/mech_eap/util_moonshot.c
-@@ -0,0 +1,238 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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_eap.h"
-+
-+#ifdef HAVE_MOONSHOT_GET_IDENTITY
-+#include <libmoonshot.h>
-+
-+static OM_uint32
-+libMoonshotMapError(OM_uint32 *minor,
-+ MoonshotError **pError)
-+{
-+ MoonshotError *error = *pError;
-+
-+ GSSEAP_ASSERT(error != NULL);
-+
-+ switch (error->code) {
-+ case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
-+ *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
-+ break;
-+ case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
-+ *minor = GSSEAP_NO_IDENTITY_SELECTED;
-+ break;
-+ case MOONSHOT_ERROR_INSTALLATION_ERROR:
-+ *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
-+ break;
-+ case MOONSHOT_ERROR_OS_ERROR:
-+ *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
-+ break;
-+ case MOONSHOT_ERROR_IPC_ERROR:
-+ *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
-+ break;
-+ default:
-+ *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
-+ break;
-+ }
-+
-+ gssEapSaveStatusInfo(*minor, error->message);
-+ moonshot_error_free(error);
-+ *pError = NULL;
-+
-+ return GSS_S_CRED_UNAVAIL;
-+}
-+
-+OM_uint32
-+libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
-+ const gss_cred_id_t cred,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_OID nameMech = gssEapPrimaryMechForCred(cred);
-+ gss_name_t name = GSS_C_NO_NAME;
-+ gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
-+ char *nai = NULL;
-+ char *password = NULL;
-+ char *serverCertificateHash = NULL;
-+ char *caCertificate = NULL;
-+ char *subjectNameConstraint = NULL;
-+ char *subjectAltNameConstraint = NULL;
-+ MoonshotError *error = NULL;
-+
-+ *pName = GSS_C_NO_NAME;
-+
-+ if (!moonshot_get_default_identity(&nai,
-+ &password,
-+ &serverCertificateHash,
-+ &caCertificate,
-+ &subjectNameConstraint,
-+ &subjectAltNameConstraint,
-+ &error)) {
-+ if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
-+ major = GSS_S_CRED_UNAVAIL;
-+ *minor = GSSEAP_NO_DEFAULT_IDENTITY;
-+ moonshot_error_free(error);
-+ } else
-+ major = libMoonshotMapError(minor, &error);
-+ goto cleanup;
-+ }
-+
-+ tmpBuffer.value = nai;
-+ tmpBuffer.length = strlen(nai);
-+
-+ major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ *pName = name;
-+ name = GSS_C_NO_NAME;
-+
-+cleanup:
-+ moonshot_free(nai);
-+ moonshot_free(password);
-+ moonshot_free(serverCertificateHash);
-+ moonshot_free(caCertificate);
-+ moonshot_free(subjectNameConstraint);
-+ moonshot_free(subjectAltNameConstraint);
-+
-+ gssEapReleaseName(&tmpMinor, &name);
-+
-+ return major;
-+}
-+
-+OM_uint32
-+libMoonshotResolveInitiatorCred(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ const gss_name_t targetName)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_OID nameMech = gssEapPrimaryMechForCred(cred);
-+ gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
-+ char *nai = NULL;
-+ char *password = NULL;
-+ char *serverCertificateHash = NULL;
-+ char *caCertificate = NULL;
-+ char *subjectNameConstraint = NULL;
-+ char *subjectAltNameConstraint = NULL;
-+ MoonshotError *error = NULL;
-+
-+ if (cred->name != GSS_C_NO_NAME) {
-+ major = gssEapExportName(minor, cred->name, &initiator);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (targetName != GSS_C_NO_NAME) {
-+ major = gssEapExportName(minor, targetName, &target);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+
-+ if (!moonshot_get_identity((const char *)initiator.value,
-+ (const char *)cred->password.value,
-+ (const char *)target.value,
-+ &nai,
-+ &password,
-+ &serverCertificateHash,
-+ &caCertificate,
-+ &subjectNameConstraint,
-+ &subjectAltNameConstraint,
-+ &error)) {
-+ major = libMoonshotMapError(minor, &error);
-+ goto cleanup;
-+ }
-+
-+ gssEapReleaseName(&tmpMinor, &cred->name);
-+
-+ tmpBuffer.value = nai;
-+ tmpBuffer.length = strlen(nai);
-+
-+ major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
-+ nameMech, &cred->name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ tmpBuffer.value = password;
-+ tmpBuffer.length = strlen(password);
-+
-+ major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ gss_release_buffer(&tmpMinor, &cred->caCertificate);
-+ gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
-+ gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
-+
-+ if (serverCertificateHash != NULL) {
-+ size_t len = strlen(serverCertificateHash);
-+
-+ #define HASH_PREFIX "hash://server/sha256/"
-+ #define HASH_PREFIX_LEN (sizeof(HASH_PREFIX) - 1)
-+
-+ cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
-+ if (cred->caCertificate.value == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
-+ memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
-+
-+ ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
-+
-+ cred->caCertificate.length = HASH_PREFIX_LEN + len;
-+ } else if (caCertificate != NULL) {
-+ makeStringBufferOrCleanup(caCertificate, &cred->caCertificate);
-+ }
-+
-+ if (subjectNameConstraint != NULL)
-+ makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
-+ if (subjectAltNameConstraint != NULL)
-+ makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
-+
-+cleanup:
-+ moonshot_free(nai);
-+ moonshot_free(password);
-+ moonshot_free(serverCertificateHash);
-+ moonshot_free(caCertificate);
-+ moonshot_free(subjectNameConstraint);
-+ moonshot_free(subjectAltNameConstraint);
-+
-+ gss_release_buffer(&tmpMinor, &initiator);
-+ gss_release_buffer(&tmpMinor, &target);
-+
-+ return major;
-+}
-+#endif /* HAVE_MOONSHOT_GET_IDENTITY */
-diff --git a/mech_eap/util_name.c b/mech_eap/util_name.c
-new file mode 100644
-index 0000000..6045724
---- /dev/null
-+++ b/mech_eap/util_name.c
-@@ -0,0 +1,789 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * Portions 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.
-+ */
-+
-+/*
-+ * Name utility routines.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+static gss_OID_desc gssEapNtEapName = {
-+ /* 1.3.6.1.4.1.5322.22.2.1 */
-+ 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
-+};
-+
-+gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
-+
-+OM_uint32
-+gssEapAllocName(OM_uint32 *minor, gss_name_t *pName)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_name_t name;
-+
-+ *pName = GSS_C_NO_NAME;
-+
-+ name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name));
-+ if (name == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
-+ *minor = GSSEAP_GET_LAST_ERROR();
-+ gssEapReleaseName(&tmpMinor, &name);
-+ return GSS_S_FAILURE;
-+ }
-+
-+ *pName = name;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName)
-+{
-+ gss_name_t name;
-+ krb5_context krbContext = NULL;
-+ OM_uint32 tmpMinor;
-+
-+ *minor = 0;
-+
-+ if (pName == NULL) {
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ name = *pName;
-+ if (name == GSS_C_NO_NAME) {
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+ krb5_free_principal(krbContext, name->krbPrincipal);
-+ gssEapReleaseOid(&tmpMinor, &name->mechanismUsed);
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ gssEapReleaseAttrContext(&tmpMinor, name);
-+#endif
-+
-+ GSSEAP_MUTEX_DESTROY(&name->mutex);
-+ GSSEAP_FREE(name);
-+ *pName = NULL;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static OM_uint32
-+krbPrincipalToName(OM_uint32 *minor,
-+ krb5_principal *principal,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major;
-+ gss_name_t name;
-+
-+ major = gssEapAllocName(minor, &name);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ name->krbPrincipal = *principal;
-+ *principal = NULL;
-+
-+ if (KRB_PRINC_LENGTH(name->krbPrincipal) > 1) {
-+ name->flags |= NAME_FLAG_SERVICE;
-+ } else {
-+ name->flags |= NAME_FLAG_NAI;
-+ }
-+
-+ *pName = name;
-+ *minor = 0;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+static char *
-+gssEapGetDefaultRealm(krb5_context krbContext)
-+{
-+ char *defaultRealm = NULL;
-+
-+ krb5_appdefault_string(krbContext, "eap_gss",
-+ NULL, "default_realm", "", &defaultRealm);
-+
-+ return defaultRealm;
-+}
-+
-+static OM_uint32
-+importServiceName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major;
-+ krb5_error_code code;
-+ krb5_context krbContext;
-+ krb5_principal krbPrinc;
-+ char *service, *host, *realm = NULL;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ major = bufferToString(minor, nameBuffer, &service);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ host = strchr(service, '@');
-+ if (host != NULL) {
-+ *host = '\0';
-+ host++;
-+ }
-+
-+ realm = gssEapGetDefaultRealm(krbContext);
-+
-+ code = krb5_build_principal(krbContext,
-+ &krbPrinc,
-+ realm != NULL ? strlen(realm) : 0,
-+ realm != NULL ? realm : "",
-+ service,
-+ host,
-+ NULL);
-+
-+ if (code == 0) {
-+ KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST;
-+
-+ major = krbPrincipalToName(minor, &krbPrinc, pName);
-+ if (GSS_ERROR(major))
-+ krb5_free_principal(krbContext, krbPrinc);
-+ } else {
-+ major = GSS_S_FAILURE;
-+ *minor = GSSEAP_BAD_SERVICE_NAME;
-+ }
-+
-+ if (realm != NULL)
-+ krb5_free_default_realm(krbContext, realm);
-+ GSSEAP_FREE(service);
-+
-+ return major;
-+}
-+
-+#define IMPORT_FLAG_DEFAULT_REALM 0x1
-+
-+/*
-+ * Import an EAP name, possibly appending the default GSS EAP realm,
-+ */
-+static OM_uint32
-+importEapNameFlags(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ OM_uint32 importFlags,
-+ gss_name_t *pName)
-+{
-+ OM_uint32 major;
-+ krb5_context krbContext;
-+ krb5_principal krbPrinc = NULL;
-+ krb5_error_code code;
-+ char *nameString;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ if (nameBuffer == GSS_C_NO_BUFFER) {
-+ nameString = "";
-+ code = KRB5_PARSE_MALFORMED;
-+ } else {
-+ major = bufferToString(minor, nameBuffer, &nameString);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /*
-+ * First, attempt to parse the name on the assumption that it includes
-+ * a qualifying realm. This allows us to avoid accidentally appending
-+ * the default Kerberos realm to an unqualified name. (A bug in MIT
-+ * Kerberos prevents the default realm being set to an empty value.)
-+ */
-+ code = krb5_parse_name_flags(krbContext, nameString,
-+ KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc);
-+ }
-+
-+ if (code == KRB5_PARSE_MALFORMED) {
-+ char *defaultRealm = NULL;
-+ int parseFlags = 0;
-+
-+ /* Possibly append the default EAP realm if required */
-+ if (importFlags & IMPORT_FLAG_DEFAULT_REALM)
-+ defaultRealm = gssEapGetDefaultRealm(krbContext);
-+
-+ /* If no default realm, leave the realm empty in the parsed name */
-+ if (defaultRealm == NULL || defaultRealm[0] == '\0')
-+ parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
-+
-+ code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc);
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) {
-+ KRB_PRINC_REALM(krbPrinc) = KRB_CALLOC(1, sizeof(char));
-+ if (KRB_PRINC_REALM(krbPrinc) == NULL)
-+ code = ENOMEM;
-+ }
-+#endif
-+
-+ if (defaultRealm != NULL)
-+ krb5_free_default_realm(krbContext, defaultRealm);
-+ }
-+
-+ if (nameBuffer != GSS_C_NO_BUFFER)
-+ GSSEAP_FREE(nameString);
-+
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ GSSEAP_ASSERT(krbPrinc != NULL);
-+
-+ major = krbPrincipalToName(minor, &krbPrinc, pName);
-+ if (GSS_ERROR(major))
-+ krb5_free_principal(krbContext, krbPrinc);
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+importEapName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *pName)
-+{
-+ return importEapNameFlags(minor, nameBuffer, 0, pName);
-+}
-+
-+static OM_uint32
-+importUserName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *pName)
-+{
-+ return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName);
-+}
-+
-+static OM_uint32
-+importAnonymousName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer GSSEAP_UNUSED,
-+ gss_name_t *pName)
-+{
-+ return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName);
-+}
-+
-+#define UPDATE_REMAIN(n) do { \
-+ p += (n); \
-+ remain -= (n); \
-+ } while (0)
-+
-+#define CHECK_REMAIN(n) do { \
-+ if (remain < (n)) { \
-+ major = GSS_S_BAD_NAME; \
-+ *minor = GSSEAP_TOK_TRUNC; \
-+ goto cleanup; \
-+ } \
-+ } while (0)
-+
-+OM_uint32
-+gssEapImportNameInternal(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *pName,
-+ OM_uint32 flags)
-+{
-+ OM_uint32 major, tmpMinor;
-+ krb5_context krbContext;
-+ unsigned char *p;
-+ size_t len, remain;
-+ gss_buffer_desc buf;
-+ gss_name_t name = GSS_C_NO_NAME;
-+ gss_OID mechanismUsed = GSS_C_NO_OID;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ p = (unsigned char *)nameBuffer->value;
-+ remain = nameBuffer->length;
-+
-+ if (flags & EXPORT_NAME_FLAG_OID) {
-+ gss_OID_desc mech;
-+ enum gss_eap_token_type tokType;
-+ uint16_t wireTokType;
-+
-+ /* TOK_ID || MECH_OID_LEN || MECH_OID */
-+ if (remain < 6) {
-+ *minor = GSSEAP_BAD_NAME_TOKEN;
-+ return GSS_S_BAD_NAME;
-+ }
-+
-+ if (flags & EXPORT_NAME_FLAG_COMPOSITE)
-+ tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
-+ else
-+ tokType = TOK_TYPE_EXPORT_NAME;
-+
-+ /* TOK_ID */
-+ wireTokType = load_uint16_be(p);
-+
-+ if ((flags & EXPORT_NAME_FLAG_ALLOW_COMPOSITE) &&
-+ wireTokType == TOK_TYPE_EXPORT_NAME_COMPOSITE) {
-+ tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
-+ flags |= EXPORT_NAME_FLAG_COMPOSITE;
-+ }
-+
-+ if (wireTokType != tokType) {
-+ *minor = GSSEAP_WRONG_TOK_ID;
-+ return GSS_S_BAD_NAME;
-+ }
-+ UPDATE_REMAIN(2);
-+
-+ /* MECH_OID_LEN */
-+ len = load_uint16_be(p);
-+ if (len < 2) {
-+ *minor = GSSEAP_BAD_NAME_TOKEN;
-+ return GSS_S_BAD_NAME;
-+ }
-+ UPDATE_REMAIN(2);
-+
-+ /* MECH_OID */
-+ if (p[0] != 0x06) {
-+ *minor = GSSEAP_BAD_NAME_TOKEN;
-+ return GSS_S_BAD_NAME;
-+ }
-+
-+ mech.length = p[1];
-+ mech.elements = &p[2];
-+
-+ CHECK_REMAIN(mech.length);
-+
-+ major = gssEapCanonicalizeOid(minor,
-+ &mech,
-+ OID_FLAG_FAMILY_MECH_VALID |
-+ OID_FLAG_MAP_FAMILY_MECH_TO_NULL,
-+ &mechanismUsed);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ UPDATE_REMAIN(2 + mech.length);
-+ }
-+
-+ /* NAME_LEN */
-+ CHECK_REMAIN(4);
-+ len = load_uint32_be(p);
-+ UPDATE_REMAIN(4);
-+
-+ /* NAME */
-+ CHECK_REMAIN(len);
-+ buf.length = len;
-+ buf.value = p;
-+ UPDATE_REMAIN(len);
-+
-+ major = importEapNameFlags(minor, &buf, 0, &name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ name->mechanismUsed = mechanismUsed;
-+ mechanismUsed = GSS_C_NO_OID;
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
-+ gss_buffer_desc buf;
-+
-+ buf.length = remain;
-+ buf.value = p;
-+
-+ major = gssEapImportAttrContext(minor, &buf, name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+#endif
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ gssEapReleaseOid(&tmpMinor, &mechanismUsed);
-+ gssEapReleaseName(&tmpMinor, &name);
-+ } else {
-+ *pName = name;
-+ }
-+
-+ return major;
-+}
-+
-+static OM_uint32
-+importExportName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *name)
-+{
-+ return gssEapImportNameInternal(minor, nameBuffer, name,
-+ EXPORT_NAME_FLAG_OID |
-+ EXPORT_NAME_FLAG_ALLOW_COMPOSITE);
-+}
-+
-+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
-+static OM_uint32
-+importCompositeExportName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ gss_name_t *name)
-+{
-+ return gssEapImportNameInternal(minor, nameBuffer, name,
-+ EXPORT_NAME_FLAG_OID |
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+}
-+#endif
-+
-+struct gss_eap_name_import_provider {
-+ gss_const_OID oid;
-+ OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
-+};
-+
-+OM_uint32
-+gssEapImportName(OM_uint32 *minor,
-+ const gss_buffer_t nameBuffer,
-+ const gss_OID nameType,
-+ const gss_OID mechType,
-+ gss_name_t *pName)
-+{
-+ struct gss_eap_name_import_provider nameTypes[] = {
-+ { GSS_EAP_NT_EAP_NAME, importEapName },
-+ { GSS_C_NT_USER_NAME, importUserName },
-+ { GSS_C_NT_HOSTBASED_SERVICE, importServiceName },
-+ { GSS_C_NT_HOSTBASED_SERVICE_X, importServiceName },
-+ { GSS_C_NT_ANONYMOUS, importAnonymousName },
-+ { GSS_C_NT_EXPORT_NAME, importExportName },
-+ { GSS_KRB5_NT_PRINCIPAL_NAME, importUserName },
-+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
-+ { GSS_C_NT_COMPOSITE_EXPORT, importCompositeExportName },
-+#endif
-+ };
-+ size_t i;
-+ OM_uint32 major = GSS_S_BAD_NAMETYPE;
-+ OM_uint32 tmpMinor;
-+ gss_name_t name = GSS_C_NO_NAME;
-+
-+ for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
-+ if (oidEqual(nameTypes[i].oid,
-+ nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) {
-+ major = nameTypes[i].import(minor, nameBuffer, &name);
-+ break;
-+ }
-+ }
-+
-+ if (major == GSS_S_COMPLETE &&
-+ mechType != GSS_C_NO_OID) {
-+ GSSEAP_ASSERT(gssEapIsConcreteMechanismOid(mechType));
-+ GSSEAP_ASSERT(name->mechanismUsed == GSS_C_NO_OID);
-+
-+ major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed);
-+ }
-+
-+ if (GSS_ERROR(major))
-+ gssEapReleaseName(&tmpMinor, &name);
-+ else
-+ *pName = name;
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapExportName(OM_uint32 *minor,
-+ const gss_name_t name,
-+ gss_buffer_t exportedName)
-+{
-+ return gssEapExportNameInternal(minor, name, exportedName,
-+ EXPORT_NAME_FLAG_OID);
-+}
-+
-+OM_uint32
-+gssEapExportNameInternal(OM_uint32 *minor,
-+ const gss_name_t name,
-+ gss_buffer_t exportedName,
-+ OM_uint32 flags)
-+{
-+ OM_uint32 major = GSS_S_FAILURE, tmpMinor;
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+ size_t exportedNameLen;
-+ unsigned char *p;
-+ gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
-+ gss_OID mech;
-+
-+ exportedName->length = 0;
-+ exportedName->value = NULL;
-+
-+ if (name->mechanismUsed != GSS_C_NO_OID)
-+ mech = name->mechanismUsed;
-+ else
-+ mech = GSS_EAP_MECHANISM;
-+
-+ major = gssEapDisplayName(minor, name, &nameBuf, NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ exportedNameLen = 0;
-+ if (flags & EXPORT_NAME_FLAG_OID) {
-+ exportedNameLen += 6 + mech->length;
-+ }
-+ exportedNameLen += 4 + nameBuf.length;
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
-+ major = gssEapExportAttrContext(minor, name, &attrs);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ exportedNameLen += attrs.length;
-+ }
-+#endif
-+
-+ exportedName->value = GSSEAP_MALLOC(exportedNameLen);
-+ if (exportedName->value == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ exportedName->length = exportedNameLen;
-+
-+ p = (unsigned char *)exportedName->value;
-+
-+ if (flags & EXPORT_NAME_FLAG_OID) {
-+ /* TOK | MECH_OID_LEN */
-+ store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
-+ ? TOK_TYPE_EXPORT_NAME_COMPOSITE
-+ : TOK_TYPE_EXPORT_NAME,
-+ p);
-+ p += 2;
-+ store_uint16_be(mech->length + 2, p);
-+ p += 2;
-+
-+ /* MECH_OID */
-+ *p++ = 0x06;
-+ *p++ = mech->length & 0xff;
-+ memcpy(p, mech->elements, mech->length);
-+ p += mech->length;
-+ }
-+
-+ /* NAME_LEN */
-+ store_uint32_be(nameBuf.length, p);
-+ p += 4;
-+
-+ /* NAME */
-+ memcpy(p, nameBuf.value, nameBuf.length);
-+ p += nameBuf.length;
-+
-+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
-+ memcpy(p, attrs.value, attrs.length);
-+ p += attrs.length;
-+ }
-+
-+ GSSEAP_ASSERT(p == (unsigned char *)exportedName->value + exportedNameLen);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ gss_release_buffer(&tmpMinor, &attrs);
-+ gss_release_buffer(&tmpMinor, &nameBuf);
-+ if (GSS_ERROR(major))
-+ gss_release_buffer(&tmpMinor, exportedName);
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapCanonicalizeName(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ const gss_OID mech_type,
-+ gss_name_t *dest_name)
-+{
-+ OM_uint32 major, tmpMinor;
-+ krb5_context krbContext;
-+ gss_name_t name;
-+ gss_OID mech_used;
-+
-+ if (input_name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ major = gssEapAllocName(minor, &name);
-+ if (GSS_ERROR(major)) {
-+ return major;
-+ }
-+
-+ if (mech_type != GSS_C_NO_OID)
-+ mech_used = mech_type;
-+ else
-+ mech_used = input_name->mechanismUsed;
-+
-+ major = gssEapCanonicalizeOid(minor,
-+ mech_used,
-+ OID_FLAG_NULL_VALID,
-+ &name->mechanismUsed);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ name->flags = input_name->flags;
-+
-+ *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
-+ &name->krbPrincipal);
-+ if (*minor != 0) {
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+
-+#ifdef GSSEAP_ENABLE_ACCEPTOR
-+ if (input_name->attrCtx != NULL) {
-+ major = gssEapDuplicateAttrContext(minor, input_name, name);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+ }
-+#endif
-+
-+ *dest_name = name;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ gssEapReleaseName(&tmpMinor, &name);
-+ }
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapDuplicateName(OM_uint32 *minor,
-+ const gss_name_t input_name,
-+ gss_name_t *dest_name)
-+{
-+ return gssEapCanonicalizeName(minor, input_name,
-+ GSS_C_NO_OID, dest_name);
-+}
-+
-+OM_uint32
-+gssEapDisplayName(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t output_name_buffer,
-+ gss_OID *output_name_type)
-+{
-+ OM_uint32 major;
-+ krb5_context krbContext;
-+ char *krbName;
-+ gss_OID name_type;
-+ int flags = 0;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ output_name_buffer->length = 0;
-+ output_name_buffer->value = NULL;
-+
-+ if (name == GSS_C_NO_NAME) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
-+ }
-+
-+ /*
-+ * According to draft-ietf-abfab-gss-eap-01, when the realm is
-+ * absent the trailing '@' is not included.
-+ */
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
-+ KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
-+#else
-+ if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
-+#endif
-+ flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
-+
-+ *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
-+ flags, &krbName);
-+ if (*minor != 0) {
-+ return GSS_S_FAILURE;
-+ }
-+
-+ major = makeStringBuffer(minor, krbName, output_name_buffer);
-+ if (GSS_ERROR(major)) {
-+ krb5_free_unparsed_name(krbContext, krbName);
-+ return major;
-+ }
-+
-+ krb5_free_unparsed_name(krbContext, krbName);
-+
-+ if (output_name_buffer->length == 0) {
-+ name_type = GSS_C_NT_ANONYMOUS;
-+ } else if (name->flags & NAME_FLAG_NAI) {
-+ name_type = GSS_C_NT_USER_NAME;
-+ } else {
-+ name_type = GSS_EAP_NT_EAP_NAME;
-+ }
-+
-+ if (output_name_type != NULL)
-+ *output_name_type = name_type;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapCompareName(OM_uint32 *minor,
-+ gss_name_t name1,
-+ gss_name_t name2,
-+ int *name_equal)
-+{
-+ krb5_context krbContext;
-+
-+ *minor = 0;
-+
-+ if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
-+ *name_equal = 1;
-+ } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ /* krbPrincipal is immutable, so lock not required */
-+ *name_equal = krb5_principal_compare(krbContext,
-+ name1->krbPrincipal,
-+ name2->krbPrincipal);
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/util_oid.c b/mech_eap/util_oid.c
-new file mode 100644
-index 0000000..096c9f8
---- /dev/null
-+++ b/mech_eap/util_oid.c
-@@ -0,0 +1,206 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * Copyright 1995-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.
-+ *
-+ */
-+
-+/*
-+ * OID utility routines.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+duplicateOid(OM_uint32 *minor,
-+ const gss_OID_desc * const oid,
-+ gss_OID *newOid)
-+{
-+ gss_OID p;
-+
-+ *newOid = GSS_C_NO_OID;
-+
-+ p = (gss_OID)GSSEAP_MALLOC(sizeof(*p));
-+ if (p == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+ p->length = oid->length;
-+ p->elements = GSSEAP_MALLOC(p->length);
-+ if (p->elements == NULL) {
-+ GSSEAP_FREE(p);
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ memcpy(p->elements, oid->elements, p->length);
-+ *newOid = p;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/* Compose an OID of a prefix and an integer suffix */
-+OM_uint32
-+composeOid(OM_uint32 *minor,
-+ 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 = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
-+ }
-+
-+ if (oid->length < prefix_len) {
-+ *minor = GSSEAP_WRONG_SIZE;
-+ 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 = GSSEAP_WRONG_SIZE;
-+ 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 = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+decomposeOid(OM_uint32 *minor,
-+ 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 = GSSEAP_WRONG_SIZE;
-+ return GSS_S_FAILURE;
-+ }
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+duplicateOidSet(OM_uint32 *minor,
-+ const gss_OID_set src,
-+ gss_OID_set *dst)
-+{
-+ OM_uint32 major, tmpMinor;
-+ int i;
-+
-+ if (src == GSS_C_NO_OID_SET) {
-+ *dst = GSS_C_NO_OID_SET;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ major = gss_create_empty_oid_set(minor, dst);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ for (i = 0; i < src->count; i++) {
-+ gss_OID oid = &src->elements[i];
-+
-+ major = gss_add_oid_set_member(minor, oid, dst);
-+ if (GSS_ERROR(major))
-+ break;
-+ }
-+
-+ if (GSS_ERROR(major))
-+ gss_release_oid_set(&tmpMinor, dst);
-+
-+ return major;
-+}
-diff --git a/mech_eap/util_ordering.c b/mech_eap/util_ordering.c
-new file mode 100644
-index 0000000..71ebfb5
---- /dev/null
-+++ b/mech_eap/util_ordering.c
-@@ -0,0 +1,302 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Functions to check sequence numbers for replay and sequencing
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#define QUEUE_LENGTH 20
-+
-+typedef struct _queue {
-+ int do_replay;
-+ int do_sequence;
-+ int start;
-+ int length;
-+ uint64_t firstnum;
-+ /* Stored as deltas from firstnum. This way, the high bit won't
-+ overflow unless we've actually gone through 2**n messages, or
-+ gotten something *way* out of sequence. */
-+ uint64_t elem[QUEUE_LENGTH];
-+ /* All ones for 64-bit sequence numbers; 32 ones for 32-bit
-+ sequence numbers. */
-+ uint64_t mask;
-+} queue;
-+
-+/* rep invariant:
-+ * - the queue is a circular queue. The first element (q->elem[q->start])
-+ * is the oldest. The last element is the newest.
-+ */
-+
-+#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
-+#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
-+
-+static void
-+queue_insert(queue *q, int after, uint64_t seqnum)
-+{
-+ /* insert. this is not the fastest way, but it's easy, and it's
-+ optimized for insert at end, which is the common case */
-+ int i;
-+
-+ /* common case: at end, after == q->start+q->length-1 */
-+
-+ /* move all the elements (after,last] up one slot */
-+
-+ for (i = q->start + q->length - 1; i > after; i--)
-+ QELEM(q,i+1) = QELEM(q,i);
-+
-+ /* fill in slot after+1 */
-+
-+ QELEM(q,after+1) = seqnum;
-+
-+ /* Either increase the length by one, or move the starting point up
-+ one (deleting the first element, which got bashed above), as
-+ appropriate. */
-+
-+ if (q->length == QSIZE(q)) {
-+ q->start++;
-+ if (q->start == QSIZE(q))
-+ q->start = 0;
-+ } else {
-+ q->length++;
-+ }
-+}
-+
-+OM_uint32
-+sequenceInit(OM_uint32 *minor,
-+ void **vqueue,
-+ uint64_t seqnum,
-+ int do_replay,
-+ int do_sequence,
-+ int wide_nums)
-+{
-+ queue *q;
-+
-+ q = (queue *)GSSEAP_CALLOC(1, sizeof(queue));
-+ if (q == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ q->do_replay = do_replay;
-+ q->do_sequence = do_sequence;
-+ q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL;
-+
-+ q->start = 0;
-+ q->length = 1;
-+ q->firstnum = seqnum;
-+ q->elem[q->start] = ((uint64_t)0 - 1) & q->mask;
-+
-+ *vqueue = (void *)q;
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+sequenceCheck(OM_uint32 *minor,
-+ void **vqueue,
-+ uint64_t seqnum)
-+{
-+ queue *q;
-+ int i;
-+ uint64_t expected;
-+
-+ *minor = 0;
-+
-+ q = (queue *) (*vqueue);
-+
-+ if (!q->do_replay && !q->do_sequence)
-+ return GSS_S_COMPLETE;
-+
-+ /* All checks are done relative to the initial sequence number, to
-+ avoid (or at least put off) the pain of wrapping. */
-+ seqnum -= q->firstnum;
-+ /* If we're only doing 32-bit values, adjust for that again.
-+
-+ Note that this will probably be the wrong thing to if we get
-+ 2**32 messages sent with 32-bit sequence numbers. */
-+ seqnum &= q->mask;
-+
-+ /* rule 1: expected sequence number */
-+
-+ expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
-+ if (seqnum == expected) {
-+ queue_insert(q, q->start+q->length-1, seqnum);
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ /* rule 2: > expected sequence number */
-+
-+ if ((seqnum > expected)) {
-+ queue_insert(q, q->start+q->length-1, seqnum);
-+ if (q->do_replay && !q->do_sequence)
-+ return GSS_S_COMPLETE;
-+ else
-+ return GSS_S_GAP_TOKEN;
-+ }
-+
-+ /* rule 3: seqnum < seqnum(first) */
-+
-+ if ((seqnum < QELEM(q,q->start)) &&
-+ /* Is top bit of whatever width we're using set?
-+
-+ We used to check for greater than or equal to firstnum, but
-+ (1) we've since switched to compute values relative to
-+ firstnum, so the lowest we can have is 0, and (2) the effect
-+ of the original scheme was highly dependent on whether
-+ firstnum was close to either side of 0. (Consider
-+ firstnum==0xFFFFFFFE and we miss three packets; the next
-+ packet is *new* but would look old.)
-+
-+ This check should give us 2**31 or 2**63 messages "new", and
-+ just as many "old". That's not quite right either. */
-+ (seqnum & (1 + (q->mask >> 1)))
-+ ) {
-+ if (q->do_replay && !q->do_sequence)
-+ return GSS_S_OLD_TOKEN;
-+ else
-+ return GSS_S_UNSEQ_TOKEN;
-+ }
-+
-+ /* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */
-+
-+ else {
-+ if (seqnum == QELEM(q,q->start+q->length - 1))
-+ return GSS_S_DUPLICATE_TOKEN;
-+
-+ for (i = q->start; i < q->start + q->length - 1; i++) {
-+ if (seqnum == QELEM(q,i))
-+ return GSS_S_DUPLICATE_TOKEN;
-+ if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
-+ queue_insert(q, i, seqnum);
-+ if (q->do_replay && !q->do_sequence)
-+ return GSS_S_COMPLETE;
-+ else
-+ return GSS_S_UNSEQ_TOKEN;
-+ }
-+ }
-+ }
-+
-+ /* this should never happen */
-+ return GSS_S_FAILURE;
-+}
-+
-+OM_uint32
-+sequenceFree(OM_uint32 *minor, void **vqueue)
-+{
-+ queue *q;
-+
-+ q = (queue *) (*vqueue);
-+
-+ GSSEAP_FREE(q);
-+
-+ *vqueue = NULL;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+/*
-+ * These support functions are for the serialization routines
-+ */
-+size_t
-+sequenceSize(void *vqueue GSSEAP_UNUSED)
-+{
-+ return sizeof(queue);
-+}
-+
-+OM_uint32
-+sequenceExternalize(OM_uint32 *minor,
-+ void *vqueue,
-+ unsigned char **buf,
-+ size_t *lenremain)
-+{
-+ if (*lenremain < sizeof(queue)) {
-+ *minor = GSSEAP_WRONG_SIZE;
-+ return GSS_S_FAILURE;
-+ }
-+ memcpy(*buf, vqueue, sizeof(queue));
-+ *buf += sizeof(queue);
-+ *lenremain -= sizeof(queue);
-+
-+ return 0;
-+}
-+
-+OM_uint32
-+sequenceInternalize(OM_uint32 *minor,
-+ void **vqueue,
-+ unsigned char **buf,
-+ size_t *lenremain)
-+{
-+ void *q;
-+
-+ if (*lenremain < sizeof(queue)) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_DEFECTIVE_TOKEN;
-+ }
-+
-+ q = GSSEAP_MALLOC(sizeof(queue));
-+ if (q == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ memcpy(q, *buf, sizeof(queue));
-+ *buf += sizeof(queue);
-+ *lenremain -= sizeof(queue);
-+ *vqueue = q;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/util_radius.cpp b/mech_eap/util_radius.cpp
-new file mode 100644
-index 0000000..9111e20
---- /dev/null
-+++ b/mech_eap/util_radius.cpp
-@@ -0,0 +1,899 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * RADIUS attribute provider implementation.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/* stuff that should be provided by libradsec/libfreeradius-radius */
-+#define VENDORATTR(vendor, attr) (((vendor) << 16) | (attr))
-+
-+#ifndef ATTRID
-+#define ATTRID(attr) ((attr) & 0xFFFF)
-+#endif
-+
-+static gss_buffer_desc radiusUrnPrefix = {
-+ sizeof("urn:x-radius:") - 1,
-+ (void *)"urn:x-radius:"
-+};
-+
-+static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
-+
-+gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
-+{
-+ m_vps = NULL;
-+ m_authenticated = false;
-+}
-+
-+gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
-+{
-+ if (m_vps != NULL)
-+ pairfree(&m_vps);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
-+ const gss_eap_attr_provider *ctx)
-+{
-+ const gss_eap_radius_attr_provider *radius;
-+
-+ if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
-+ return false;
-+
-+ radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
-+
-+ if (radius->m_vps != NULL)
-+ m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
-+
-+ m_authenticated = radius->m_authenticated;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
-+ const gss_cred_id_t gssCred,
-+ const gss_ctx_id_t gssCtx)
-+{
-+ if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
-+ return false;
-+
-+ if (gssCtx != GSS_C_NO_CONTEXT) {
-+ if (gssCtx->acceptorCtx.vps != NULL) {
-+ m_vps = copyAvps(gssCtx->acceptorCtx.vps);
-+ if (m_vps == NULL)
-+ return false;
-+
-+ /* We assume libradsec validated this for us */
-+ GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
-+ m_authenticated = true;
-+ }
-+ }
-+
-+ return true;
-+}
-+
-+static bool
-+alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
-+{
-+ for (std::vector<std::string>::const_iterator a = attrs.begin();
-+ a != attrs.end();
-+ ++a) {
-+ if (strcmp(vp->name, (*a).c_str()) == 0)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static bool
-+isSecretAttributeP(uint16_t attrid, uint16_t vendor)
-+{
-+ bool bSecretAttribute = false;
-+
-+ switch (vendor) {
-+ case VENDORPEC_MS:
-+ switch (attrid) {
-+ case PW_MS_MPPE_SEND_KEY:
-+ case PW_MS_MPPE_RECV_KEY:
-+ bSecretAttribute = true;
-+ break;
-+ default:
-+ break;
-+ }
-+ default:
-+ break;
-+ }
-+
-+ return bSecretAttribute;
-+}
-+
-+static bool
-+isSecretAttributeP(uint32_t attribute)
-+{
-+ return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
-+}
-+
-+static bool
-+isInternalAttributeP(uint16_t attrid, uint16_t vendor)
-+{
-+ bool bInternalAttribute = false;
-+
-+ /* should have been filtered */
-+ GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
-+
-+ switch (vendor) {
-+ case VENDORPEC_UKERNA:
-+ switch (attrid) {
-+ case PW_GSS_ACCEPTOR_SERVICE_NAME:
-+ case PW_GSS_ACCEPTOR_HOST_NAME:
-+ case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
-+ case PW_GSS_ACCEPTOR_REALM_NAME:
-+ case PW_SAML_AAA_ASSERTION:
-+ bInternalAttribute = true;
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return bInternalAttribute;
-+}
-+
-+static bool
-+isInternalAttributeP(uint32_t attribute)
-+{
-+ return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
-+}
-+
-+static bool
-+isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
-+{
-+ /* A bit of a hack for the PAC for now. Should be configurable. */
-+ return (vendor == VENDORPEC_UKERNA) &&
-+ !isInternalAttributeP(attrid, vendor);
-+}
-+
-+static bool
-+isFragmentedAttributeP(uint32_t attribute)
-+{
-+ return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
-+}
-+
-+/*
-+ * Copy AVP list, same as paircopy except it filters out attributes
-+ * containing keys.
-+ */
-+static VALUE_PAIR *
-+copyAvps(const VALUE_PAIR *src)
-+{
-+ const VALUE_PAIR *vp;
-+ VALUE_PAIR *dst = NULL, **pDst = &dst;
-+
-+ for (vp = src; vp != NULL; vp = vp->next) {
-+ VALUE_PAIR *vpcopy;
-+
-+ if (isSecretAttributeP(vp->attribute))
-+ continue;
-+
-+ vpcopy = paircopyvp(vp);
-+ if (vpcopy == NULL) {
-+ pairfree(&dst);
-+ throw std::bad_alloc();
-+ }
-+ *pDst = vpcopy;
-+ pDst = &vpcopy->next;
-+ }
-+
-+ return dst;
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
-+ void *data) const
-+{
-+ VALUE_PAIR *vp;
-+ std::vector <std::string> seen;
-+
-+ for (vp = m_vps; vp != NULL; vp = vp->next) {
-+ gss_buffer_desc attribute;
-+ char attrid[64];
-+
-+ /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
-+ if (isInternalAttributeP(vp->attribute))
-+ continue;
-+
-+ if (alreadyAddedAttributeP(seen, vp))
-+ continue;
-+
-+ snprintf(attrid, sizeof(attrid), "%s%d",
-+ (char *)radiusUrnPrefix.value, vp->attribute);
-+
-+ attribute.value = attrid;
-+ attribute.length = strlen(attrid);
-+
-+ if (!addAttribute(m_manager, this, &attribute, data))
-+ return false;
-+
-+ seen.push_back(std::string(vp->name));
-+ }
-+
-+ return true;
-+}
-+
-+uint32_t
-+getAttributeId(const gss_buffer_t attr)
-+{
-+ OM_uint32 tmpMinor;
-+ gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
-+ DICT_ATTR *da;
-+ char *s;
-+ uint32_t attrid = 0;
-+
-+ if (attr->length < radiusUrnPrefix.length ||
-+ memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
-+ return 0;
-+
-+ /* need to duplicate because attr may not be NUL terminated */
-+ duplicateBuffer(*attr, &strAttr);
-+ s = (char *)strAttr.value + radiusUrnPrefix.length;
-+
-+ if (isdigit(*s)) {
-+ attrid = strtoul(s, NULL, 10);
-+ } else {
-+ da = dict_attrbyname(s);
-+ if (da != NULL)
-+ attrid = da->attr;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &strAttr);
-+
-+ return attrid;
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
-+ uint32_t attrid,
-+ const gss_buffer_t value)
-+{
-+ OM_uint32 major = GSS_S_UNAVAILABLE, minor;
-+
-+ if (!isSecretAttributeP(attrid) &&
-+ !isInternalAttributeP(attrid)) {
-+ deleteAttribute(attrid);
-+
-+ major = gssEapRadiusAddAvp(&minor, &m_vps,
-+ ATTRID(attrid), VENDOR(attrid),
-+ value);
-+ }
-+
-+ return !GSS_ERROR(major);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value)
-+{
-+ uint32_t attrid = getAttributeId(attr);
-+
-+ if (!attrid)
-+ return false;
-+
-+ return setAttribute(complete, attrid, value);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
-+{
-+ if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
-+ pairfind(m_vps, attrid) == NULL)
-+ return false;
-+
-+ pairdelete(&m_vps, attrid);
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
-+{
-+ uint32_t attrid = getAttributeId(attr);
-+
-+ if (!attrid)
-+ return false;
-+
-+ return deleteAttribute(attrid);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+ uint32_t attrid;
-+
-+ attrid = getAttributeId(attr);
-+ if (!attrid)
-+ return false;
-+
-+ return getAttribute(attrid, authenticated, complete,
-+ value, display_value, more);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+ VALUE_PAIR *vp;
-+ int i = *more, count = 0;
-+
-+ *more = 0;
-+
-+ if (i == -1)
-+ i = 0;
-+
-+ if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
-+ return false;
-+ } else if (isFragmentedAttributeP(attrid)) {
-+ return getFragmentedAttribute(attrid,
-+ authenticated,
-+ complete,
-+ value);
-+ }
-+
-+ for (vp = pairfind(m_vps, attrid);
-+ vp != NULL;
-+ vp = pairfind(vp->next, attrid)) {
-+ if (count++ == i) {
-+ if (pairfind(vp->next, attrid) != NULL)
-+ *more = count;
-+ break;
-+ }
-+ }
-+
-+ if (vp == NULL && *more == 0)
-+ return false;
-+
-+ if (value != GSS_C_NO_BUFFER) {
-+ gss_buffer_desc valueBuf;
-+
-+ valueBuf.value = (void *)vp->vp_octets;
-+ valueBuf.length = vp->length;
-+
-+ duplicateBuffer(valueBuf, value);
-+ }
-+
-+ if (display_value != GSS_C_NO_BUFFER &&
-+ vp->type != PW_TYPE_OCTETS) {
-+ char displayString[MAX_STRING_LEN];
-+ gss_buffer_desc displayBuf;
-+
-+ displayBuf.length = vp_prints_value(displayString,
-+ sizeof(displayString), vp, 0);
-+ displayBuf.value = (void *)displayString;
-+
-+ duplicateBuffer(displayBuf, display_value);
-+ }
-+
-+ if (authenticated != NULL)
-+ *authenticated = m_authenticated;
-+ if (complete != NULL)
-+ *complete = true;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
-+ uint16_t vendor,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value) const
-+{
-+ OM_uint32 major, minor;
-+
-+ major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
-+
-+ if (authenticated != NULL)
-+ *authenticated = m_authenticated;
-+ if (complete != NULL)
-+ *complete = true;
-+
-+ return !GSS_ERROR(major);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value) const
-+{
-+ return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
-+ authenticated, complete, value);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
-+ uint16_t vendor,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+
-+ return getAttribute(VENDORATTR(attribute, vendor),
-+ authenticated, complete,
-+ value, display_value, more);
-+}
-+
-+gss_any_t
-+gss_eap_radius_attr_provider::mapToAny(int authenticated,
-+ gss_buffer_t type_id GSSEAP_UNUSED) const
-+{
-+ if (authenticated && !m_authenticated)
-+ return (gss_any_t)NULL;
-+
-+ return (gss_any_t)copyAvps(m_vps);
-+}
-+
-+void
-+gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
-+ gss_any_t input) const
-+{
-+ VALUE_PAIR *vp = (VALUE_PAIR *)input;
-+ pairfree(&vp);
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::init(void)
-+{
-+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext);
-+
-+ return true;
-+}
-+
-+void
-+gss_eap_radius_attr_provider::finalize(void)
-+{
-+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
-+}
-+
-+gss_eap_attr_provider *
-+gss_eap_radius_attr_provider::createAttrContext(void)
-+{
-+ return new gss_eap_radius_attr_provider;
-+}
-+
-+OM_uint32
-+gssEapRadiusAddAvp(OM_uint32 *minor,
-+ VALUE_PAIR **vps,
-+ uint16_t attribute,
-+ uint16_t vendor,
-+ const gss_buffer_t buffer)
-+{
-+ uint32_t attrid = VENDORATTR(vendor, attribute);
-+ unsigned char *p = (unsigned char *)buffer->value;
-+ size_t remain = buffer->length;
-+
-+ do {
-+ VALUE_PAIR *vp;
-+ size_t n = remain;
-+
-+ /*
-+ * There's an extra byte of padding; RADIUS AVPs can only
-+ * be 253 octets.
-+ */
-+ if (n >= MAX_STRING_LEN)
-+ n = MAX_STRING_LEN - 1;
-+
-+ vp = paircreate(attrid, PW_TYPE_OCTETS);
-+ if (vp == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ memcpy(vp->vp_octets, p, n);
-+ vp->length = n;
-+
-+ pairadd(vps, vp);
-+
-+ p += n;
-+ remain -= n;
-+ } while (remain != 0);
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapRadiusGetRawAvp(OM_uint32 *minor,
-+ VALUE_PAIR *vps,
-+ uint16_t attribute,
-+ uint16_t vendor,
-+ VALUE_PAIR **vp)
-+{
-+ uint32_t attr = VENDORATTR(vendor, attribute);
-+
-+ *vp = pairfind(vps, attr);
-+ if (*vp == NULL) {
-+ *minor = GSSEAP_NO_SUCH_ATTR;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapRadiusGetAvp(OM_uint32 *minor,
-+ VALUE_PAIR *vps,
-+ uint16_t attribute,
-+ uint16_t vendor,
-+ gss_buffer_t buffer,
-+ int concat)
-+{
-+ VALUE_PAIR *vp;
-+ unsigned char *p;
-+ uint32_t attr = VENDORATTR(vendor, attribute);
-+
-+ if (buffer != GSS_C_NO_BUFFER) {
-+ buffer->length = 0;
-+ buffer->value = NULL;
-+ }
-+
-+ vp = pairfind(vps, attr);
-+ if (vp == NULL) {
-+ *minor = GSSEAP_NO_SUCH_ATTR;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (buffer != GSS_C_NO_BUFFER) {
-+ do {
-+ buffer->length += vp->length;
-+ } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
-+
-+ buffer->value = GSSEAP_MALLOC(buffer->length);
-+ if (buffer->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ p = (unsigned char *)buffer->value;
-+
-+ for (vp = pairfind(vps, attr);
-+ concat && vp != NULL;
-+ vp = pairfind(vp->next, attr)) {
-+ memcpy(p, vp->vp_octets, vp->length);
-+ p += vp->length;
-+ }
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapRadiusFreeAvps(OM_uint32 *minor,
-+ VALUE_PAIR **vps)
-+{
-+ pairfree(vps);
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapRadiusAttrProviderInit(OM_uint32 *minor)
-+{
-+ if (!gss_eap_radius_attr_provider::init()) {
-+ *minor = GSSEAP_RADSEC_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
-+{
-+ gss_eap_radius_attr_provider::finalize();
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+static JSONObject
-+avpToJson(const VALUE_PAIR *vp)
-+{
-+ JSONObject obj;
-+
-+ GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
-+
-+ switch (vp->type) {
-+ case PW_TYPE_INTEGER:
-+ case PW_TYPE_IPADDR:
-+ case PW_TYPE_DATE:
-+ obj.set("value", vp->lvalue);
-+ break;
-+ case PW_TYPE_STRING:
-+ obj.set("value", vp->vp_strvalue);
-+ break;
-+ default: {
-+ char *b64;
-+
-+ if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
-+ throw std::bad_alloc();
-+
-+ obj.set("value", b64);
-+ GSSEAP_FREE(b64);
-+ break;
-+ }
-+ }
-+
-+ obj.set("type", vp->attribute);
-+
-+ return obj;
-+}
-+
-+static bool
-+jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
-+{
-+ VALUE_PAIR *vp = NULL;
-+ DICT_ATTR *da;
-+ uint32_t attrid;
-+
-+ JSONObject type = obj["type"];
-+ JSONObject value = obj["value"];
-+
-+ if (!type.isInteger())
-+ goto fail;
-+
-+ attrid = type.integer();
-+ da = dict_attrbyvalue(attrid);
-+ if (da != NULL) {
-+ vp = pairalloc(da);
-+ } else {
-+ int type = base64Valid(value.string()) ?
-+ PW_TYPE_OCTETS : PW_TYPE_STRING;
-+ vp = paircreate(attrid, type);
-+ }
-+ if (vp == NULL)
-+ throw std::bad_alloc();
-+
-+ switch (vp->type) {
-+ case PW_TYPE_INTEGER:
-+ case PW_TYPE_IPADDR:
-+ case PW_TYPE_DATE:
-+ if (!value.isInteger())
-+ goto fail;
-+
-+ vp->length = 4;
-+ vp->lvalue = value.integer();
-+ break;
-+ case PW_TYPE_STRING: {
-+ if (!value.isString())
-+ goto fail;
-+
-+ const char *str = value.string();
-+ size_t len = strlen(str);
-+
-+ if (len >= MAX_STRING_LEN)
-+ goto fail;
-+
-+ vp->length = len;
-+ memcpy(vp->vp_strvalue, str, len + 1);
-+ break;
-+ }
-+ case PW_TYPE_OCTETS:
-+ default: {
-+ if (!value.isString())
-+ goto fail;
-+
-+ const char *str = value.string();
-+ ssize_t len = strlen(str);
-+
-+ /* this optimization requires base64Decode only understand packed encoding */
-+ if (len >= BASE64_EXPAND(MAX_STRING_LEN))
-+ goto fail;
-+
-+ len = base64Decode(str, vp->vp_octets);
-+ if (len < 0)
-+ goto fail;
-+
-+ vp->length = len;
-+ break;
-+ }
-+ }
-+
-+ *pVp = vp;
-+
-+ return true;
-+
-+fail:
-+ if (vp != NULL)
-+ pairbasicfree(vp);
-+ *pVp = NULL;
-+ return false;
-+}
-+
-+const char *
-+gss_eap_radius_attr_provider::name(void) const
-+{
-+ return "radius";
-+}
-+
-+bool
-+gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
-+ JSONObject &obj)
-+{
-+ VALUE_PAIR **pNext = &m_vps;
-+
-+ if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
-+ return false;
-+
-+ JSONObject attrs = obj["attributes"];
-+ size_t nelems = attrs.size();
-+
-+ for (size_t i = 0; i < nelems; i++) {
-+ JSONObject attr = attrs[i];
-+ VALUE_PAIR *vp;
-+
-+ if (!jsonToAvp(&vp, attr))
-+ return false;
-+
-+ *pNext = vp;
-+ pNext = &vp->next;
-+ }
-+
-+ m_authenticated = obj["authenticated"].integer() ? true : false;
-+
-+ return true;
-+}
-+
-+const char *
-+gss_eap_radius_attr_provider::prefix(void) const
-+{
-+ return "urn:ietf:params:gss-eap:radius-avp";
-+}
-+
-+JSONObject
-+gss_eap_radius_attr_provider::jsonRepresentation(void) const
-+{
-+ JSONObject obj, attrs = JSONObject::array();
-+
-+ for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
-+ JSONObject attr = avpToJson(vp);
-+ attrs.append(attr);
-+ }
-+
-+ obj.set("attributes", attrs);
-+
-+ obj.set("authenticated", m_authenticated);
-+
-+ return obj;
-+}
-+
-+time_t
-+gss_eap_radius_attr_provider::getExpiryTime(void) const
-+{
-+ VALUE_PAIR *vp;
-+
-+ vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
-+ if (vp == NULL || vp->lvalue == 0)
-+ return 0;
-+
-+ return time(NULL) + vp->lvalue;
-+}
-+
-+OM_uint32
-+gssEapRadiusMapError(OM_uint32 *minor,
-+ struct rs_error *err)
-+{
-+ int code;
-+
-+ GSSEAP_ASSERT(err != NULL);
-+
-+ code = rs_err_code(err, 0);
-+
-+ if (code == RSE_OK) {
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ *minor = ERROR_TABLE_BASE_rse + code;
-+
-+ gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
-+ rs_err_free(err);
-+
-+ return GSS_S_FAILURE;
-+}
-+
-+OM_uint32
-+gssEapCreateRadiusContext(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ struct rs_context **pRadContext)
-+{
-+ const char *configFile = RS_CONFIG_FILE;
-+ struct rs_context *radContext;
-+ struct rs_alloc_scheme ralloc;
-+ struct rs_error *err;
-+ OM_uint32 major;
-+
-+ *pRadContext = NULL;
-+
-+ if (rs_context_create(&radContext) != 0) {
-+ *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (cred->radiusConfigFile.value != NULL)
-+ configFile = (const char *)cred->radiusConfigFile.value;
-+
-+ ralloc.calloc = GSSEAP_CALLOC;
-+ ralloc.malloc = GSSEAP_MALLOC;
-+ ralloc.free = GSSEAP_FREE;
-+ ralloc.realloc = GSSEAP_REALLOC;
-+
-+ rs_context_set_alloc_scheme(radContext, &ralloc);
-+
-+ if (rs_context_read_config(radContext, configFile) != 0) {
-+ err = rs_err_ctx_pop(radContext);
-+ goto fail;
-+ }
-+
-+ if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
-+ err = rs_err_ctx_pop(radContext);
-+ goto fail;
-+ }
-+
-+ *pRadContext = radContext;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+
-+fail:
-+ major = gssEapRadiusMapError(minor, err);
-+ rs_context_destroy(radContext);
-+
-+ return major;
-+}
-diff --git a/mech_eap/util_radius.h b/mech_eap/util_radius.h
-new file mode 100644
-index 0000000..481876a
---- /dev/null
-+++ b/mech_eap/util_radius.h
-@@ -0,0 +1,183 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * RADIUS attribute provider.
-+ */
-+
-+#ifndef _UTIL_RADIUS_H_
-+#define _UTIL_RADIUS_H_ 1
-+
-+#ifdef __cplusplus
-+
-+struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
-+public:
-+ gss_eap_radius_attr_provider(void);
-+ ~gss_eap_radius_attr_provider(void);
-+
-+ bool initWithExistingContext(const gss_eap_attr_ctx *source,
-+ const gss_eap_attr_provider *ctx);
-+ bool initWithGssContext(const gss_eap_attr_ctx *source,
-+ const gss_cred_id_t cred,
-+ const gss_ctx_id_t ctx);
-+
-+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
-+ bool setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(const gss_buffer_t attr);
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ gss_any_t mapToAny(int authenticated,
-+ gss_buffer_t type_id) const;
-+ void releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const;
-+
-+ const char *prefix(void) const;
-+ const char *name(void) const;
-+ bool initWithJsonObject(const gss_eap_attr_ctx *manager,
-+ JSONObject &obj);
-+ JSONObject jsonRepresentation(void) const;
-+
-+ bool getAttribute(uint32_t attribute,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ bool getAttribute(uint16_t attribute,
-+ uint16_t vendor,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ bool setAttribute(int complete,
-+ uint32_t attribute,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(uint32_t attribute);
-+
-+ bool getFragmentedAttribute(uint16_t attribute,
-+ uint16_t vendor,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value) const;
-+ bool getFragmentedAttribute(uint32_t attrid,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value) const;
-+
-+ bool authenticated(void) const { return m_authenticated; }
-+
-+ time_t getExpiryTime(void) const;
-+
-+ static bool init(void);
-+ static void finalize(void);
-+
-+ static gss_eap_attr_provider *createAttrContext(void);
-+
-+private:
-+ const VALUE_PAIR *getAvps(void) const {
-+ return m_vps;
-+ }
-+
-+ VALUE_PAIR *m_vps;
-+ bool m_authenticated;
-+};
-+
-+/* For now */
-+extern "C" {
-+#endif
-+
-+OM_uint32
-+gssEapRadiusAddAvp(OM_uint32 *minor,
-+ VALUE_PAIR **vp,
-+ uint16_t type,
-+ uint16_t vendor,
-+ const gss_buffer_t buffer);
-+
-+OM_uint32
-+gssEapRadiusGetAvp(OM_uint32 *minor,
-+ VALUE_PAIR *vps,
-+ uint16_t type,
-+ uint16_t vendor,
-+ gss_buffer_t buffer,
-+ int concat);
-+
-+OM_uint32
-+gssEapRadiusGetRawAvp(OM_uint32 *minor,
-+ VALUE_PAIR *vps,
-+ uint16_t type,
-+ uint16_t vendor,
-+ VALUE_PAIR **vp);
-+OM_uint32
-+gssEapRadiusFreeAvps(OM_uint32 *minor,
-+ VALUE_PAIR **vps);
-+
-+OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
-+OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
-+
-+OM_uint32
-+gssEapRadiusMapError(OM_uint32 *minor,
-+ struct rs_error *err);
-+
-+OM_uint32
-+gssEapCreateRadiusContext(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ struct rs_context **pRadContext);
-+
-+/* This really needs to be a function call on Windows */
-+#define RS_CONFIG_FILE SYSCONFDIR "/radsec.conf"
-+
-+#define VENDORPEC_MS 311 /* RFC 2548 */
-+
-+#define PW_MS_MPPE_SEND_KEY 16
-+#define PW_MS_MPPE_RECV_KEY 17
-+
-+#define VENDORPEC_UKERNA 25622
-+
-+#define PW_GSS_ACCEPTOR_SERVICE_NAME 128
-+#define PW_GSS_ACCEPTOR_HOST_NAME 129
-+#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC 130
-+#define PW_GSS_ACCEPTOR_REALM_NAME 131
-+#define PW_SAML_AAA_ASSERTION 132
-+#define PW_MS_WINDOWS_AUTH_DATA 133
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _UTIL_RADIUS_H_ */
-diff --git a/mech_eap/util_reauth.c b/mech_eap/util_reauth.c
-new file mode 100644
-index 0000000..50011ca
---- /dev/null
-+++ b/mech_eap/util_reauth.c
-@@ -0,0 +1,1196 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Fast reauthentication support.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#include <dlfcn.h>
-+
-+/*
-+ * Fast reauthentication support for EAP GSS.
-+ */
-+
-+krb5_error_code
-+krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
-+
-+krb5_error_code
-+encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
-+
-+static OM_uint32
-+gssDisplayName(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t buffer,
-+ gss_OID *name_type);
-+
-+static OM_uint32
-+gssImportName(OM_uint32 *minor,
-+ gss_buffer_t buffer,
-+ gss_OID name_type,
-+ gss_name_t *name);
-+
-+static krb5_error_code
-+getAcceptorKey(krb5_context krbContext,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ krb5_principal *princ,
-+ krb5_keyblock *key)
-+{
-+ krb5_error_code code;
-+ krb5_keytab keytab = NULL;
-+ krb5_keytab_entry ktent = { 0 };
-+ krb5_kt_cursor cursor;
-+
-+ *princ = NULL;
-+ memset(key, 0, sizeof(*key));
-+ memset(&cursor, 0, sizeof(cursor));
-+
-+ code = krb5_kt_default(krbContext, &keytab);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
-+ code = krb5_kt_get_entry(krbContext, keytab,
-+ cred->name->krbPrincipal, 0,
-+ ctx->encryptionType, &ktent);
-+ if (code != 0)
-+ goto cleanup;
-+ } else {
-+ /*
-+ * It's not clear that looking encrypting the ticket in the
-+ * requested EAP enctype provides any value.
-+ */
-+ code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ while ((code = krb5_kt_next_entry(krbContext, keytab,
-+ &ktent, &cursor)) == 0) {
-+ if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType)
-+ break;
-+ else
-+ KRB_KT_ENT_FREE(krbContext, &ktent);
-+ }
-+ }
-+
-+ if (code == 0) {
-+ *princ = ktent.principal;
-+ *key = *KRB_KT_ENT_KEYBLOCK(&ktent);
-+ }
-+
-+cleanup:
-+ if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
-+ krb5_kt_end_seq_get(krbContext, keytab, &cursor);
-+ krb5_kt_close(krbContext, keytab);
-+ if (code != 0)
-+ KRB_KT_ENT_FREE(krbContext, &ktent);
-+
-+ return code;
-+}
-+
-+static OM_uint32
-+freezeAttrContext(OM_uint32 *minor,
-+ gss_name_t initiatorName,
-+ krb5_const_principal acceptorPrinc,
-+ krb5_keyblock *session,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_authdata *kdcIssuedAuthData
-+#else
-+ krb5_authdata ***kdcIssuedAuthData
-+#endif
-+ )
-+{
-+ OM_uint32 major, tmpMinor;
-+ krb5_error_code code;
-+ krb5_context krbContext;
-+ gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_authdata authDataBuf, *authData = &authDataBuf;
-+ AuthorizationDataElement authDatum = { 0 };
-+#else
-+ krb5_authdata *authData[2], authDatum = { 0 };
-+#endif
-+
-+ memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData));
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ authDatum.ad_data.length = attrBuf.length;
-+ authDatum.ad_data.data = attrBuf.value;
-+ authData->len = 1;
-+ authData->val = &authDatum;
-+#else
-+ authDatum.length = attrBuf.length;
-+ authDatum.contents = attrBuf.value;
-+ authData[0] = &authDatum;
-+ authData[1] = NULL;
-+#endif
-+
-+ code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc,
-+ authData, kdcIssuedAuthData);
-+ if (code != 0) {
-+ major = GSS_S_FAILURE;
-+ *minor = code;
-+ } else {
-+ major = GSS_S_COMPLETE;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &attrBuf);
-+
-+ return major;
-+}
-+
-+/*
-+ * Fabricate a ticket to ourselves given a GSS EAP context.
-+ */
-+OM_uint32
-+gssEapMakeReauthCreds(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ gss_buffer_t credBuf)
-+{
-+ OM_uint32 major = GSS_S_COMPLETE;
-+ krb5_error_code code;
-+ krb5_context krbContext = NULL;
-+ krb5_keyblock session = { 0 }, acceptorKey = { 0 };
-+ krb5_principal server = NULL;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ Ticket ticket;
-+ EncTicketPart enc_part;
-+ AuthorizationData authData = { 0 };
-+ krb5_crypto krbCrypto = NULL;
-+ krb5_data ticketData = { 0 };
-+ krb5_data encPartData = { 0 };
-+ size_t len;
-+#else
-+ krb5_ticket ticket;
-+ krb5_enc_tkt_part enc_part;
-+ krb5_data *ticketData = NULL;
-+#endif
-+ krb5_data credsData = { 0 };
-+ krb5_creds creds = { 0 };
-+ krb5_auth_context authContext = NULL;
-+
-+ memset(&ticket, 0, sizeof(ticket));
-+ memset(&enc_part, 0, sizeof(enc_part));
-+
-+ credBuf->length = 0;
-+ credBuf->value = NULL;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ /*
-+ * Generate a random session key to place in the ticket and
-+ * sign the "KDC-Issued" authorization data element.
-+ */
-+#ifdef HAVE_HEIMDAL_VERSION
-+ ticket.realm = server->realm;
-+ ticket.sname = server->name;
-+
-+ code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType,
-+ &session);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ enc_part.flags.initial = 1;
-+ enc_part.key = session;
-+ enc_part.crealm = ctx->initiatorName->krbPrincipal->realm;
-+ enc_part.cname = ctx->initiatorName->krbPrincipal->name;
-+ enc_part.authtime = time(NULL);
-+ enc_part.starttime = &enc_part.authtime;
-+ enc_part.endtime = (ctx->expiryTime != 0)
-+ ? ctx->expiryTime : KRB_TIME_FOREVER;
-+ enc_part.renew_till = NULL;
-+ enc_part.authorization_data = &authData;
-+
-+ major = freezeAttrContext(minor, ctx->initiatorName, server,
-+ &session, &authData);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length,
-+ &enc_part, &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_encrypt_EncryptedData(krbContext,
-+ krbCrypto,
-+ KRB5_KU_TICKET,
-+ encPartData.data,
-+ encPartData.length,
-+ 0,
-+ &ticket.enc_part);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length,
-+ &ticket, &len, code);
-+ if (code != 0)
-+ goto cleanup;
-+#else
-+ ticket.server = server;
-+
-+ code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
-+ &session);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ enc_part.flags = TKT_FLG_INITIAL;
-+ enc_part.session = &session;
-+ enc_part.client = ctx->initiatorName->krbPrincipal;
-+ enc_part.times.authtime = time(NULL);
-+ enc_part.times.starttime = enc_part.times.authtime;
-+ enc_part.times.endtime = (ctx->expiryTime != 0)
-+ ? ctx->expiryTime
-+ : KRB_TIME_FOREVER;
-+ enc_part.times.renew_till = 0;
-+
-+ major = freezeAttrContext(minor, ctx->initiatorName, server,
-+ &session, &enc_part.authorization_data);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ticket.enc_part2 = &enc_part;
-+
-+ code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = encode_krb5_ticket(&ticket, &ticketData);
-+ if (code != 0)
-+ goto cleanup;
-+#endif /* HAVE_HEIMDAL_VERSION */
-+
-+ creds.client = ctx->initiatorName->krbPrincipal;
-+ creds.server = server;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ creds.session = session;
-+ creds.times.authtime = enc_part.authtime;
-+ creds.times.starttime = *enc_part.starttime;
-+ creds.times.endtime = enc_part.endtime;
-+ creds.times.renew_till = 0;
-+ creds.flags.b = enc_part.flags;
-+ creds.ticket = ticketData;
-+ creds.authdata = authData;
-+#else
-+ creds.keyblock = session;
-+ creds.times = enc_part.times;
-+ creds.ticket_flags = enc_part.flags;
-+ creds.ticket = *ticketData;
-+ creds.authdata = enc_part.authorization_data;
-+#endif
-+
-+ code = krb5_auth_con_init(krbContext, &authContext);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_auth_con_setflags(krbContext, authContext, 0);
-+ if (code != 0)
-+ goto cleanup;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_auth_con_setlocalsubkey(krbContext, authContext,
-+ &ctx->rfc3961Key);
-+#else
-+ code = krb5_auth_con_setsendsubkey(krbContext, authContext,
-+ &ctx->rfc3961Key);
-+#endif
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krbMakeCred(krbContext, authContext, &creds, &credsData);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ krbDataToGssBuffer(&credsData, credBuf);
-+
-+cleanup:
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (krbCrypto != NULL)
-+ krb5_crypto_destroy(krbContext, krbCrypto);
-+ free_AuthorizationData(&authData);
-+ free_EncryptedData(&ticket.enc_part);
-+ krb5_data_free(&ticketData);
-+ krb5_data_free(&encPartData);
-+#else
-+ krb5_free_authdata(krbContext, enc_part.authorization_data);
-+ if (ticket.enc_part.ciphertext.data != NULL)
-+ GSSEAP_FREE(ticket.enc_part.ciphertext.data);
-+ krb5_free_data(krbContext, ticketData);
-+#endif
-+ krb5_free_keyblock_contents(krbContext, &session);
-+ krb5_free_principal(krbContext, server);
-+ krb5_free_keyblock_contents(krbContext, &acceptorKey);
-+ krb5_auth_con_free(krbContext, authContext);
-+
-+ if (major == GSS_S_COMPLETE) {
-+ *minor = code;
-+ major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
-+ }
-+
-+ return major;
-+}
-+
-+static int
-+isTicketGrantingServiceP(krb5_context krbContext GSSEAP_UNUSED,
-+ krb5_const_principal principal)
-+{
-+ if (KRB_PRINC_LENGTH(principal) == 2 &&
-+#ifdef HAVE_HEIMDAL_VERSION
-+ strcmp(KRB_PRINC_NAME(principal)[0], "krbtgt") == 0
-+#else
-+ krb5_princ_component(krbContext, principal, 0)->length == 6 &&
-+ memcmp(krb5_princ_component(krbContext,
-+ principal, 0)->data, "krbtgt", 6) == 0
-+#endif
-+ )
-+ return TRUE;
-+
-+ return FALSE;
-+}
-+
-+/*
-+ * Returns TRUE if the configuration variable reauth_use_ccache is
-+ * set in krb5.conf for the eap_gss application and the client realm.
-+ */
-+static int
-+reauthUseCredsCache(krb5_context krbContext,
-+ krb5_principal principal)
-+{
-+ int reauthUseCCache;
-+
-+ /* if reauth_use_ccache, use default credentials cache if ticket is for us */
-+ krb5_appdefault_boolean(krbContext, "eap_gss",
-+ KRB_PRINC_REALM(principal),
-+ "reauth_use_ccache", 0, &reauthUseCCache);
-+
-+ return reauthUseCCache;
-+}
-+
-+/*
-+ * Look in default credentials cache for reauthentication credentials,
-+ * if policy allows.
-+ */
-+static OM_uint32
-+getDefaultReauthCredentials(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_name_t target,
-+ time_t now,
-+ OM_uint32 timeReq)
-+{
-+ OM_uint32 major = GSS_S_CRED_UNAVAIL;
-+ krb5_context krbContext = NULL;
-+ krb5_error_code code = 0;
-+ krb5_ccache ccache = NULL;
-+ krb5_creds match = { 0 };
-+ krb5_creds creds = { 0 };
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
-+ GSSEAP_ASSERT(target != GSS_C_NO_NAME);
-+
-+ if (cred->name == GSS_C_NO_NAME ||
-+ !reauthUseCredsCache(krbContext, cred->name->krbPrincipal))
-+ goto cleanup;
-+
-+ match.client = cred->name->krbPrincipal;
-+ match.server = target->krbPrincipal;
-+ if (timeReq != 0 && timeReq != GSS_C_INDEFINITE)
-+ match.times.endtime = now + timeReq;
-+
-+ code = krb5_cc_default(krbContext, &ccache);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
-+ cred->krbCredCache = ccache;
-+ ccache = NULL;
-+
-+ major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
-+ &cred->reauthCred);
-+
-+cleanup:
-+ if (major == GSS_S_CRED_UNAVAIL)
-+ *minor = code;
-+
-+ if (ccache != NULL)
-+ krb5_cc_close(krbContext, ccache);
-+ krb5_free_cred_contents(krbContext, &creds);
-+
-+ return major;
-+}
-+
-+/*
-+ * Returns TRUE if the credential handle's reauth credentials are
-+ * valid or if we can use the default credentials cache. Credentials
-+ * handle must be locked.
-+ */
-+int
-+gssEapCanReauthP(gss_cred_id_t cred,
-+ gss_name_t target,
-+ OM_uint32 timeReq)
-+{
-+ time_t now, expiryReq;
-+ OM_uint32 minor;
-+
-+ if (cred == GSS_C_NO_CREDENTIAL)
-+ return FALSE;
-+
-+ now = time(NULL);
-+ expiryReq = now;
-+ if (timeReq != GSS_C_INDEFINITE)
-+ expiryReq += timeReq;
-+
-+ if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq)
-+ return TRUE;
-+
-+ if (getDefaultReauthCredentials(&minor, cred, target,
-+ now, timeReq) == GSS_S_COMPLETE)
-+ return TRUE;
-+
-+ return FALSE;
-+}
-+
-+/*
-+ * Store re-authentication (Kerberos) credentials in a credential handle.
-+ * Credentials handle must be locked.
-+ */
-+OM_uint32
-+gssEapStoreReauthCreds(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ gss_buffer_t credBuf)
-+{
-+ OM_uint32 major = GSS_S_COMPLETE;
-+ krb5_error_code code;
-+ krb5_context krbContext = NULL;
-+ krb5_auth_context authContext = NULL;
-+ krb5_data credData = { 0 };
-+ krb5_creds **creds = NULL;
-+ krb5_principal canonPrinc;
-+ krb5_principal ccPrinc = NULL;
-+ int i;
-+
-+ if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL)
-+ return GSS_S_COMPLETE;
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ code = krb5_auth_con_init(krbContext, &authContext);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_auth_con_setflags(krbContext, authContext, 0);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
-+ &ctx->rfc3961Key);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ gssBufferToKrbData(credBuf, &credData);
-+
-+ code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ if (creds == NULL || creds[0] == NULL)
-+ goto cleanup;
-+
-+ code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ krb5_free_principal(krbContext, cred->name->krbPrincipal);
-+ cred->name->krbPrincipal = canonPrinc;
-+
-+ if (creds[0]->times.endtime == KRB_TIME_FOREVER)
-+ cred->expiryTime = 0;
-+ else
-+ cred->expiryTime = creds[0]->times.endtime;
-+
-+ if (cred->krbCredCache == NULL) {
-+ if (reauthUseCredsCache(krbContext, creds[0]->client) &&
-+ krb5_cc_default(krbContext, &cred->krbCredCache) == 0)
-+ cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
-+ } else {
-+ /*
-+ * If we already have an associated credentials cache, possibly from
-+ * the last time we stored a reauthentication credential, then we
-+ * need to clear it out and release the associated GSS credential.
-+ */
-+ if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) {
-+ krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]);
-+ } else {
-+ krb5_cc_destroy(krbContext, cred->krbCredCache);
-+ cred->krbCredCache = NULL;
-+ }
-+ gssReleaseCred(minor, &cred->reauthCred);
-+ }
-+
-+ if (cred->krbCredCache == NULL) {
-+ code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+
-+ if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 ||
-+ krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) {
-+ code = krb5_cc_initialize(krbContext, cred->krbCredCache,
-+ creds[0]->client);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+
-+ for (i = 0; creds[i] != NULL; i++) {
-+ krb5_creds kcred = *(creds[i]);
-+
-+ /*
-+ * Swap in the acceptor name the client asked for so
-+ * get_credentials() works. We're making the assumption that
-+ * any service tickets returned are for us. We'll need to
-+ * reflect some more on whether that is a safe assumption.
-+ */
-+ if (!isTicketGrantingServiceP(krbContext, kcred.server))
-+ kcred.server = ctx->acceptorName->krbPrincipal;
-+
-+ code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
-+ if (code != 0)
-+ goto cleanup;
-+ }
-+
-+ major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
-+ &cred->reauthCred);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ *minor = code;
-+
-+ krb5_free_principal(krbContext, ccPrinc);
-+ krb5_auth_con_free(krbContext, authContext);
-+ if (creds != NULL) {
-+ for (i = 0; creds[i] != NULL; i++)
-+ krb5_free_creds(krbContext, creds[i]);
-+ GSSEAP_FREE(creds);
-+ }
-+ if (major == GSS_S_COMPLETE)
-+ major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
-+
-+ return major;
-+}
-+
-+#ifndef HAVE_HEIMDAL_VERSION
-+static gss_buffer_desc radiusAvpKrbAttr = {
-+ sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
-+};
-+#endif
-+
-+/*
-+ * Unfortunately extracting an AD-KDCIssued authorization data element
-+ * is pretty implementation-dependent. It's not possible to verify the
-+ * signature ourselves because the ticket session key is not exposed
-+ * outside GSS. In an ideal world, all AD-KDCIssued elements would be
-+ * verified by the Kerberos library and authentication would fail if
-+ * verification failed. We're not quite there yet and as a result have
-+ * to go through some hoops to get this to work. The alternative would
-+ * be to sign the authorization data with our long-term key, but it
-+ * seems a pity to compromise the design because of current implementation
-+ * limitations.
-+ *
-+ * (Specifically, the hoops involve a libkrb5 authorisation data plugin
-+ * that exposes the verified and serialised attribute context through
-+ * the Kerberos GSS mechanism's naming extensions API.)
-+ */
-+static OM_uint32
-+defrostAttrContext(OM_uint32 *minor,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ gss_ctx_id_t glueContext,
-+#else
-+ gss_name_t glueName,
-+#endif
-+ gss_name_t mechName)
-+{
-+ OM_uint32 major, tmpMinor;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ gss_OID_desc oid = { 0 };
-+ gss_buffer_set_t authData = GSS_C_NO_BUFFER_SET;
-+#else
-+ gss_buffer_desc authData = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER;
-+ int more = -1;
-+ int authenticated, complete;
-+#endif
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ major = composeOid(minor,
-+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
-+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
-+ KRB5_AUTHDATA_RADIUS_AVP, &oid);
-+ if (GSS_ERROR(major))
-+ return major;
-+
-+ /* XXX we are assuming that this verifies AD-KDCIssued signature */
-+ major = gssInquireSecContextByOid(minor, glueContext,
-+ &oid, &authData);
-+ if (major == GSS_S_COMPLETE) {
-+ if (authData == GSS_C_NO_BUFFER_SET || authData->count != 1)
-+ major = GSS_S_FAILURE;
-+ else
-+ major = gssEapImportAttrContext(minor, authData->elements, mechName);
-+ } else if (major == GSS_S_FAILURE && *minor == ENOENT) {
-+ /* This is the equivalent of GSS_S_UNAVAILABLE for MIT attr APIs */
-+ *minor = 0;
-+ major = GSS_S_COMPLETE;
-+ }
-+
-+ gss_release_buffer_set(&tmpMinor, &authData);
-+ GSSEAP_FREE(oid.elements);
-+#else
-+ major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr,
-+ &authenticated, &complete,
-+ &authData, &authDataDisplay, &more);
-+ if (major == GSS_S_COMPLETE) {
-+ if (authenticated == 0)
-+ major = GSS_S_BAD_NAME;
-+ else
-+ major = gssEapImportAttrContext(minor, &authData, mechName);
-+ } else if (major == GSS_S_UNAVAILABLE) {
-+ major = GSS_S_COMPLETE;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &authData);
-+ gss_release_buffer(&tmpMinor, &authDataDisplay);
-+#endif /* HAVE_HEIMDAL_VERSION */
-+
-+ return major;
-+}
-+
-+/*
-+ * Convert a mechanism glue to an EAP mechanism name by displaying and
-+ * importing it. This also handles the RADIUS attributes.
-+ */
-+OM_uint32
-+gssEapGlueToMechName(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_name_t glueName,
-+ gss_name_t *pMechName)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+
-+ *pMechName = GSS_C_NO_NAME;
-+
-+ major = gssDisplayName(minor, glueName, &nameBuf, NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
-+ ctx->mechanismUsed, pMechName);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = defrostAttrContext(minor,
-+#ifdef HAVE_HEIMDAL_VERSION
-+ ctx->reauthCtx,
-+#else
-+ glueName,
-+#endif
-+ *pMechName);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ gssReleaseName(&tmpMinor, pMechName);
-+ *pMechName = GSS_C_NO_NAME;
-+ }
-+
-+ gss_release_buffer(&tmpMinor, &nameBuf);
-+
-+ return major;
-+}
-+
-+/*
-+ * Convert an EAP mechanism name to a mechanism glue name by displaying
-+ * and importing it.
-+ */
-+OM_uint32
-+gssEapMechToGlueName(OM_uint32 *minor,
-+ gss_name_t mechName,
-+ gss_name_t *pGlueName)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+
-+ *pGlueName = GSS_C_NO_NAME;
-+
-+ major = gssEapDisplayName(minor, mechName, &nameBuf, NULL);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
-+ pGlueName);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ gss_release_buffer(&tmpMinor, &nameBuf);
-+
-+ return major;
-+}
-+
-+/*
-+ * Suck out the analgous elements of a Kerberos GSS context into an EAP
-+ * one so that the application doesn't know the difference.
-+ */
-+OM_uint32
-+gssEapReauthComplete(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred GSSEAP_UNUSED,
-+ const gss_OID mech,
-+ OM_uint32 timeRec)
-+{
-+ OM_uint32 major, tmpMinor;
-+ gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
-+ krb5_context krbContext = NULL;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_storage *sp = NULL;
-+#endif
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ if (!oidEqual(mech, gss_mech_krb5)) {
-+ major = GSS_S_BAD_MECH;
-+ goto cleanup;
-+ }
-+
-+ /* Get the raw subsession key and encryption type */
-+#ifdef HAVE_HEIMDAL_VERSION
-+#define KRB_GSS_SUBKEY_COUNT 1 /* encoded session key */
-+ major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
-+ GSS_KRB5_GET_SUBKEY_X, &keyData);
-+#else
-+#define KRB_GSS_SUBKEY_COUNT 2 /* raw session key, enctype OID */
-+ major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
-+ GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
-+#endif
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (keyData == GSS_C_NO_BUFFER_SET || keyData->count < KRB_GSS_SUBKEY_COUNT) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ sp = krb5_storage_from_mem(keyData->elements[0].value,
-+ keyData->elements[0].length);
-+ if (sp == NULL) {
-+ *minor = ENOMEM;
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+
-+ *minor = krb5_ret_keyblock(sp, &ctx->rfc3961Key);
-+ if (*minor != 0) {
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+#else
-+ {
-+ gss_OID_desc oid;
-+ int suffix;
-+
-+ oid.length = keyData->elements[1].length;
-+ oid.elements = keyData->elements[1].value;
-+
-+ /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
-+ major = decomposeOid(minor,
-+ "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
-+ 10, &oid, &suffix);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ctx->encryptionType = suffix;
-+ }
-+
-+ {
-+ krb5_keyblock key;
-+
-+ KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
-+ KRB_KEY_DATA(&key) = keyData->elements[0].value;
-+ KRB_KEY_TYPE(&key) = ctx->encryptionType;
-+
-+ *minor = krb5_copy_keyblock_contents(krbContext,
-+ &key, &ctx->rfc3961Key);
-+ if (*minor != 0) {
-+ major = GSS_S_FAILURE;
-+ goto cleanup;
-+ }
-+ }
-+#endif /* HAVE_HEIMDAL_VERSION */
-+
-+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
-+ &ctx->checksumType);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (timeRec != GSS_C_INDEFINITE)
-+ ctx->expiryTime = time(NULL) + timeRec;
-+
-+ /* Initialize our sequence state */
-+ major = sequenceInit(minor,
-+ &ctx->seqState, ctx->recvSeq,
-+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
-+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
-+ TRUE);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = GSS_S_COMPLETE;
-+
-+cleanup:
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (sp != NULL)
-+ krb5_storage_free(sp);
-+#endif
-+ gss_release_buffer_set(&tmpMinor, &keyData);
-+
-+ return major;
-+}
-+
-+/*
-+ * The remainder of this file consists of wrappers so we can call into the
-+ * mechanism glue without calling ourselves.
-+ */
-+static OM_uint32
-+(*gssInitSecContextNext)(OM_uint32 *,
-+ gss_cred_id_t,
-+ gss_ctx_id_t *,
-+ gss_name_t,
-+ gss_OID,
-+ OM_uint32,
-+ OM_uint32,
-+ gss_channel_bindings_t,
-+ gss_buffer_t,
-+ gss_OID *,
-+ gss_buffer_t,
-+ OM_uint32 *,
-+ OM_uint32 *);
-+
-+static OM_uint32
-+(*gssAcceptSecContextNext)(OM_uint32 *,
-+ gss_ctx_id_t *,
-+ gss_cred_id_t,
-+ gss_buffer_t,
-+ gss_channel_bindings_t,
-+ gss_name_t *,
-+ gss_OID *,
-+ gss_buffer_t,
-+ OM_uint32 *,
-+ OM_uint32 *,
-+ gss_cred_id_t *);
-+
-+static OM_uint32
-+(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *);
-+
-+static OM_uint32
-+(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *);
-+
-+static OM_uint32
-+(*gssInquireSecContextByOidNext)(OM_uint32 *,
-+ const gss_ctx_id_t,
-+ const gss_OID,
-+ gss_buffer_set_t *);
-+
-+static OM_uint32
-+(*gssDeleteSecContextNext)(OM_uint32 *,
-+ gss_ctx_id_t *,
-+ gss_buffer_t);
-+
-+static OM_uint32
-+(*gssDisplayNameNext)(OM_uint32 *,
-+ gss_name_t,
-+ gss_buffer_t,
-+ gss_OID *);
-+
-+static OM_uint32
-+(*gssImportNameNext)(OM_uint32 *,
-+ gss_buffer_t,
-+ gss_OID,
-+ gss_name_t *);
-+
-+static OM_uint32
-+(*gssStoreCredNext)(OM_uint32 *,
-+ const gss_cred_id_t,
-+ gss_cred_usage_t,
-+ const gss_OID,
-+ OM_uint32,
-+ OM_uint32,
-+ gss_OID_set *,
-+ gss_cred_usage_t *);
-+
-+static OM_uint32
-+(*gssGetNameAttributeNext)(OM_uint32 *,
-+ gss_name_t,
-+ gss_buffer_t,
-+ int *,
-+ int *,
-+ gss_buffer_t,
-+ gss_buffer_t,
-+ int *);
-+
-+#define NEXT_SYMBOL(local, global) do { \
-+ ((local) = dlsym(RTLD_NEXT, (global))); \
-+ if ((local) == NULL) { \
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \
-+ major = GSS_S_UNAVAILABLE; \
-+ /* but continue */ \
-+ } \
-+ } while (0)
-+
-+OM_uint32
-+gssEapReauthInitialize(OM_uint32 *minor)
-+{
-+ OM_uint32 major = GSS_S_COMPLETE;
-+
-+ NEXT_SYMBOL(gssInitSecContextNext, "gss_init_sec_context");
-+ NEXT_SYMBOL(gssAcceptSecContextNext, "gss_accept_sec_context");
-+ NEXT_SYMBOL(gssReleaseCredNext, "gss_release_cred");
-+ NEXT_SYMBOL(gssReleaseNameNext, "gss_release_name");
-+ NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid");
-+ NEXT_SYMBOL(gssDeleteSecContextNext, "gss_delete_sec_context");
-+ NEXT_SYMBOL(gssDisplayNameNext, "gss_display_name");
-+ NEXT_SYMBOL(gssImportNameNext, "gss_import_name");
-+ NEXT_SYMBOL(gssStoreCredNext, "gss_store_cred");
-+#ifndef HAVE_HEIMDAL_VERSION
-+ NEXT_SYMBOL(gssGetNameAttributeNext, "gss_get_name_attribute");
-+#endif
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssInitSecContext(OM_uint32 *minor,
-+ 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)
-+{
-+ if (gssInitSecContextNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssInitSecContextNext(minor, 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);
-+}
-+
-+OM_uint32
-+gssAcceptSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_cred_id_t cred,
-+ 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)
-+{
-+ if (gssAcceptSecContextNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssAcceptSecContextNext(minor, context_handle, cred,
-+ input_token, input_chan_bindings,
-+ src_name, mech_type, output_token,
-+ ret_flags, time_rec, delegated_cred_handle);
-+}
-+
-+OM_uint32
-+gssReleaseCred(OM_uint32 *minor,
-+ gss_cred_id_t *cred_handle)
-+{
-+ if (gssReleaseCredNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssReleaseCredNext(minor, cred_handle);
-+}
-+
-+OM_uint32
-+gssReleaseName(OM_uint32 *minor,
-+ gss_name_t *name)
-+{
-+ if (gssReleaseName == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssReleaseNameNext(minor, name);
-+}
-+
-+OM_uint32
-+gssDeleteSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_buffer_t output_token)
-+{
-+ if (gssDeleteSecContextNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssDeleteSecContextNext(minor, context_handle, output_token);
-+}
-+
-+static OM_uint32
-+gssDisplayName(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t buffer,
-+ gss_OID *name_type)
-+{
-+ if (gssDisplayNameNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssDisplayNameNext(minor, name, buffer, name_type);
-+}
-+
-+static OM_uint32
-+gssImportName(OM_uint32 *minor,
-+ gss_buffer_t buffer,
-+ gss_OID name_type,
-+ gss_name_t *name)
-+{
-+ if (gssImportNameNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssImportNameNext(minor, buffer, name_type, name);
-+}
-+
-+OM_uint32
-+gssInquireSecContextByOid(OM_uint32 *minor,
-+ const gss_ctx_id_t context_handle,
-+ const gss_OID desired_object,
-+ gss_buffer_set_t *data_set)
-+{
-+ if (gssInquireSecContextByOidNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssInquireSecContextByOidNext(minor, context_handle,
-+ desired_object, data_set);
-+}
-+
-+OM_uint32
-+gssStoreCred(OM_uint32 *minor,
-+ 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)
-+{
-+ if (gssStoreCredNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssStoreCredNext(minor, input_cred_handle, input_usage,
-+ desired_mech, overwrite_cred, default_cred,
-+ elements_stored, cred_usage_stored);
-+}
-+
-+OM_uint32
-+gssGetNameAttribute(OM_uint32 *minor,
-+ gss_name_t name,
-+ gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more)
-+{
-+ if (gssGetNameAttributeNext == NULL) {
-+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ return gssGetNameAttributeNext(minor, name, attr, authenticated, complete,
-+ value, display_value, more);
-+}
-diff --git a/mech_eap/util_reauth.h b/mech_eap/util_reauth.h
-new file mode 100644
-index 0000000..9b9f264
---- /dev/null
-+++ b/mech_eap/util_reauth.h
-@@ -0,0 +1,151 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Fast reauthentication support.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#ifndef _UTIL_REAUTH_H_
-+#define _UTIL_REAUTH_H_ 1
-+
-+/* AD element containing serialised AVPs. */
-+#define KRB5_AUTHDATA_RADIUS_AVP 513
-+
-+OM_uint32
-+gssInitSecContext(OM_uint32 *minor,
-+ 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);
-+
-+OM_uint32
-+gssAcceptSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_cred_id_t cred,
-+ 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
-+gssReleaseCred(OM_uint32 *minor,
-+ gss_cred_id_t *cred_handle);
-+
-+OM_uint32
-+gssReleaseName(OM_uint32 *minor,
-+ gss_name_t *name);
-+
-+OM_uint32
-+gssDeleteSecContext(OM_uint32 *minor,
-+ gss_ctx_id_t *context_handle,
-+ gss_buffer_t output_token);
-+
-+OM_uint32
-+gssInquireSecContextByOid(OM_uint32 *minor,
-+ const gss_ctx_id_t context_handle,
-+ const gss_OID desired_object,
-+ gss_buffer_set_t *data_set);
-+
-+OM_uint32
-+gssStoreCred(OM_uint32 *minor,
-+ 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
-+gssGetNameAttribute(OM_uint32 *minor,
-+ 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
-+gssEapMakeReauthCreds(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ gss_buffer_t credBuf);
-+
-+OM_uint32
-+gssEapStoreReauthCreds(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ gss_buffer_t credBuf);
-+
-+
-+OM_uint32
-+gssEapGlueToMechName(OM_uint32 *minor,
-+ gss_ctx_id_t glueContext,
-+ gss_name_t glueName,
-+ gss_name_t *pMechName);
-+
-+OM_uint32
-+gssEapMechToGlueName(OM_uint32 *minor,
-+ gss_name_t mechName,
-+ gss_name_t *pGlueName);
-+
-+OM_uint32
-+gssEapReauthComplete(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_cred_id_t cred,
-+ const gss_OID mech,
-+ OM_uint32 timeRec);
-+
-+OM_uint32
-+gssEapReauthInitialize(OM_uint32 *minor);
-+
-+int
-+gssEapCanReauthP(gss_cred_id_t cred,
-+ gss_name_t target,
-+ OM_uint32 timeReq);
-+
-+#endif /* _UTIL_REAUTH_H_ */
-diff --git a/mech_eap/util_saml.cpp b/mech_eap/util_saml.cpp
-new file mode 100644
-index 0000000..ce7582e
---- /dev/null
-+++ b/mech_eap/util_saml.cpp
-@@ -0,0 +1,775 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * SAML attribute provider implementation.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#include <sstream>
-+
-+#include <xercesc/util/XMLUniDefs.hpp>
-+#include <xmltooling/unicode.h>
-+#include <xmltooling/XMLToolingConfig.h>
-+#include <xmltooling/util/XMLHelper.h>
-+#include <xmltooling/util/ParserPool.h>
-+#include <xmltooling/util/DateTime.h>
-+
-+#include <saml/exceptions.h>
-+#include <saml/SAMLConfig.h>
-+#include <saml/saml1/core/Assertions.h>
-+#include <saml/saml2/core/Assertions.h>
-+#include <saml/saml2/metadata/Metadata.h>
-+#include <saml/saml2/metadata/MetadataProvider.h>
-+
-+using namespace xmltooling;
-+using namespace opensaml::saml2md;
-+using namespace opensaml;
-+using namespace xercesc;
-+using namespace std;
-+
-+static const XMLCh
-+base64Binary[] = {'b','a','s','e','6','4','B','i','n','a','r','y',0};
-+
-+/*
-+ * gss_eap_saml_assertion_provider is for retrieving the underlying
-+ * assertion.
-+ */
-+gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
-+{
-+ m_assertion = NULL;
-+ m_authenticated = false;
-+}
-+
-+gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
-+{
-+ delete m_assertion;
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
-+ const gss_eap_attr_provider *ctx)
-+{
-+ /* Then we may be creating from an existing attribute context */
-+ const gss_eap_saml_assertion_provider *saml;
-+
-+ GSSEAP_ASSERT(m_assertion == NULL);
-+
-+ if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
-+ return false;
-+
-+ saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
-+ setAssertion(saml->getAssertion(), saml->authenticated());
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
-+ const gss_cred_id_t gssCred,
-+ const gss_ctx_id_t gssCtx)
-+{
-+ const gss_eap_radius_attr_provider *radius;
-+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
-+ int authenticated, complete;
-+ OM_uint32 minor;
-+
-+ GSSEAP_ASSERT(m_assertion == NULL);
-+
-+ if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
-+ return false;
-+
-+ /*
-+ * XXX TODO we need to support draft-howlett-radius-saml-attr-00
-+ */
-+ radius = static_cast<const gss_eap_radius_attr_provider *>
-+ (m_manager->getProvider(ATTR_TYPE_RADIUS));
-+ if (radius != NULL &&
-+ radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
-+ VENDORPEC_UKERNA,
-+ &authenticated, &complete, &value)) {
-+ setAssertion(&value, authenticated);
-+ gss_release_buffer(&minor, &value);
-+ } else {
-+ m_assertion = NULL;
-+ }
-+
-+ return true;
-+}
-+
-+void
-+gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
-+ bool authenticated)
-+{
-+
-+ delete m_assertion;
-+
-+ if (assertion != NULL) {
-+#ifdef __APPLE__
-+ m_assertion = (saml2::Assertion *)((void *)assertion->clone());
-+#else
-+ m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
-+#endif
-+ m_authenticated = authenticated;
-+ } else {
-+ m_assertion = NULL;
-+ m_authenticated = false;
-+ }
-+}
-+
-+void
-+gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
-+ bool authenticated)
-+{
-+ delete m_assertion;
-+
-+ m_assertion = parseAssertion(buffer);
-+ m_authenticated = (m_assertion != NULL && authenticated);
-+}
-+
-+saml2::Assertion *
-+gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
-+{
-+ string str((char *)buffer->value, buffer->length);
-+ istringstream istream(str);
-+ DOMDocument *doc;
-+ const XMLObjectBuilder *b;
-+
-+ try {
-+ doc = XMLToolingConfig::getConfig().getParser().parse(istream);
-+ if (doc == NULL)
-+ return NULL;
-+
-+ b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
-+
-+#ifdef __APPLE__
-+ return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
-+#else
-+ return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
-+#endif
-+ } catch (exception &e) {
-+ return NULL;
-+ }
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
-+ void *data) const
-+{
-+ bool ret;
-+
-+ /* just add the prefix */
-+ if (m_assertion != NULL)
-+ ret = addAttribute(m_manager, this, GSS_C_NO_BUFFER, data);
-+ else
-+ ret = true;
-+
-+ return ret;
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::setAttribute(int complete GSSEAP_UNUSED,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value)
-+{
-+ if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
-+ setAssertion(value);
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
-+{
-+ delete m_assertion;
-+ m_assertion = NULL;
-+ m_authenticated = false;
-+
-+ return true;
-+}
-+
-+time_t
-+gss_eap_saml_assertion_provider::getExpiryTime(void) const
-+{
-+ saml2::Conditions *conditions;
-+ time_t expiryTime = 0;
-+
-+ if (m_assertion == NULL)
-+ return 0;
-+
-+ conditions = m_assertion->getConditions();
-+
-+ if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
-+ expiryTime = conditions->getNotOnOrAfter()->getEpoch();
-+
-+ return expiryTime;
-+}
-+
-+OM_uint32
-+gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor,
-+ std::exception &e) const
-+{
-+ if (typeid(e) == typeid(SecurityPolicyException))
-+ *minor = GSSEAP_SAML_SEC_POLICY_FAILURE;
-+ else if (typeid(e) == typeid(BindingException))
-+ *minor = GSSEAP_SAML_BINDING_FAILURE;
-+ else if (typeid(e) == typeid(ProfileException))
-+ *minor = GSSEAP_SAML_PROFILE_FAILURE;
-+ else if (typeid(e) == typeid(FatalProfileException))
-+ *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE;
-+ else if (typeid(e) == typeid(RetryableProfileException))
-+ *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE;
-+ else if (typeid(e) == typeid(MetadataException))
-+ *minor = GSSEAP_SAML_METADATA_FAILURE;
-+ else
-+ return GSS_S_CONTINUE_NEEDED;
-+
-+ gssEapSaveStatusInfo(*minor, "%s", e.what());
-+
-+ return GSS_S_FAILURE;
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value GSSEAP_UNUSED,
-+ int *more) const
-+{
-+ string str;
-+
-+ if (attr != GSS_C_NO_BUFFER && attr->length != 0)
-+ return false;
-+
-+ if (m_assertion == NULL)
-+ return false;
-+
-+ if (*more != -1)
-+ return false;
-+
-+ if (authenticated != NULL)
-+ *authenticated = m_authenticated;
-+ if (complete != NULL)
-+ *complete = true;
-+
-+ XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
-+
-+ if (value != NULL)
-+ duplicateBuffer(str, value);
-+ if (display_value != NULL)
-+ duplicateBuffer(str, display_value);
-+
-+ *more = 0;
-+
-+ return true;
-+}
-+
-+gss_any_t
-+gss_eap_saml_assertion_provider::mapToAny(int authenticated,
-+ gss_buffer_t type_id GSSEAP_UNUSED) const
-+{
-+ if (authenticated && !m_authenticated)
-+ return (gss_any_t)NULL;
-+
-+ return (gss_any_t)m_assertion;
-+}
-+
-+void
-+gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
-+ gss_any_t input) const
-+{
-+ delete ((saml2::Assertion *)input);
-+}
-+
-+const char *
-+gss_eap_saml_assertion_provider::prefix(void) const
-+{
-+ return "urn:ietf:params:gss-eap:saml-aaa-assertion";
-+}
-+
-+bool
-+gss_eap_saml_assertion_provider::init(void)
-+{
-+ bool ret = false;
-+
-+ try {
-+ ret = SAMLConfig::getConfig().init();
-+ } catch (exception &e) {
-+ }
-+
-+ if (ret)
-+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION, createAttrContext);
-+
-+ return ret;
-+}
-+
-+void
-+gss_eap_saml_assertion_provider::finalize(void)
-+{
-+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION);
-+}
-+
-+gss_eap_attr_provider *
-+gss_eap_saml_assertion_provider::createAttrContext(void)
-+{
-+ return new gss_eap_saml_assertion_provider;
-+}
-+
-+saml2::Assertion *
-+gss_eap_saml_assertion_provider::initAssertion(void)
-+{
-+ delete m_assertion;
-+ m_assertion = saml2::AssertionBuilder::buildAssertion();
-+ m_authenticated = false;
-+
-+ return m_assertion;
-+}
-+
-+/*
-+ * gss_eap_saml_attr_provider is for retrieving the underlying attributes.
-+ */
-+bool
-+gss_eap_saml_attr_provider::getAssertion(int *authenticated,
-+ saml2::Assertion **pAssertion,
-+ bool createIfAbsent) const
-+{
-+ gss_eap_saml_assertion_provider *saml;
-+
-+ if (authenticated != NULL)
-+ *authenticated = false;
-+ if (pAssertion != NULL)
-+ *pAssertion = NULL;
-+
-+ saml = static_cast<gss_eap_saml_assertion_provider *>
-+ (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
-+ if (saml == NULL)
-+ return false;
-+
-+ if (authenticated != NULL)
-+ *authenticated = saml->authenticated();
-+ if (pAssertion != NULL)
-+ *pAssertion = saml->getAssertion();
-+
-+ if (saml->getAssertion() == NULL) {
-+ if (createIfAbsent) {
-+ if (authenticated != NULL)
-+ *authenticated = false;
-+ if (pAssertion != NULL)
-+ *pAssertion = saml->initAssertion();
-+ } else
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
-+ void *data) const
-+{
-+ saml2::Assertion *assertion;
-+ int authenticated;
-+
-+ if (!getAssertion(&authenticated, &assertion))
-+ return true;
-+
-+ /*
-+ * Note: the first prefix is added by the attribute provider manager
-+ *
-+ * From draft-hartman-gss-eap-naming-00:
-+ *
-+ * Each attribute carried in the assertion SHOULD also be a GSS name
-+ * attribute. The name of this attribute has three parts, all separated
-+ * by an ASCII space character. The first part is
-+ * urn:ietf:params:gss-eap:saml-attr. The second part is the URI for
-+ * the SAML attribute name format. The final part is the name of the
-+ * SAML attribute. If the mechanism performs an additional attribute
-+ * query, the retrieved attributes SHOULD be GSS-API name attributes
-+ * using the same name syntax.
-+ */
-+ /* For each attribute statement, look for an attribute match */
-+ const vector <saml2::AttributeStatement *> &statements =
-+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
-+
-+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
-+ s != statements.end();
-+ ++s) {
-+ const vector<saml2::Attribute*> &attrs =
-+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
-+
-+ for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
-+ const XMLCh *attributeName, *attributeNameFormat;
-+ XMLCh space[2] = { ' ', 0 };
-+ gss_buffer_desc utf8;
-+
-+ attributeName = (*a)->getName();
-+ attributeNameFormat = (*a)->getNameFormat();
-+ if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
-+ attributeNameFormat = saml2::Attribute::UNSPECIFIED;
-+
-+ XMLCh qualifiedName[XMLString::stringLen(attributeNameFormat) + 1 +
-+ XMLString::stringLen(attributeName) + 1];
-+ XMLString::copyString(qualifiedName, attributeNameFormat);
-+ XMLString::catString(qualifiedName, space);
-+ XMLString::catString(qualifiedName, attributeName);
-+
-+ utf8.value = (void *)toUTF8(qualifiedName);
-+ utf8.length = strlen((char *)utf8.value);
-+
-+ if (!addAttribute(m_manager, this, &utf8, data))
-+ return false;
-+ }
-+ }
-+
-+ return true;
-+}
-+
-+static BaseRefVectorOf<XMLCh> *
-+decomposeAttributeName(const gss_buffer_t attr)
-+{
-+ BaseRefVectorOf<XMLCh> *components;
-+ string str((const char *)attr->value, attr->length);
-+ auto_ptr_XMLCh qualifiedAttr(str.c_str());
-+
-+ components = XMLString::tokenizeString(qualifiedAttr.get());
-+
-+ if (components->size() != 2) {
-+ delete components;
-+ components = NULL;
-+ }
-+
-+ return components;
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value)
-+{
-+ saml2::Assertion *assertion;
-+ saml2::Attribute *attribute;
-+ saml2::AttributeValue *attributeValue;
-+ saml2::AttributeStatement *attributeStatement;
-+
-+ if (!getAssertion(NULL, &assertion, true))
-+ return false;
-+
-+ if (assertion->getAttributeStatements().size() != 0) {
-+ attributeStatement = assertion->getAttributeStatements().front();
-+ } else {
-+ attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement();
-+ assertion->getAttributeStatements().push_back(attributeStatement);
-+ }
-+
-+ /* Check the attribute name consists of name format | whsp | name */
-+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
-+ if (components == NULL)
-+ return false;
-+
-+ attribute = saml2::AttributeBuilder::buildAttribute();
-+ attribute->setNameFormat(components->elementAt(0));
-+ attribute->setName(components->elementAt(1));
-+
-+ attributeValue = saml2::AttributeValueBuilder::buildAttributeValue();
-+ auto_ptr_XMLCh unistr((char *)value->value, value->length);
-+ attributeValue->setTextContent(unistr.get());
-+
-+ attribute->getAttributeValues().push_back(attributeValue);
-+
-+ GSSEAP_ASSERT(attributeStatement != NULL);
-+ attributeStatement->getAttributes().push_back(attribute);
-+
-+ delete components;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr)
-+{
-+ saml2::Assertion *assertion;
-+ bool ret = false;
-+
-+ if (!getAssertion(NULL, &assertion) ||
-+ assertion->getAttributeStatements().size() == 0)
-+ return false;
-+
-+ /* Check the attribute name consists of name format | whsp | name */
-+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
-+ if (components == NULL)
-+ return false;
-+
-+ /* For each attribute statement, look for an attribute match */
-+ const vector<saml2::AttributeStatement *> &statements =
-+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
-+
-+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
-+ s != statements.end();
-+ ++s) {
-+ const vector<saml2::Attribute *> &attrs =
-+ const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
-+ ssize_t index = -1, i = 0;
-+
-+ /* There's got to be an easier way to do this */
-+ for (vector<saml2::Attribute *>::const_iterator a = attrs.begin();
-+ a != attrs.end();
-+ ++a) {
-+ if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
-+ XMLString::equals((*a)->getName(), components->elementAt(1))) {
-+ index = i;
-+ break;
-+ }
-+ ++i;
-+ }
-+ if (index != -1) {
-+ (*s)->getAttributes().erase((*s)->getAttributes().begin() + index);
-+ ret = true;
-+ }
-+ }
-+
-+ delete components;
-+
-+ return ret;
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ const saml2::Attribute **pAttribute) const
-+{
-+ saml2::Assertion *assertion;
-+
-+ if (authenticated != NULL)
-+ *authenticated = false;
-+ if (complete != NULL)
-+ *complete = true;
-+ *pAttribute = NULL;
-+
-+ if (!getAssertion(authenticated, &assertion) ||
-+ assertion->getAttributeStatements().size() == 0)
-+ return false;
-+
-+ /* Check the attribute name consists of name format | whsp | name */
-+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
-+ if (components == NULL)
-+ return false;
-+
-+ /* For each attribute statement, look for an attribute match */
-+ const vector <saml2::AttributeStatement *> &statements =
-+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
-+ const saml2::Attribute *ret = NULL;
-+
-+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
-+ s != statements.end();
-+ ++s) {
-+ const vector<saml2::Attribute *> &attrs =
-+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
-+
-+ for (vector<saml2::Attribute *>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
-+ const XMLCh *attributeName, *attributeNameFormat;
-+
-+ attributeName = (*a)->getName();
-+ attributeNameFormat = (*a)->getNameFormat();
-+ if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
-+ attributeNameFormat = saml2::Attribute::UNSPECIFIED;
-+
-+ if (XMLString::equals(attributeNameFormat, components->elementAt(0)) &&
-+ XMLString::equals(attributeName, components->elementAt(1))) {
-+ ret = *a;
-+ break;
-+ }
-+ }
-+
-+ if (ret != NULL)
-+ break;
-+ }
-+
-+ delete components;
-+
-+ *pAttribute = ret;
-+
-+ return (ret != NULL);
-+}
-+
-+static bool
-+isBase64EncodedAttributeValueP(const saml2::AttributeValue *av)
-+{
-+ const xmltooling::QName *type = av->getSchemaType();
-+
-+ if (type == NULL)
-+ return false;
-+
-+ if (!type->hasNamespaceURI() ||
-+ !XMLString::equals(type->getNamespaceURI(), xmlconstants::XSD_NS))
-+ return false;
-+
-+ if (!type->hasLocalPart() ||
-+ !XMLString::equals(type->getLocalPart(), base64Binary))
-+ return false;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+ const saml2::Attribute *a;
-+ const saml2::AttributeValue *av;
-+ int nvalues, i = *more;
-+
-+ *more = 0;
-+
-+ if (!getAttribute(attr, authenticated, complete, &a))
-+ return false;
-+
-+ nvalues = a->getAttributeValues().size();
-+
-+ if (i == -1)
-+ i = 0;
-+ if (i >= nvalues)
-+ return false;
-+#ifdef __APPLE__
-+ av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
-+#else
-+ av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
-+#endif
-+ if (av != NULL) {
-+ bool base64Encoded = isBase64EncodedAttributeValueP(av);
-+
-+ if (value != NULL) {
-+ char *stringValue = toUTF8(av->getTextContent(), true);
-+ size_t stringValueLen = strlen(stringValue);
-+
-+ if (base64Encoded) {
-+ ssize_t octetLen;
-+
-+ value->value = GSSEAP_MALLOC(stringValueLen);
-+ if (value->value == NULL) {
-+ GSSEAP_FREE(stringValue);
-+ throw new std::bad_alloc;
-+ }
-+
-+ octetLen = base64Decode(stringValue, value->value);
-+ if (octetLen < 0) {
-+ GSSEAP_FREE(value->value);
-+ GSSEAP_FREE(stringValue);
-+ value->value = NULL;
-+ return false;
-+ }
-+ value->length = octetLen;
-+ GSSEAP_FREE(stringValue);
-+ } else {
-+ value->value = stringValue;
-+ value->length = stringValueLen;
-+ }
-+ }
-+ if (display_value != NULL && base64Encoded == false) {
-+ display_value->value = toUTF8(av->getTextContent(), true);
-+ display_value->length = strlen((char *)value->value);
-+ }
-+ }
-+
-+ if (nvalues > ++i)
-+ *more = i;
-+
-+ return true;
-+}
-+
-+gss_any_t
-+gss_eap_saml_attr_provider::mapToAny(int authenticated GSSEAP_UNUSED,
-+ gss_buffer_t type_id GSSEAP_UNUSED) const
-+{
-+ return (gss_any_t)NULL;
-+}
-+
-+void
-+gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
-+ gss_any_t input GSSEAP_UNUSED) const
-+{
-+}
-+
-+const char *
-+gss_eap_saml_attr_provider::prefix(void) const
-+{
-+ return "urn:ietf:params:gss-eap:saml-attr";
-+}
-+
-+bool
-+gss_eap_saml_attr_provider::init(void)
-+{
-+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML, createAttrContext);
-+ return true;
-+}
-+
-+void
-+gss_eap_saml_attr_provider::finalize(void)
-+{
-+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
-+}
-+
-+gss_eap_attr_provider *
-+gss_eap_saml_attr_provider::createAttrContext(void)
-+{
-+ return new gss_eap_saml_attr_provider;
-+}
-+
-+OM_uint32
-+gssEapSamlAttrProvidersInit(OM_uint32 *minor)
-+{
-+ if (!gss_eap_saml_assertion_provider::init() ||
-+ !gss_eap_saml_attr_provider::init()) {
-+ *minor = GSSEAP_SAML_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
-+{
-+ gss_eap_saml_attr_provider::finalize();
-+ gss_eap_saml_assertion_provider::finalize();
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/util_saml.h b/mech_eap/util_saml.h
-new file mode 100644
-index 0000000..9110ad4
---- /dev/null
-+++ b/mech_eap/util_saml.h
-@@ -0,0 +1,176 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * SAML attribute provider.
-+ */
-+
-+#ifndef _UTIL_SAML_H_
-+#define _UTIL_SAML_H_ 1
-+
-+#ifdef __cplusplus
-+
-+namespace opensaml {
-+ namespace saml2 {
-+ class Attribute;
-+ class Assertion;
-+ class NameID;
-+ };
-+};
-+
-+struct gss_eap_saml_assertion_provider : gss_eap_attr_provider {
-+public:
-+ gss_eap_saml_assertion_provider(void);
-+ ~gss_eap_saml_assertion_provider(void);
-+
-+ bool initWithExistingContext(const gss_eap_attr_ctx *source,
-+ const gss_eap_attr_provider *ctx);
-+ bool initWithGssContext(const gss_eap_attr_ctx *source,
-+ const gss_cred_id_t cred,
-+ const gss_ctx_id_t ctx);
-+
-+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
-+ bool setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(const gss_buffer_t value);
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ gss_any_t mapToAny(int authenticated,
-+ gss_buffer_t type_id) const;
-+ void releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const;
-+
-+ const char *prefix(void) const;
-+ const char *name(void) const { return NULL; }
-+ bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
-+ JSONObject &object GSSEAP_UNUSED) {
-+ return false;
-+ }
-+ JSONObject jsonRepresentation(void) const {
-+ return JSONObject::null();
-+ }
-+
-+ opensaml::saml2::Assertion *initAssertion(void);
-+
-+ opensaml::saml2::Assertion *getAssertion(void) const {
-+ return m_assertion;
-+ }
-+ bool authenticated(void) const {
-+ return m_authenticated;
-+ }
-+
-+ time_t getExpiryTime(void) const;
-+ OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
-+
-+ static bool init(void);
-+ static void finalize(void);
-+
-+ static gss_eap_attr_provider *createAttrContext(void);
-+
-+private:
-+ static opensaml::saml2::Assertion *
-+ parseAssertion(const gss_buffer_t buffer);
-+
-+ void setAssertion(const opensaml::saml2::Assertion *assertion,
-+ bool authenticated = false);
-+ void setAssertion(const gss_buffer_t buffer,
-+ bool authenticated = false);
-+
-+ opensaml::saml2::Assertion *m_assertion;
-+ bool m_authenticated;
-+};
-+
-+struct gss_eap_saml_attr_provider : gss_eap_attr_provider {
-+public:
-+ gss_eap_saml_attr_provider(void) {}
-+ ~gss_eap_saml_attr_provider(void) {}
-+
-+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
-+ bool setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(const gss_buffer_t value);
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ gss_any_t mapToAny(int authenticated,
-+ gss_buffer_t type_id) const;
-+ void releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const;
-+
-+ const char *prefix(void) const;
-+ const char *name(void) const {
-+ return NULL;
-+ }
-+ bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
-+ JSONObject &object GSSEAP_UNUSED) {
-+ return false;
-+ }
-+ JSONObject jsonRepresentation(void) const {
-+ return JSONObject::null();
-+ }
-+
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ const opensaml::saml2::Attribute **pAttribute) const;
-+ bool getAssertion(int *authenticated,
-+ opensaml::saml2::Assertion **pAssertion,
-+ bool createIfAbsent = false) const;
-+
-+ static bool init(void);
-+ static void finalize(void);
-+
-+ static gss_eap_attr_provider *createAttrContext(void);
-+
-+private:
-+};
-+
-+extern "C" {
-+#endif
-+
-+OM_uint32 gssEapSamlAttrProvidersInit(OM_uint32 *minor);
-+OM_uint32 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _UTIL_SAML_H_ */
-diff --git a/mech_eap/util_shib.cpp b/mech_eap/util_shib.cpp
-new file mode 100644
-index 0000000..f8c702b
---- /dev/null
-+++ b/mech_eap/util_shib.cpp
-@@ -0,0 +1,555 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * Copyright 2001-2009 Internet2
-+ *
-+ * Licensed under the Apache License, Version 2.0 (the "License");
-+ * you may not use this file except in compliance with the License.
-+ * You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+
-+/*
-+ * Local attribute provider implementation.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#include <xmltooling/XMLObject.h>
-+#ifndef HAVE_OPENSAML
-+#include <xmltooling/XMLToolingConfig.h>
-+#include <xmltooling/util/ParserPool.h>
-+#endif
-+
-+#include <saml/saml2/core/Assertions.h>
-+
-+#include <shibsp/exceptions.h>
-+#include <shibsp/attribute/SimpleAttribute.h>
-+#include <shibsp/attribute/BinaryAttribute.h>
-+#include <shibsp/attribute/ScopedAttribute.h>
-+#include <shibresolver/resolver.h>
-+
-+#include <sstream>
-+
-+using namespace shibsp;
-+using namespace shibresolver;
-+using namespace xmltooling;
-+using namespace std;
-+#ifdef HAVE_OPENSAML
-+using namespace opensaml::saml2md;
-+using namespace opensaml;
-+#else
-+using namespace xercesc;
-+#endif
-+
-+gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
-+{
-+ m_initialized = false;
-+ m_authenticated = false;
-+}
-+
-+gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void)
-+{
-+ for_each(m_attributes.begin(),
-+ m_attributes.end(),
-+ xmltooling::cleanup<Attribute>())
-+ ;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
-+ const gss_eap_attr_provider *ctx)
-+{
-+ const gss_eap_shib_attr_provider *shib;
-+
-+ if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) {
-+ return false;
-+ }
-+
-+ m_authenticated = false;
-+
-+ shib = static_cast<const gss_eap_shib_attr_provider *>(ctx);
-+ if (shib != NULL) {
-+ m_attributes = duplicateAttributes(shib->getAttributes());
-+ m_authenticated = shib->authenticated();
-+ }
-+
-+ m_initialized = true;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
-+ const gss_cred_id_t gssCred,
-+ const gss_ctx_id_t gssCtx)
-+{
-+ if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
-+ return false;
-+
-+ auto_ptr<ShibbolethResolver> resolver(ShibbolethResolver::create());
-+
-+ /*
-+ * For now, leave ApplicationID defaulted.
-+ * Later on, we could allow this via config option to the mechanism
-+ * or rely on an SPRequest interface to pass in a URI identifying the
-+ * acceptor.
-+ */
-+#if 0
-+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-+ if (gssCred != GSS_C_NO_CREDENTIAL &&
-+ gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) {
-+ resolver->setApplicationID((const char *)nameBuf.value);
-+ gss_release_buffer(&minor, &nameBuf);
-+ }
-+#endif
-+
-+ gss_buffer_desc mechName = GSS_C_EMPTY_BUFFER;
-+ OM_uint32 major, minor;
-+
-+ major = gssEapExportNameInternal(&minor, gssCtx->initiatorName, &mechName,
-+ EXPORT_NAME_FLAG_OID |
-+ EXPORT_NAME_FLAG_COMPOSITE);
-+ if (major == GSS_S_COMPLETE) {
-+ resolver->addToken(&mechName);
-+ gss_release_buffer(&minor, &mechName);
-+ }
-+
-+#ifdef HAVE_OPENSAML
-+ const gss_eap_saml_assertion_provider *saml;
-+ saml = static_cast<const gss_eap_saml_assertion_provider *>
-+ (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
-+ if (saml != NULL && saml->getAssertion() != NULL) {
-+ resolver->addToken(saml->getAssertion());
-+ }
-+#else
-+ /* If no OpenSAML, parse the XML assertion explicitly */
-+ const gss_eap_radius_attr_provider *radius;
-+ int authenticated, complete;
-+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
-+
-+ radius = static_cast<const gss_eap_radius_attr_provider *>
-+ (m_manager->getProvider(ATTR_TYPE_RADIUS));
-+ if (radius != NULL &&
-+ radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
-+ VENDORPEC_UKERNA,
-+ &authenticated, &complete, &value)) {
-+ string str((char *)value.value, value.length);
-+ istringstream istream(str);
-+ DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream);
-+ const XMLObjectBuilder *b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
-+ resolver->addToken(b->buildFromDocument(doc));
-+ gss_release_buffer(&minor, &value);
-+ }
-+#endif /* HAVE_OPENSAML */
-+
-+ try {
-+ resolver->resolve();
-+ m_attributes = resolver->getResolvedAttributes();
-+ resolver->getResolvedAttributes().clear();
-+ } catch (exception &e) {
-+ return false;
-+ }
-+
-+ m_authenticated = true;
-+ m_initialized = true;
-+
-+ return true;
-+}
-+
-+ssize_t
-+gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const
-+{
-+ int i = 0;
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ for (vector<Attribute *>::const_iterator a = m_attributes.begin();
-+ a != m_attributes.end();
-+ ++a)
-+ {
-+ for (vector<string>::const_iterator s = (*a)->getAliases().begin();
-+ s != (*a)->getAliases().end();
-+ ++s) {
-+ if (attr->length == (*s).length() &&
-+ memcmp((*s).c_str(), attr->value, attr->length) == 0) {
-+ return i;
-+ }
-+ }
-+ }
-+
-+ return -1;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value)
-+{
-+ string attrStr((char *)attr->value, attr->length);
-+ vector <string> ids(1, attrStr);
-+ BinaryAttribute *a = new BinaryAttribute(ids);
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ if (value->length != 0) {
-+ string valueStr((char *)value->value, value->length);
-+
-+ a->getValues().push_back(valueStr);
-+ }
-+
-+ m_attributes.push_back(a);
-+ m_authenticated = false;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr)
-+{
-+ int i;
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ i = getAttributeIndex(attr);
-+ if (i >= 0)
-+ m_attributes.erase(m_attributes.begin() + i);
-+
-+ m_authenticated = false;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
-+ void *data) const
-+{
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ for (vector<Attribute*>::const_iterator a = m_attributes.begin();
-+ a != m_attributes.end();
-+ ++a)
-+ {
-+ gss_buffer_desc attribute;
-+
-+ attribute.value = (void *)((*a)->getId());
-+ attribute.length = strlen((char *)attribute.value);
-+
-+ if (!addAttribute(m_manager, this, &attribute, data))
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+const Attribute *
-+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
-+{
-+ const Attribute *ret = NULL;
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ for (vector<Attribute *>::const_iterator a = m_attributes.begin();
-+ a != m_attributes.end();
-+ ++a)
-+ {
-+ for (vector<string>::const_iterator s = (*a)->getAliases().begin();
-+ s != (*a)->getAliases().end();
-+ ++s) {
-+ if (attr->length == (*s).length() &&
-+ memcmp((*s).c_str(), attr->value, attr->length) == 0) {
-+ ret = *a;
-+ break;
-+ }
-+ }
-+ if (ret != NULL)
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const
-+{
-+ const Attribute *shibAttr = NULL;
-+ const BinaryAttribute *binaryAttr;
-+ gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc displayValueBuf = GSS_C_EMPTY_BUFFER;
-+ int nvalues, i = *more;
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ *more = 0;
-+
-+ shibAttr = getAttribute(attr);
-+ if (shibAttr == NULL)
-+ return false;
-+
-+ nvalues = shibAttr->valueCount();
-+
-+ if (i == -1)
-+ i = 0;
-+ if (i >= nvalues)
-+ return false;
-+
-+ binaryAttr = dynamic_cast<const BinaryAttribute *>(shibAttr);
-+ if (binaryAttr != NULL) {
-+ std::string str = binaryAttr->getValues()[*more];
-+
-+ valueBuf.value = (void *)str.data();
-+ valueBuf.length = str.size();
-+ } else {
-+ std::string str = shibAttr->getSerializedValues()[*more];
-+
-+ valueBuf.value = (void *)str.c_str();
-+ valueBuf.length = str.length();
-+
-+ const SimpleAttribute *simpleAttr =
-+ dynamic_cast<const SimpleAttribute *>(shibAttr);
-+ const ScopedAttribute *scopedAttr =
-+ dynamic_cast<const ScopedAttribute *>(shibAttr);
-+ if (simpleAttr != NULL || scopedAttr != NULL)
-+ displayValueBuf = valueBuf;
-+ }
-+
-+ if (authenticated != NULL)
-+ *authenticated = m_authenticated;
-+ if (complete != NULL)
-+ *complete = true;
-+ if (value != NULL)
-+ duplicateBuffer(valueBuf, value);
-+ if (display_value != NULL)
-+ duplicateBuffer(displayValueBuf, display_value);
-+ if (nvalues > ++i)
-+ *more = i;
-+
-+ return true;
-+}
-+
-+gss_any_t
-+gss_eap_shib_attr_provider::mapToAny(int authenticated,
-+ gss_buffer_t type_id GSSEAP_UNUSED) const
-+{
-+ gss_any_t output;
-+
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ if (authenticated && !m_authenticated)
-+ return (gss_any_t)NULL;
-+
-+ vector <Attribute *>v = duplicateAttributes(m_attributes);
-+
-+ output = (gss_any_t)new vector <Attribute *>(v);
-+
-+ return output;
-+}
-+
-+void
-+gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
-+ gss_any_t input) const
-+{
-+ GSSEAP_ASSERT(m_initialized);
-+
-+ vector <Attribute *> *v = ((vector <Attribute *> *)input);
-+ delete v;
-+}
-+
-+const char *
-+gss_eap_shib_attr_provider::prefix(void) const
-+{
-+ return NULL;
-+}
-+
-+const char *
-+gss_eap_shib_attr_provider::name(void) const
-+{
-+ return "local";
-+}
-+
-+JSONObject
-+gss_eap_shib_attr_provider::jsonRepresentation(void) const
-+{
-+ JSONObject obj;
-+
-+ if (m_initialized == false)
-+ return obj; /* don't export incomplete context */
-+
-+ JSONObject jattrs = JSONObject::array();
-+
-+ for (vector<Attribute*>::const_iterator a = m_attributes.begin();
-+ a != m_attributes.end(); ++a) {
-+ DDF attr = (*a)->marshall();
-+ JSONObject jattr = JSONObject::ddf(attr);
-+ jattrs.append(jattr);
-+ }
-+
-+ obj.set("attributes", jattrs);
-+
-+ obj.set("authenticated", m_authenticated);
-+
-+ return obj;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
-+ JSONObject &obj)
-+{
-+ if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
-+ return false;
-+
-+ GSSEAP_ASSERT(m_authenticated == false);
-+ GSSEAP_ASSERT(m_attributes.size() == 0);
-+
-+ JSONObject jattrs = obj["attributes"];
-+ size_t nelems = jattrs.size();
-+
-+ for (size_t i = 0; i < nelems; i++) {
-+ JSONObject jattr = jattrs.get(i);
-+
-+ DDF attr = jattr.ddf();
-+ Attribute *attribute = Attribute::unmarshall(attr);
-+ m_attributes.push_back(attribute);
-+ }
-+
-+ m_authenticated = obj["authenticated"].integer();
-+ m_initialized = true;
-+
-+ return true;
-+}
-+
-+bool
-+gss_eap_shib_attr_provider::init(void)
-+{
-+ bool ret = false;
-+
-+ try {
-+ ret = ShibbolethResolver::init();
-+ } catch (exception &e) {
-+ }
-+
-+ if (ret)
-+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
-+
-+ return ret;
-+}
-+
-+void
-+gss_eap_shib_attr_provider::finalize(void)
-+{
-+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
-+ ShibbolethResolver::term();
-+}
-+
-+OM_uint32
-+gss_eap_shib_attr_provider::mapException(OM_uint32 *minor,
-+ std::exception &e) const
-+{
-+ if (typeid(e) == typeid(AttributeException))
-+ *minor = GSSEAP_SHIB_ATTR_FAILURE;
-+ else if (typeid(e) == typeid(AttributeExtractionException))
-+ *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE;
-+ else if (typeid(e) == typeid(AttributeFilteringException))
-+ *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE;
-+ else if (typeid(e) == typeid(AttributeResolutionException))
-+ *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE;
-+ else if (typeid(e) == typeid(ConfigurationException))
-+ *minor = GSSEAP_SHIB_CONFIG_FAILURE;
-+ else if (typeid(e) == typeid(ListenerException))
-+ *minor = GSSEAP_SHIB_LISTENER_FAILURE;
-+ else
-+ return GSS_S_CONTINUE_NEEDED;
-+
-+ gssEapSaveStatusInfo(*minor, "%s", e.what());
-+
-+ return GSS_S_FAILURE;
-+}
-+
-+gss_eap_attr_provider *
-+gss_eap_shib_attr_provider::createAttrContext(void)
-+{
-+ return new gss_eap_shib_attr_provider;
-+}
-+
-+Attribute *
-+gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src)
-+{
-+ DDF obj = src->marshall();
-+ Attribute *attribute = Attribute::unmarshall(obj);
-+ obj.destroy();
-+
-+ return attribute;
-+}
-+
-+vector <Attribute *>
-+gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
-+{
-+ vector <Attribute *> dst;
-+
-+ for (vector<Attribute *>::const_iterator a = src.begin();
-+ a != src.end();
-+ ++a)
-+ dst.push_back(duplicateAttribute(*a));
-+
-+ return dst;
-+}
-+
-+OM_uint32
-+gssEapLocalAttrProviderInit(OM_uint32 *minor)
-+{
-+ if (!gss_eap_shib_attr_provider::init()) {
-+ *minor = GSSEAP_SHIB_INIT_FAILURE;
-+ return GSS_S_FAILURE;
-+ }
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
-+{
-+ gss_eap_shib_attr_provider::finalize();
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/util_shib.h b/mech_eap/util_shib.h
-new file mode 100644
-index 0000000..4cf7481
---- /dev/null
-+++ b/mech_eap/util_shib.h
-@@ -0,0 +1,122 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Local attribute provider.
-+ */
-+
-+#ifndef _UTIL_SHIB_H_
-+#define _UTIL_SHIB_H_ 1
-+
-+#ifdef __cplusplus
-+
-+#include <vector>
-+
-+namespace shibsp {
-+ class Attribute;
-+};
-+
-+namespace shibresolver {
-+ class ShibbolethResolver;
-+};
-+
-+struct gss_eap_shib_attr_provider : gss_eap_attr_provider {
-+public:
-+ gss_eap_shib_attr_provider(void);
-+ ~gss_eap_shib_attr_provider(void);
-+
-+ bool initWithExistingContext(const gss_eap_attr_ctx *source,
-+ const gss_eap_attr_provider *ctx);
-+ bool initWithGssContext(const gss_eap_attr_ctx *source,
-+ const gss_cred_id_t cred,
-+ const gss_ctx_id_t ctx);
-+
-+ bool setAttribute(int complete,
-+ const gss_buffer_t attr,
-+ const gss_buffer_t value);
-+ bool deleteAttribute(const gss_buffer_t value);
-+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
-+ bool getAttribute(const gss_buffer_t attr,
-+ int *authenticated,
-+ int *complete,
-+ gss_buffer_t value,
-+ gss_buffer_t display_value,
-+ int *more) const;
-+ gss_any_t mapToAny(int authenticated,
-+ gss_buffer_t type_id) const;
-+ void releaseAnyNameMapping(gss_buffer_t type_id,
-+ gss_any_t input) const;
-+
-+ const char *prefix(void) const;
-+ const char *name(void) const;
-+ bool initWithJsonObject(const gss_eap_attr_ctx *manager,
-+ JSONObject &obj);
-+ JSONObject jsonRepresentation(void) const;
-+
-+ static bool init(void);
-+ static void finalize(void);
-+
-+ OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
-+
-+ static gss_eap_attr_provider *createAttrContext(void);
-+
-+ std::vector<shibsp::Attribute *> getAttributes(void) const {
-+ return m_attributes;
-+ }
-+
-+private:
-+ static shibsp::Attribute *
-+ duplicateAttribute(const shibsp::Attribute *src);
-+ static std::vector <shibsp::Attribute *>
-+ duplicateAttributes(const std::vector <shibsp::Attribute *>src);
-+
-+ ssize_t getAttributeIndex(const gss_buffer_t attr) const;
-+ const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const;
-+
-+ bool authenticated(void) const { return m_authenticated; }
-+
-+ bool m_initialized;
-+ bool m_authenticated;
-+ std::vector<shibsp::Attribute *> m_attributes;
-+};
-+
-+extern "C" {
-+#endif
-+
-+OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
-+OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _UTIL_SHIB_H_ */
-diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c
-new file mode 100644
-index 0000000..56248d8
---- /dev/null
-+++ b/mech_eap/util_sm.c
-@@ -0,0 +1,372 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Context establishment state machine.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/* private flags */
-+#define SM_FLAG_TRANSITED 0x80000000
-+
-+#define SM_ASSERT_VALID(ctx, status) do { \
-+ GSSEAP_ASSERT(GSS_ERROR((status)) || \
-+ ((status) == GSS_S_CONTINUE_NEEDED && ((ctx)->state > GSSEAP_STATE_INITIAL && (ctx)->state < GSSEAP_STATE_ESTABLISHED)) || \
-+ ((status) == GSS_S_COMPLETE && (ctx)->state == GSSEAP_STATE_ESTABLISHED)); \
-+ } while (0)
-+
-+#ifdef GSSEAP_DEBUG
-+static const char *
-+gssEapStateToString(enum gss_eap_state state)
-+{
-+ const char *s;
-+
-+ switch (state) {
-+ case GSSEAP_STATE_INITIAL:
-+ s = "INITIAL";
-+ break;
-+ case GSSEAP_STATE_AUTHENTICATE:
-+ s = "AUTHENTICATE";
-+ break;
-+ case GSSEAP_STATE_INITIATOR_EXTS:
-+ s = "INITIATOR_EXTS";
-+ break;
-+ case GSSEAP_STATE_ACCEPTOR_EXTS:
-+ s = "ACCEPTOR_EXTS";
-+ break;
-+#ifdef GSSEAP_ENABLE_REAUTH
-+ case GSSEAP_STATE_REAUTHENTICATE:
-+ s = "REAUTHENTICATE";
-+ break;
-+#endif
-+ case GSSEAP_STATE_ESTABLISHED:
-+ s = "ESTABLISHED";
-+ break;
-+ default:
-+ s = "INVALID";
-+ break;
-+ }
-+
-+ return s;
-+}
-+
-+void
-+gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state)
-+{
-+ GSSEAP_ASSERT(state >= GSSEAP_STATE_INITIAL);
-+ GSSEAP_ASSERT(state <= GSSEAP_STATE_ESTABLISHED);
-+
-+ fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
-+ gssEapStateToString(GSSEAP_SM_STATE(ctx)),
-+ gssEapStateToString(state));
-+
-+ ctx->state = state;
-+}
-+#endif /* GSSEAP_DEBUG */
-+
-+static OM_uint32
-+makeErrorToken(OM_uint32 *minor,
-+ OM_uint32 majorStatus,
-+ OM_uint32 minorStatus,
-+ struct gss_eap_token_buffer_set *token)
-+{
-+ OM_uint32 major, tmpMinor;
-+ unsigned char errorData[8];
-+ gss_buffer_desc errorBuffer;
-+
-+ GSSEAP_ASSERT(GSS_ERROR(majorStatus));
-+
-+ /*
-+ * Only return error codes that the initiator could have caused,
-+ * to avoid information leakage.
-+ */
-+ if (IS_RADIUS_ERROR(minorStatus)) {
-+ /* Squash RADIUS error codes */
-+ minorStatus = GSSEAP_RADIUS_PROT_FAILURE;
-+ } else if (!IS_WIRE_ERROR(minorStatus)) {
-+ /* Don't return non-wire error codes */
-+ return GSS_S_COMPLETE;
-+ }
-+
-+ minorStatus -= ERROR_TABLE_BASE_eapg;
-+
-+ store_uint32_be(majorStatus, &errorData[0]);
-+ store_uint32_be(minorStatus, &errorData[4]);
-+
-+ major = gssEapAllocInnerTokens(&tmpMinor, 1, token);
-+ if (GSS_ERROR(major)) {
-+ *minor = tmpMinor;
-+ return major;
-+ }
-+
-+ errorBuffer.length = sizeof(errorData);
-+ errorBuffer.value = errorData;
-+
-+ major = duplicateBuffer(&tmpMinor, &errorBuffer, &token->buffers.elements[0]);
-+ if (GSS_ERROR(major)) {
-+ gssEapReleaseInnerTokens(&tmpMinor, token, 1);
-+ *minor = tmpMinor;
-+ return major;
-+ }
-+
-+ token->buffers.count = 1;
-+ token->types[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapSmStep(OM_uint32 *minor,
-+ gss_cred_id_t cred,
-+ gss_ctx_id_t ctx,
-+ gss_name_t target,
-+ gss_OID mech,
-+ OM_uint32 reqFlags,
-+ OM_uint32 timeReq,
-+ gss_channel_bindings_t chanBindings,
-+ gss_buffer_t inputToken,
-+ gss_buffer_t outputToken,
-+ struct gss_eap_sm *sm, /* ordered by state */
-+ size_t smCount)
-+{
-+ OM_uint32 major, tmpMajor, tmpMinor;
-+ struct gss_eap_token_buffer_set inputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
-+ struct gss_eap_token_buffer_set outputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
-+ gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER;
-+ gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER;
-+ unsigned int smFlags = 0;
-+ size_t i, j;
-+ int initialContextToken = 0;
-+ enum gss_eap_token_type tokType;
-+
-+ GSSEAP_ASSERT(smCount > 0);
-+
-+ *minor = 0;
-+
-+ outputToken->length = 0;
-+ outputToken->value = NULL;
-+
-+ if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
-+ major = gssEapVerifyToken(minor, ctx, inputToken, &tokType,
-+ &unwrappedInputToken);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ if (tokType != (CTX_IS_INITIATOR(ctx)
-+ ? TOK_TYPE_ACCEPTOR_CONTEXT : TOK_TYPE_INITIATOR_CONTEXT)) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_WRONG_TOK_ID;
-+ goto cleanup;
-+ }
-+ } else if (!CTX_IS_INITIATOR(ctx) || ctx->state != GSSEAP_STATE_INITIAL) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_WRONG_SIZE;
-+ goto cleanup;
-+ } else {
-+ initialContextToken = 1;
-+ }
-+
-+ if (CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_BAD_STATUS;
-+ *minor = GSSEAP_CONTEXT_ESTABLISHED;
-+ goto cleanup;
-+ }
-+
-+ GSSEAP_ASSERT(ctx->state < GSSEAP_STATE_ESTABLISHED);
-+
-+ major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, &inputTokens);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ major = gssEapAllocInnerTokens(minor, smCount, &outputTokens);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ ctx->inputTokens = &inputTokens;
-+ ctx->outputTokens = &outputTokens;
-+
-+ /* Process all the tokens that are valid for the current state. */
-+ for (i = 0; i < smCount; i++) {
-+ struct gss_eap_sm *smp = &sm[i];
-+ int processToken = 0;
-+ gss_buffer_t innerInputToken = GSS_C_NO_BUFFER;
-+ OM_uint32 *inputTokenType = NULL;
-+ gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
-+
-+ if ((smp->validStates & ctx->state) == 0)
-+ continue;
-+
-+ /*
-+ * We special case the first call to gss_init_sec_context so that
-+ * all token providers have the opportunity to generate an initial
-+ * context token. Providers where inputTokenType is ITOK_TYPE_NONE
-+ * are always called and generally act on state transition boundaries,
-+ * for example to advance the state after a series of optional tokens
-+ * (as is the case with the extension token exchange) or to generate
-+ * a new token after the state was advanced by a provider which did
-+ * not emit a token.
-+ */
-+ if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
-+ processToken = 1;
-+ } else if ((smFlags & SM_FLAG_TRANSITED) == 0) {
-+ /* Don't regurgitate a token which belonds to a previous state. */
-+ for (j = 0; j < inputTokens.buffers.count; j++) {
-+ if ((inputTokens.types[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
-+ if (processToken) {
-+ /* Check for duplicate inner tokens */
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_DUPLICATE_ITOK;
-+ break;
-+ }
-+ processToken = 1;
-+ innerInputToken = &inputTokens.buffers.elements[j];
-+ inputTokenType = &inputTokens.types[j];
-+ }
-+ }
-+ if (GSS_ERROR(major))
-+ break;
-+ }
-+
-+ if (processToken) {
-+ enum gss_eap_state oldState = ctx->state;
-+
-+ smFlags = 0;
-+ if (inputTokenType != NULL && (*inputTokenType & ITOK_FLAG_CRITICAL))
-+ smFlags |= SM_FLAG_INPUT_TOKEN_CRITICAL;
-+
-+ major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
-+ timeReq, chanBindings, innerInputToken,
-+ &innerOutputToken, &smFlags);
-+ if (GSS_ERROR(major))
-+ break;
-+
-+ if (inputTokenType != NULL)
-+ *inputTokenType |= ITOK_FLAG_VERIFIED;
-+ if (ctx->state < oldState)
-+ i = 0; /* restart */
-+ else if (ctx->state != oldState)
-+ smFlags |= SM_FLAG_TRANSITED;
-+
-+ if (innerOutputToken.value != NULL) {
-+ outputTokens.buffers.elements[outputTokens.buffers.count] = innerOutputToken;
-+ GSSEAP_ASSERT(smp->outputTokenType != ITOK_TYPE_NONE);
-+ outputTokens.types[outputTokens.buffers.count] = smp->outputTokenType;
-+ if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL)
-+ outputTokens.types[outputTokens.buffers.count] |= ITOK_FLAG_CRITICAL;
-+ outputTokens.buffers.count++;
-+ }
-+ /*
-+ * Break out if we made a state transition and have some tokens to send.
-+ */
-+ if ((smFlags & SM_FLAG_TRANSITED) &&
-+ ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || outputTokens.buffers.count != 0)) {
-+ SM_ASSERT_VALID(ctx, major);
-+ break;
-+ }
-+ } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
-+ smp->inputTokenType != ITOK_TYPE_NONE) {
-+ /* Check for required inner tokens */
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_MISSING_REQUIRED_ITOK;
-+ break;
-+ }
-+ }
-+
-+ GSSEAP_ASSERT(outputTokens.buffers.count <= smCount);
-+
-+ /* Check we understood all critical tokens sent by peer */
-+ if (!GSS_ERROR(major)) {
-+ for (j = 0; j < inputTokens.buffers.count; j++) {
-+ if ((inputTokens.types[j] & ITOK_FLAG_CRITICAL) &&
-+ (inputTokens.types[j] & ITOK_FLAG_VERIFIED) == 0) {
-+ major = GSS_S_UNAVAILABLE;
-+ *minor = GSSEAP_CRIT_ITOK_UNAVAILABLE;
-+ goto cleanup;
-+ }
-+ }
-+ }
-+
-+ /* Optionaly emit an error token if we are the acceptor */
-+ if (GSS_ERROR(major)) {
-+ if (CTX_IS_INITIATOR(ctx))
-+ goto cleanup; /* return error directly to caller */
-+
-+ /* replace any emitted tokens with error token */
-+ gssEapReleaseInnerTokens(&tmpMinor, &outputTokens, 1);
-+
-+ tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &outputTokens);
-+ if (GSS_ERROR(tmpMajor)) {
-+ major = tmpMajor;
-+ *minor = tmpMinor;
-+ goto cleanup;
-+ }
-+ }
-+
-+ /* Format output token from inner tokens */
-+ if (outputTokens.buffers.count != 0 || /* inner tokens to send */
-+ !CTX_IS_INITIATOR(ctx) || /* any leg acceptor */
-+ !CTX_IS_ESTABLISHED(ctx)) { /* non-last leg initiator */
-+ tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, &outputTokens, &unwrappedOutputToken);
-+ if (tmpMajor == GSS_S_COMPLETE) {
-+ if (CTX_IS_INITIATOR(ctx))
-+ tokType = TOK_TYPE_INITIATOR_CONTEXT;
-+ else
-+ tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
-+
-+ tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &unwrappedOutputToken,
-+ tokType, outputToken);
-+ if (GSS_ERROR(tmpMajor)) {
-+ major = tmpMajor;
-+ *minor = tmpMinor;
-+ goto cleanup;
-+ }
-+ }
-+ }
-+
-+ /* If the context is established, empty tokens only to be emitted by initiator */
-+ GSSEAP_ASSERT(!CTX_IS_ESTABLISHED(ctx) || ((outputToken->length == 0) == CTX_IS_INITIATOR(ctx)));
-+
-+ SM_ASSERT_VALID(ctx, major);
-+
-+cleanup:
-+ gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 0);
-+ gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 1);
-+
-+ gss_release_buffer(&tmpMinor, &unwrappedOutputToken);
-+
-+ ctx->inputTokens = NULL;
-+ ctx->outputTokens = NULL;
-+
-+ return major;
-+}
-diff --git a/mech_eap/util_tld.c b/mech_eap/util_tld.c
-new file mode 100644
-index 0000000..05bc3d1
---- /dev/null
-+++ b/mech_eap/util_tld.c
-@@ -0,0 +1,167 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Thread local data abstraction, using pthreads on Unix and the TlsXXX
-+ * APIs on Windows.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+/* Clean up thread-local data; called on thread detach */
-+static void
-+destroyThreadLocalData(struct gss_eap_thread_local_data *tld)
-+{
-+ if (tld->statusInfo != NULL)
-+ gssEapDestroyStatusInfo(tld->statusInfo);
-+ if (tld->krbContext != NULL)
-+ gssEapDestroyKrbContext(tld->krbContext);
-+ GSSEAP_FREE(tld);
-+}
-+
-+#ifdef WIN32
-+
-+/*
-+ * This is the TLS index returned by TlsAlloc() on process init.
-+ * Each thread, on thread attach in DllMain(), allocates its thread-local
-+ * data and uses this index with TlsSetValue() to store it.
-+ * It can then subsequently be retrieved with TlsGetValue().
-+ */
-+static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
-+
-+/* Access thread-local data */
-+struct gss_eap_thread_local_data *
-+gssEapGetThreadLocalData(void)
-+{
-+ struct gss_eap_thread_local_data *tlsData;
-+
-+ GSSEAP_ASSERT(tlsIndex != TLS_OUT_OF_INDEXES);
-+
-+ tlsData = TlsGetValue(tlsIndex);
-+ if (tlsData == NULL) {
-+ tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
-+ TlsSetValue(tlsIndex, tlsData);
-+ }
-+
-+ return tlsData;
-+}
-+
-+BOOL WINAPI
-+DllMain(HINSTANCE hDLL, /* DLL module handle */
-+ DWORD reason, /* reason called */
-+ LPVOID reserved) /* reserved */
-+{
-+ struct gss_eap_thread_local_data *tlsData;
-+ OM_uint32 major, minor;
-+
-+ switch (reason) {
-+ case DLL_PROCESS_ATTACH:
-+ /* Allocate a TLS index. */
-+ major = gssEapInitiatorInit(&minor);
-+ if (GSS_ERROR(major))
-+ return FALSE;
-+
-+ tlsIndex = TlsAlloc();
-+ if (tlsIndex == TLS_OUT_OF_INDEXES)
-+ return FALSE;
-+ /* No break: Initialize the index for first thread.*/
-+ case DLL_THREAD_ATTACH:
-+ /* Initialize the TLS index for this thread. */
-+ tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
-+ if (tlsData == NULL)
-+ return FALSE;
-+ TlsSetValue(tlsIndex, tlsData);
-+ break;
-+ case DLL_THREAD_DETACH:
-+ /* Release the allocated memory for this thread. */
-+ tlsData = TlsGetValue(tlsIndex);
-+ if (tlsData != NULL) {
-+ destroyThreadLocalData(tlsData);
-+ TlsSetValue(tlsIndex, NULL);
-+ }
-+ break;
-+ case DLL_PROCESS_DETACH:
-+ /* Release the TLS index. */
-+ TlsFree(tlsIndex);
-+ gssEapFinalize();
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return TRUE;
-+ UNREFERENCED_PARAMETER(hDLL);
-+ UNREFERENCED_PARAMETER(reserved);
-+}
-+
-+#else /* WIN32 */
-+
-+/* pthreads implementation */
-+
-+static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER;
-+static GSSEAP_THREAD_KEY tldKey;
-+
-+static void
-+pthreadDestroyThreadLocalData(void *arg)
-+{
-+ struct gss_eap_thread_local_data* tld = arg;
-+
-+ if (tld != NULL)
-+ destroyThreadLocalData(tld);
-+}
-+
-+static void
-+createThreadLocalDataKey(void)
-+{
-+ GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData);
-+}
-+
-+struct gss_eap_thread_local_data *
-+gssEapGetThreadLocalData()
-+{
-+ struct gss_eap_thread_local_data *tld;
-+
-+ GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey);
-+
-+ tld = GSSEAP_GETSPECIFIC(tldKey);
-+ if (tld == NULL) {
-+ tld = GSSEAP_CALLOC(1, sizeof(*tld));
-+ if (tld == NULL)
-+ return NULL;
-+
-+ GSSEAP_SETSPECIFIC(tldKey, tld);
-+ }
-+
-+ return tld;
-+}
-+
-+#endif /* WIN32 */
-diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c
-new file mode 100644
-index 0000000..a1aea0c
---- /dev/null
-+++ b/mech_eap/util_token.c
-@@ -0,0 +1,493 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * Portions 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.
-+ */
-+
-+/*
-+ * Utility routines for GSS tokens.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32
-+gssEapEncodeInnerTokens(OM_uint32 *minor,
-+ struct gss_eap_token_buffer_set *tokens,
-+ gss_buffer_t buffer)
-+{
-+ OM_uint32 major, tmpMinor;
-+ size_t required = 0, i;
-+ unsigned char *p;
-+
-+ buffer->value = NULL;
-+ buffer->length = 0;
-+
-+ for (i = 0; i < tokens->buffers.count; i++) {
-+ required += 8 + tokens->buffers.elements[i].length;
-+ }
-+
-+ /*
-+ * We must always return a non-NULL token otherwise the calling state
-+ * machine assumes we are finished. Hence care in case malloc(0) does
-+ * return NULL.
-+ */
-+ buffer->value = GSSEAP_MALLOC(required ? required : 1);
-+ if (buffer->value == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ buffer->length = required;
-+ p = (unsigned char *)buffer->value;
-+
-+ for (i = 0; i < tokens->buffers.count; i++) {
-+ gss_buffer_t tokenBuffer = &tokens->buffers.elements[i];
-+
-+ GSSEAP_ASSERT((tokens->types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */
-+
-+ /*
-+ * Extensions are encoded as type-length-value, where the upper
-+ * bit of the type indicates criticality.
-+ */
-+ store_uint32_be(tokens->types[i], &p[0]);
-+ store_uint32_be(tokenBuffer->length, &p[4]);
-+ memcpy(&p[8], tokenBuffer->value, tokenBuffer->length);
-+
-+ p += 8 + tokenBuffer->length;
-+ }
-+
-+ GSSEAP_ASSERT(p == (unsigned char *)buffer->value + required);
-+ GSSEAP_ASSERT(buffer->value != NULL);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ gss_release_buffer(&tmpMinor, buffer);
-+ }
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapDecodeInnerTokens(OM_uint32 *minor,
-+ const gss_buffer_t buffer,
-+ struct gss_eap_token_buffer_set *tokens)
-+{
-+ OM_uint32 major, tmpMinor;
-+ unsigned char *p;
-+ size_t count = 0;
-+ size_t remain;
-+
-+ tokens->buffers.count = 0;
-+ tokens->buffers.elements = NULL;
-+ tokens->types = NULL;
-+
-+ if (buffer->length == 0) {
-+ major = GSS_S_COMPLETE;
-+ goto cleanup;
-+ }
-+
-+ p = (unsigned char *)buffer->value;
-+ remain = buffer->length;
-+
-+ do {
-+ OM_uint32 *ntypes;
-+ gss_buffer_desc tokenBuffer, *newTokenBuffers;
-+
-+ if (remain < 8) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_TOK_TRUNC;
-+ goto cleanup;
-+ }
-+
-+ if (tokens->buffers.count <= count) {
-+ if (count == 0)
-+ count = 1;
-+ else
-+ count *= 2;
-+
-+ ntypes = GSSEAP_MALLOC(count * sizeof(OM_uint32));
-+ if (ntypes == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ if (tokens->types != NULL) {
-+ memcpy(ntypes, tokens->types, tokens->buffers.count * sizeof(OM_uint32));
-+ GSSEAP_FREE(tokens->types);
-+ }
-+ tokens->types = ntypes;
-+
-+ newTokenBuffers = GSSEAP_MALLOC(count * sizeof(gss_buffer_desc));
-+ if (newTokenBuffers == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+ if (tokens->buffers.elements != NULL) {
-+ memcpy(newTokenBuffers, tokens->buffers.elements,
-+ tokens->buffers.count * sizeof(gss_buffer_desc));
-+ GSSEAP_FREE(tokens->buffers.elements);
-+ }
-+ tokens->buffers.elements = newTokenBuffers;
-+ }
-+
-+ tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]);
-+ tokenBuffer.length = load_uint32_be(&p[4]);
-+
-+ if (remain < 8 + tokenBuffer.length) {
-+ major = GSS_S_DEFECTIVE_TOKEN;
-+ *minor = GSSEAP_TOK_TRUNC;
-+ goto cleanup;
-+ }
-+ tokenBuffer.value = &p[8];
-+
-+ tokens->buffers.elements[tokens->buffers.count] = tokenBuffer;
-+ tokens->buffers.count++;
-+
-+ p += 8 + tokenBuffer.length;
-+ remain -= 8 + tokenBuffer.length;
-+ } while (remain != 0);
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major))
-+ gssEapReleaseInnerTokens(&tmpMinor, tokens, 0);
-+
-+ return major;
-+}
-+
-+/*
-+ * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
-+ */
-+
-+/* 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 size_t
-+der_length_size(size_t 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, size_t 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, ssize_t *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 */
-+
-+size_t
-+tokenSize(const gss_OID_desc *mech, size_t body_size)
-+{
-+ GSSEAP_ASSERT(mech != GSS_C_NO_OID);
-+
-+ /* set body_size to sequence contents size */
-+ body_size += 4 + (size_t) 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
-+makeTokenHeader(
-+ const gss_OID_desc *mech,
-+ size_t body_size,
-+ unsigned char **buf,
-+ enum gss_eap_token_type tok_type)
-+{
-+ *(*buf)++ = 0x60;
-+ der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
-+ *(*buf)++ = 0x06;
-+ *(*buf)++ = (unsigned char)mech->length;
-+ memcpy(*buf, mech->elements, mech->length);
-+ *buf += mech->length;
-+ GSSEAP_ASSERT(tok_type != TOK_TYPE_NONE);
-+ *(*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.
-+ */
-+
-+OM_uint32
-+verifyTokenHeader(OM_uint32 *minor,
-+ gss_OID mech,
-+ size_t *body_size,
-+ unsigned char **buf_in,
-+ size_t toksize_in,
-+ enum gss_eap_token_type *ret_tok_type)
-+{
-+ unsigned char *buf = *buf_in;
-+ ssize_t seqsize;
-+ gss_OID_desc toid;
-+ ssize_t toksize = (ssize_t)toksize_in;
-+
-+ *minor = GSSEAP_BAD_TOK_HEADER;
-+
-+ if (ret_tok_type != NULL)
-+ *ret_tok_type = TOK_TYPE_NONE;
-+
-+ if ((toksize -= 1) < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ if (*buf++ != 0x60)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ seqsize = der_read_length(&buf, &toksize);
-+ if (seqsize < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ if (seqsize != toksize)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ if ((toksize -= 1) < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ if (*buf++ != 0x06)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ if ((toksize -= 1) < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ toid.length = *buf++;
-+
-+ if ((toksize -= toid.length) < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ toid.elements = buf;
-+ buf += toid.length;
-+
-+ if (mech->elements == NULL) {
-+ *mech = toid;
-+ if (toid.length == 0)
-+ return GSS_S_BAD_MECH;
-+ } else if (!oidEqual(&toid, mech)) {
-+ *minor = GSSEAP_WRONG_MECH;
-+ return GSS_S_BAD_MECH;
-+ }
-+
-+ if (ret_tok_type != NULL) {
-+ if ((toksize -= 2) < 0)
-+ return GSS_S_DEFECTIVE_TOKEN;
-+
-+ *ret_tok_type = load_uint16_be(buf);
-+ buf += 2;
-+ }
-+
-+ *buf_in = buf;
-+ *body_size = toksize;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32
-+gssEapAllocInnerTokens(OM_uint32 *minor,
-+ size_t count,
-+ struct gss_eap_token_buffer_set *tokens)
-+{
-+ OM_uint32 major;
-+
-+ tokens->buffers.count = 0;
-+ tokens->buffers.elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc));
-+ if (tokens->buffers.elements == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ tokens->types = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32));
-+ if (tokens->types == NULL) {
-+ major = GSS_S_FAILURE;
-+ *minor = ENOMEM;
-+ goto cleanup;
-+ }
-+
-+ major = GSS_S_COMPLETE;
-+ *minor = 0;
-+
-+cleanup:
-+ if (GSS_ERROR(major)) {
-+ if (tokens->buffers.elements != NULL) {
-+ GSSEAP_FREE(tokens->buffers.elements);
-+ tokens->buffers.elements = NULL;
-+ }
-+ if (tokens->types != NULL) {
-+ GSSEAP_FREE(tokens->types);
-+ tokens->types = NULL;
-+ }
-+ }
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapReleaseInnerTokens(OM_uint32 *minor,
-+ struct gss_eap_token_buffer_set *tokens,
-+ int freeBuffers)
-+{
-+ OM_uint32 tmpMinor;
-+ size_t i;
-+
-+ if (tokens->buffers.elements != NULL) {
-+ if (freeBuffers) {
-+ for (i = 0; i < tokens->buffers.count; i++)
-+ gss_release_buffer(&tmpMinor, &tokens->buffers.elements[i]);
-+ }
-+ GSSEAP_FREE(tokens->buffers.elements);
-+ tokens->buffers.elements = NULL;
-+ }
-+ tokens->buffers.count = 0;
-+
-+ if (tokens->types != NULL) {
-+ GSSEAP_FREE(tokens->types);
-+ tokens->types = NULL;
-+ }
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-diff --git a/mech_eap/verify_mic.c b/mech_eap/verify_mic.c
-new file mode 100644
-index 0000000..c0829f5
---- /dev/null
-+++ b/mech_eap/verify_mic.c
-@@ -0,0 +1,71 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Message protection services: verify a message integrity check.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_verify_mic(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ gss_buffer_t message_buffer,
-+ gss_buffer_t message_token,
-+ gss_qop_t *qop_state)
-+{
-+ OM_uint32 major;
-+ gss_iov_buffer_desc iov[3];
-+ int conf_state;
-+
-+ if (message_token->length < 16) {
-+ *minor = GSSEAP_TOK_TRUNC;
-+ return GSS_S_BAD_SIG;
-+ }
-+
-+ *minor = 0;
-+
-+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
-+ iov[0].buffer = *message_buffer;
-+
-+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
-+ iov[1].buffer = *message_token;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state,
-+ iov, 2, TOK_TYPE_MIC);
-+
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/wrap.c b/mech_eap/wrap.c
-new file mode 100644
-index 0000000..2e27fb3
---- /dev/null
-+++ b/mech_eap/wrap.c
-@@ -0,0 +1,137 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Message protection services: wrap.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_wrap(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ 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 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapWrap(minor, ctx, conf_req_flag, qop_req,
-+ input_message_buffer,
-+ conf_state, output_message_buffer);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-+
-+OM_uint32
-+gssEapWrap(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ 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 major, tmpMinor;
-+ gss_iov_buffer_desc iov[4];
-+ unsigned char *p;
-+ int i;
-+
-+ 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 = *input_message_buffer;
-+
-+ 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;
-+
-+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
-+ NULL, iov, 4);
-+ if (GSS_ERROR(major)) {
-+ return major;
-+ }
-+
-+ for (i = 0, output_message_buffer->length = 0; i < 4; i++) {
-+ output_message_buffer->length += iov[i].buffer.length;
-+ }
-+
-+ output_message_buffer->value = GSSEAP_MALLOC(output_message_buffer->length);
-+ if (output_message_buffer->value == NULL) {
-+ *minor = ENOMEM;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ for (i = 0, p = output_message_buffer->value; i < 4; i++) {
-+ if (iov[i].type == GSS_IOV_BUFFER_TYPE_DATA) {
-+ memcpy(p, input_message_buffer->value, input_message_buffer->length);
-+ }
-+ iov[i].buffer.value = p;
-+ p += iov[i].buffer.length;
-+ }
-+
-+ major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
-+ iov, 4, TOK_TYPE_WRAP);
-+ if (GSS_ERROR(major)) {
-+ gss_release_buffer(&tmpMinor, output_message_buffer);
-+ }
-+
-+ return major;
-+}
-diff --git a/mech_eap/wrap_iov.c b/mech_eap/wrap_iov.c
-new file mode 100644
-index 0000000..be890b6
---- /dev/null
-+++ b/mech_eap/wrap_iov.c
-@@ -0,0 +1,379 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Message protection services: wrap with scatter-gather API.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+unsigned char
-+rfc4121Flags(gss_ctx_id_t ctx, int receiving)
-+{
-+ unsigned char flags;
-+ int isAcceptor;
-+
-+ isAcceptor = !CTX_IS_INITIATOR(ctx);
-+ if (receiving)
-+ isAcceptor = !isAcceptor;
-+
-+ flags = 0;
-+ if (isAcceptor)
-+ flags |= TOK_FLAG_SENDER_IS_ACCEPTOR;
-+
-+ if ((ctx->flags & CTX_FLAG_KRB_REAUTH) &&
-+ (ctx->gssFlags & GSS_C_MUTUAL_FLAG))
-+ flags |= TOK_FLAG_ACCEPTOR_SUBKEY;
-+
-+ return flags;
-+}
-+
-+OM_uint32
-+gssEapWrapOrGetMIC(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count,
-+ enum gss_eap_token_type toktype)
-+{
-+ krb5_error_code code = 0;
-+ gss_iov_buffer_t header;
-+ gss_iov_buffer_t padding;
-+ gss_iov_buffer_t trailer;
-+ unsigned char flags;
-+ unsigned char *outbuf = NULL;
-+ unsigned char *tbuf = NULL;
-+ int keyUsage;
-+ size_t rrc = 0;
-+ size_t gssHeaderLen, gssTrailerLen;
-+ size_t dataLen, assocDataLen;
-+ krb5_context krbContext;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto = NULL;
-+#endif
-+
-+ if (ctx->encryptionType == ENCTYPE_NULL) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ flags = rfc4121Flags(ctx, FALSE);
-+
-+ if (toktype == TOK_TYPE_WRAP) {
-+ keyUsage = CTX_IS_INITIATOR(ctx)
-+ ? KEY_USAGE_INITIATOR_SEAL
-+ : KEY_USAGE_ACCEPTOR_SEAL;
-+ } else {
-+ keyUsage = CTX_IS_INITIATOR(ctx)
-+ ? KEY_USAGE_INITIATOR_SIGN
-+ : KEY_USAGE_ACCEPTOR_SIGN;
-+ }
-+
-+ gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
-+
-+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
-+ if (header == NULL) {
-+ *minor = GSSEAP_MISSING_IOV;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
-+ if (padding != NULL)
-+ padding->buffer.length = 0;
-+
-+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
-+ if (code != 0)
-+ goto cleanup;
-+#endif
-+
-+ if (toktype == TOK_TYPE_WRAP && conf_req_flag) {
-+ size_t krbHeaderLen, krbTrailerLen, krbPadLen;
-+ size_t ec = 0, confDataLen = dataLen - assocDataLen;
-+
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ confDataLen + 16 /* E(Header) */,
-+ &krbPadLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
-+ /* Windows rejects AEAD tokens with non-zero EC */
-+ code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
-+ if (code != 0)
-+ goto cleanup;
-+ } else
-+ ec = krbPadLen;
-+
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ gssHeaderLen = 16 /* Header */ + krbHeaderLen;
-+ gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen;
-+
-+ if (trailer == NULL) {
-+ rrc = gssTrailerLen;
-+ /* Workaround for Windows bug where it rotates by EC + RRC */
-+ if (ctx->gssFlags & GSS_C_DCE_STYLE)
-+ rrc -= ec;
-+ gssHeaderLen += gssTrailerLen;
-+ }
-+
-+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
-+ code = gssEapAllocIov(header, (size_t)gssHeaderLen);
-+ } else if (header->buffer.length < gssHeaderLen)
-+ code = GSSEAP_WRONG_SIZE;
-+ if (code != 0)
-+ goto cleanup;
-+ outbuf = (unsigned char *)header->buffer.value;
-+ header->buffer.length = (size_t)gssHeaderLen;
-+
-+ if (trailer != NULL) {
-+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
-+ code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
-+ else if (trailer->buffer.length < gssTrailerLen)
-+ code = GSSEAP_WRONG_SIZE;
-+ if (code != 0)
-+ goto cleanup;
-+ trailer->buffer.length = (size_t)gssTrailerLen;
-+ }
-+
-+ /* TOK_ID */
-+ store_uint16_be((uint16_t)toktype, outbuf);
-+ /* flags */
-+ outbuf[2] = flags
-+ | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0);
-+ /* filler */
-+ outbuf[3] = 0xFF;
-+ /* EC */
-+ store_uint16_be(ec, outbuf + 4);
-+ /* RRC */
-+ store_uint16_be(0, outbuf + 6);
-+ store_uint64_be(ctx->sendSeq, 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 = gssEapEncrypt(krbContext,
-+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
-+ ec, rrc, KRB_CRYPTO_CONTEXT(ctx),
-+ keyUsage, iov, iov_count);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ /* RRC */
-+ store_uint16_be(rrc, outbuf + 6);
-+
-+ ctx->sendSeq++;
-+ } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) {
-+ wrap_with_checksum:
-+
-+ gssHeaderLen = 16;
-+
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ KRB5_CRYPTO_TYPE_CHECKSUM, &gssTrailerLen);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ GSSEAP_ASSERT(gssTrailerLen <= 0xFFFF);
-+
-+ if (trailer == NULL) {
-+ rrc = gssTrailerLen;
-+ gssHeaderLen += gssTrailerLen;
-+ }
-+
-+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
-+ code = gssEapAllocIov(header, (size_t)gssHeaderLen);
-+ else if (header->buffer.length < gssHeaderLen)
-+ code = GSSEAP_WRONG_SIZE;
-+ if (code != 0)
-+ goto cleanup;
-+ outbuf = (unsigned char *)header->buffer.value;
-+ header->buffer.length = (size_t)gssHeaderLen;
-+
-+ if (trailer != NULL) {
-+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
-+ code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
-+ else if (trailer->buffer.length < gssTrailerLen)
-+ code = GSSEAP_WRONG_SIZE;
-+ if (code != 0)
-+ goto cleanup;
-+ trailer->buffer.length = (size_t)gssTrailerLen;
-+ }
-+
-+ /* TOK_ID */
-+ store_uint16_be((uint16_t)toktype, outbuf);
-+ /* flags */
-+ outbuf[2] = flags;
-+ /* filler */
-+ outbuf[3] = 0xFF;
-+ if (toktype == TOK_TYPE_WRAP) {
-+ /* Use 0 for checksum calculation, substitute
-+ * checksum length later.
-+ */
-+ /* EC */
-+ store_uint16_be(0, outbuf + 4);
-+ /* RRC */
-+ store_uint16_be(0, outbuf + 6);
-+ } else {
-+ /* MIC and DEL store 0xFF in EC and RRC */
-+ store_uint16_be(0xFFFF, outbuf + 4);
-+ store_uint16_be(0xFFFF, outbuf + 6);
-+ }
-+ store_uint64_be(ctx->sendSeq, outbuf + 8);
-+
-+ code = gssEapSign(krbContext, ctx->checksumType, rrc,
-+ KRB_CRYPTO_CONTEXT(ctx), keyUsage,
-+ iov, iov_count);
-+ if (code != 0)
-+ goto cleanup;
-+
-+ ctx->sendSeq++;
-+
-+ if (toktype == TOK_TYPE_WRAP) {
-+ /* Fix up EC field */
-+ store_uint16_be(gssTrailerLen, outbuf + 4);
-+ /* Fix up RRC field */
-+ store_uint16_be(rrc, outbuf + 6);
-+ }
-+ } else if (toktype == TOK_TYPE_MIC) {
-+ trailer = NULL;
-+ goto wrap_with_checksum;
-+ } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
-+ trailer = NULL;
-+ goto wrap_with_checksum;
-+ } else {
-+ abort();
-+ }
-+
-+ code = 0;
-+ if (conf_state != NULL)
-+ *conf_state = conf_req_flag;
-+
-+cleanup:
-+ if (code != 0)
-+ gssEapReleaseIov(iov, iov_count);
-+#ifdef HAVE_HEIMDAL_VERSION
-+ if (krbCrypto != NULL)
-+ krb5_crypto_destroy(krbContext, krbCrypto);
-+#endif
-+
-+ *minor = code;
-+
-+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_wrap_iov(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ gss_qop_t qop_req,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ if (qop_req != GSS_C_QOP_DEFAULT) {
-+ *minor = GSSEAP_UNKNOWN_QOP;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
-+ iov, iov_count, TOK_TYPE_WRAP);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/wrap_iov_length.c b/mech_eap/wrap_iov_length.c
-new file mode 100644
-index 0000000..247b78d
---- /dev/null
-+++ b/mech_eap/wrap_iov_length.c
-@@ -0,0 +1,234 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+/*
-+ * 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.
-+ */
-+
-+/*
-+ * Message protection services: determine protected message size.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+#define INIT_IOV_DATA(_iov) do { (_iov)->buffer.value = NULL; \
-+ (_iov)->buffer.length = 0; } \
-+ while (0)
-+
-+OM_uint32
-+gssEapWrapIovLength(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ gss_qop_t qop_req,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ gss_iov_buffer_t header, trailer, padding;
-+ size_t dataLength, assocDataLength;
-+ size_t gssHeaderLen, gssPadLen, gssTrailerLen;
-+ size_t krbHeaderLen = 0, krbTrailerLen = 0, krbPadLen = 0;
-+ krb5_error_code code;
-+ krb5_context krbContext;
-+ int dce_style;
-+ size_t ec;
-+#ifdef HAVE_HEIMDAL_VERSION
-+ krb5_crypto krbCrypto = NULL;
-+#endif
-+
-+ if (qop_req != GSS_C_QOP_DEFAULT) {
-+ *minor = GSSEAP_UNKNOWN_QOP;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ if (ctx->encryptionType == ENCTYPE_NULL) {
-+ *minor = GSSEAP_KEY_UNAVAILABLE;
-+ return GSS_S_UNAVAILABLE;
-+ }
-+
-+ GSSEAP_KRB_INIT(&krbContext);
-+
-+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
-+ if (header == NULL) {
-+ *minor = GSSEAP_MISSING_IOV;
-+ return GSS_S_FAILURE;
-+ }
-+ INIT_IOV_DATA(header);
-+
-+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
-+ if (trailer != NULL) {
-+ INIT_IOV_DATA(trailer);
-+ }
-+
-+ dce_style = ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0);
-+
-+ /* For CFX, EC is used instead of padding, and is placed in header or trailer */
-+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
-+ if (padding != NULL) {
-+ INIT_IOV_DATA(padding);
-+ }
-+
-+ gssEapIovMessageLength(iov, iov_count, &dataLength, &assocDataLength);
-+
-+ if (conf_req_flag && gssEapIsIntegrityOnly(iov, iov_count))
-+ conf_req_flag = FALSE;
-+
-+ gssHeaderLen = gssPadLen = gssTrailerLen = 0;
-+
-+#ifdef HAVE_HEIMDAL_VERSION
-+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
-+ if (code != 0)
-+ return code;
-+#endif
-+
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ conf_req_flag ?
-+ KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
-+ &krbTrailerLen);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (conf_req_flag) {
-+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+ }
-+
-+ gssHeaderLen = 16; /* Header */
-+ if (conf_req_flag) {
-+ gssHeaderLen += krbHeaderLen; /* Kerb-Header */
-+ gssTrailerLen = 16 /* E(Header) */ + krbTrailerLen; /* Kerb-Trailer */
-+
-+ code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
-+ dataLength - assocDataLength + 16 /* E(Header) */,
-+ &krbPadLen);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+
-+ if (krbPadLen == 0 && dce_style) {
-+ /* Windows rejects AEAD tokens with non-zero EC */
-+ code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
-+ if (code != 0) {
-+ *minor = code;
-+ return GSS_S_FAILURE;
-+ }
-+ } else
-+ ec = krbPadLen;
-+
-+ gssTrailerLen += ec;
-+ } else {
-+ gssTrailerLen = krbTrailerLen; /* Kerb-Checksum */
-+ }
-+
-+ dataLength += gssPadLen;
-+
-+ if (trailer == NULL)
-+ gssHeaderLen += gssTrailerLen;
-+ else
-+ trailer->buffer.length = gssTrailerLen;
-+
-+ GSSEAP_ASSERT(gssPadLen == 0 || padding != NULL);
-+
-+ if (padding != NULL)
-+ padding->buffer.length = gssPadLen;
-+
-+ header->buffer.length = gssHeaderLen;
-+
-+ if (conf_state != NULL)
-+ *conf_state = conf_req_flag;
-+
-+ *minor = 0;
-+ return GSS_S_COMPLETE;
-+}
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_wrap_iov_length(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ int conf_req_flag,
-+ gss_qop_t qop_req,
-+ int *conf_state,
-+ gss_iov_buffer_desc *iov,
-+ int iov_count)
-+{
-+ OM_uint32 major;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
-+ conf_state, iov, iov_count);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
-diff --git a/mech_eap/wrap_size_limit.c b/mech_eap/wrap_size_limit.c
-new file mode 100644
-index 0000000..d11fd63
---- /dev/null
-+++ b/mech_eap/wrap_size_limit.c
-@@ -0,0 +1,97 @@
-+/*
-+ * Copyright (c) 2011, JANET(UK)
-+ * 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 JANET(UK) nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE 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.
-+ */
-+
-+/*
-+ * Message protection services: determine maximum input size.
-+ */
-+
-+#include "gssapiP_eap.h"
-+
-+OM_uint32 GSSAPI_CALLCONV
-+gss_wrap_size_limit(OM_uint32 *minor,
-+ gss_ctx_id_t ctx,
-+ 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 major, overhead;
-+
-+ if (ctx == GSS_C_NO_CONTEXT) {
-+ *minor = EINVAL;
-+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
-+ }
-+
-+ *minor = 0;
-+
-+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
-+
-+ if (!CTX_IS_ESTABLISHED(ctx)) {
-+ major = GSS_S_NO_CONTEXT;
-+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
-+ goto cleanup;
-+ }
-+
-+ 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;
-+
-+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
-+ NULL, iov, 4);
-+ if (GSS_ERROR(major))
-+ goto cleanup;
-+
-+ overhead = iov[0].buffer.length + iov[3].buffer.length;
-+
-+ if (iov[2].buffer.length == 0 && overhead < req_output_size)
-+ *max_input_size = req_output_size - overhead;
-+ else
-+ *max_input_size = 0;
-+
-+cleanup:
-+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
-+
-+ return major;
-+}
---
-1.7.5.4
-