Merge branch 'windows'
authorLuke Howard <lukeh@padl.com>
Wed, 14 Sep 2011 06:11:37 +0000 (16:11 +1000)
committerLuke Howard <lukeh@padl.com>
Wed, 14 Sep 2011 06:11:37 +0000 (16:11 +1000)
Conflicts:
moonshot/configure.ac
moonshot/mech_eap/Makefile.am
moonshot/mech_eap/accept_sec_context.c
moonshot/mech_eap/acquire_cred.c
moonshot/mech_eap/add_cred.c
moonshot/mech_eap/add_cred_with_password.c
moonshot/mech_eap/canonicalize_name.c
moonshot/mech_eap/compare_name.c
moonshot/mech_eap/context_time.c
moonshot/mech_eap/delete_name_attribute.c
moonshot/mech_eap/delete_sec_context.c
moonshot/mech_eap/display_name.c
moonshot/mech_eap/display_name_ext.c
moonshot/mech_eap/display_status.c
moonshot/mech_eap/duplicate_name.c
moonshot/mech_eap/eap_mech.c
moonshot/mech_eap/export_name.c
moonshot/mech_eap/export_name_composite.c
moonshot/mech_eap/export_sec_context.c
moonshot/mech_eap/get_mic.c
moonshot/mech_eap/get_name_attribute.c
moonshot/mech_eap/gssapiP_eap.h
moonshot/mech_eap/import_name.c
moonshot/mech_eap/import_sec_context.c
moonshot/mech_eap/indicate_mechs.c
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/inquire_attrs_for_mech.c
moonshot/mech_eap/inquire_context.c
moonshot/mech_eap/inquire_cred.c
moonshot/mech_eap/inquire_cred_by_oid.c
moonshot/mech_eap/inquire_mech_for_saslname.c
moonshot/mech_eap/inquire_mechs_for_name.c
moonshot/mech_eap/inquire_name.c
moonshot/mech_eap/inquire_names_for_mech.c
moonshot/mech_eap/inquire_saslname_for_mech.c
moonshot/mech_eap/inquire_sec_context_by_oid.c
moonshot/mech_eap/map_name_to_any.c
moonshot/mech_eap/process_context_token.c
moonshot/mech_eap/pseudo_random.c
moonshot/mech_eap/release_any_name_mapping.c
moonshot/mech_eap/release_cred.c
moonshot/mech_eap/release_name.c
moonshot/mech_eap/set_name_attribute.c
moonshot/mech_eap/set_sec_context_option.c
moonshot/mech_eap/store_cred.c
moonshot/mech_eap/unwrap.c
moonshot/mech_eap/unwrap_iov.c
moonshot/mech_eap/util.h
moonshot/mech_eap/util_context.c
moonshot/mech_eap/util_cred.c
moonshot/mech_eap/util_krb.c
moonshot/mech_eap/util_name.c
moonshot/mech_eap/util_tld.c
moonshot/mech_eap/verify_mic.c
moonshot/mech_eap/wrap.c
moonshot/mech_eap/wrap_iov.c
moonshot/mech_eap/wrap_iov_length.c
moonshot/mech_eap/wrap_size_limit.c

15 files changed:
1  2 
acinclude.m4
configure.ac
mech_eap/Makefile.am
mech_eap/delete_sec_context.c
mech_eap/display_status.c
mech_eap/export_sec_context.c
mech_eap/gssapiP_eap.h
mech_eap/import_sec_context.c
mech_eap/util.h
mech_eap/util_context.c
mech_eap/util_cred.c
mech_eap/util_krb.c
mech_eap/util_name.c
mech_eap/util_radius.h
mech_eap/util_tld.c

diff --combined acinclude.m4
@@@ -1,5 -1,5 +1,13 @@@
  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=
@@@ -9,16 -9,23 +17,22 @@@ AC_ARG_WITH(krb5
         [Use krb5 (in specified installation directory)]),
      [check_krb5_dir="$withval"],
      [check_krb5_dir=])
 -AM_COND_IF(TARGET_WINDOWS,[
 -   found_krb5="yes"
 -   krb5dir=$check_krb5_dir
 -   KRB5_CFLAGS=-I"$check_krb5_dir/include"
 -   KRB5_LIBS="-L$check_krb5_dir/lib/ -lkrb5_32 -lgssapi32"
 -   COMPILE_ET=
 -],
 -[for dir in $check_krb5_dir $prefix /usr /usr/local ; do
 +for dir in $check_krb5_dir $prefix /usr /usr/local ; do
     krb5dir="$dir"
     if test -x "$dir/bin/krb5-config"; then
       found_krb5="yes";
--     KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
--     KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`;
--     COMPILE_ET="$dir/bin/compile_et";
++     if test "x$target_windows" = "xyes"; then
++        KRB5_CFLAGS=-I"$check_krb5_dir/include";
++        KRB5_LIBS="-L$check_krb5_dir/lib/ -lkrb5_32 -lgssapi32";
++        COMPILE_ET="$check_krb5_dir/bin/compile_et";
++     else
++        KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
++        KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`;
++        COMPILE_ET="$dir/bin/compile_et";
++     fi
       break;
     fi
 -done])
 +done
  AC_MSG_RESULT($found_krb5)
  if test x_$found_krb5 != x_yes; then
     AC_MSG_ERROR([
@@@ -129,7 -136,7 +143,7 @@@ AC_MSG_RESULT($found_shibsp
  if test x_$found_shibsp != x_yes; then
     AC_MSG_ERROR([
  ----------------------------------------------------------------------
 -  Cannot find Shibboleth/OpenSAML libraries.
 +  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_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
  
@@@ -155,7 -161,6 +169,7 @@@ AC_ARG_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
       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_ERROR([
 +   AC_MSG_WARN([
  ----------------------------------------------------------------------
 -  Cannot find Shibboleth resolver libraries.
 +  Cannot find Shibboleth resolver libraries, building without
 +  Shibboleth support.
  
    Please install Shibboleth or specify installation directory with
    --with-shibresolver=(dir).
@@@ -185,53 -187,17 +199,53 @@@ els
        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_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_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)
@@@ -308,43 -274,3 +322,43 @@@ els
        AC_SUBST(JANSSON_LIBS)
  fi
  ])dnl
 +
 +AC_DEFUN([AX_CHECK_LIBMOONSHOT],
 +[AC_MSG_CHECKING(for Moonshot identity selector implementation)
 +LIBMOONSHOT_DIR=
 +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 ../../moonshot-ui/libmoonshot ; 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
 +   AC_MSG_ERROR([
 +----------------------------------------------------------------------
 +  Cannot find Moonshot identity selector libraries.
 +
 +  Please install wpa_supplicant or specify installation directory with
 +  --with-libmoonshot=(dir).
 +----------------------------------------------------------------------
 +])
 +else
 +      printf "libmoonshot found in $libmoonshotdir\n";
 +      LIBMOONSHOT_LIBS="-lmoonshot";
 +      LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib";
 +      AC_SUBST(LIBMOONSHOT_CFLAGS)
 +      AC_SUBST(LIBMOONSHOT_LDFLAGS)
 +      AC_SUBST(LIBMOONSHOT_LIBS)
 +      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
 +])dnl
 +
diff --combined configure.ac
@@@ -2,16 -2,19 +2,19 @@@ AC_PREREQ([2.61]
  AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
  dnl AC_CONFIG_MACRO_DIR([m4])
  dnl AM_INIT_AUTOMAKE([silent-rules])
+ AC_USE_SYSTEM_EXTENSIONS
+ AC_GNU_SOURCE
  AM_INIT_AUTOMAKE
 -LT_PREREQ([2.4])
+ AM_PROG_CC_C_O
+ AM_MAINTAINER_MODE()
- LT_INIT([dlopen disable-static])
 +LT_PREREQ([2.2])
+ LT_INIT([dlopen disable-static win32-dll])
  
- AC_PROG_CC
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)
- AC_GNU_SOURCE
  
  dnl Check if we're on Solaris and set CFLAGS accordingly
  dnl AC_CANONICAL_TARGET
@@@ -66,21 -69,15 +69,22 @@@ AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, 
  
  AC_SUBST(TARGET_CFLAGS)
  AC_SUBST(TARGET_LDFLAGS)
+ AX_CHECK_WINDOWS
  AX_CHECK_KRB5
 -AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno")
 -dnl AX_CHECK_EAP
 -if test "x$acceptor" = "xyes" ; then
 +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
 -  AX_CHECK_SHIBRESOLVER
 +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])
  AC_OUTPUT
diff --combined mech_eap/Makefile.am
@@@ -4,32 -4,33 +4,46 @@@ gssincludedir = $(includedir)/gssap
  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 \
-       -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
+       -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_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@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
 +mech_eap_la_CFLAGS   = -Werror -Wall -Wunused-parameter \
 +                      @KRB5_CFLAGS@  @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
 +mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter \
 +                      @KRB5_CFLAGS@  @RADSEC_CFLAGS@ \
 +                      @OPENSAML_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ \
 +                      @TARGET_CFLAGS@ $(EAP_CFLAGS)
  mech_eap_la_LDFLAGS  = -avoid-version -module \
 -                      -export-symbols $(srcdir)/mech_eap.exports -no-undefined \
 +                      -export-symbols $(GSSEAP_EXPORTS) -no-undefined \
                        @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
 -mech_eap_la_LIBADD   = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \
 -                     @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@ $(OS_LIBS) $(LTLIBOBJS)
++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 =                         \
 -      accept_sec_context.c                    \
        acquire_cred.c                          \
        acquire_cred_with_password.c            \
        add_cred.c                              \
@@@ -38,6 -39,7 +52,6 @@@
        canonicalize_name.c                     \
        compare_name.c                          \
        context_time.c                          \
 -      delete_name_attribute.c                 \
        delete_sec_context.c                    \
        display_name.c                          \
        display_name_ext.c                      \
        duplicate_name.c                        \
        eap_mech.c                              \
        export_name.c                           \
 -      export_name_composite.c                 \
        export_sec_context.c                    \
        get_mic.c                               \
 -      get_name_attribute.c                    \
        gsseap_err.c                            \
        import_name.c                           \
        import_sec_context.c                    \
        inquire_names_for_mech.c                \
        inquire_saslname_for_mech.c             \
        inquire_sec_context_by_oid.c            \
 -      map_name_to_any.c                       \
        process_context_token.c                 \
        pseudo_random.c                         \
        radsec_err.c                            \
 -      release_any_name_mapping.c              \
        release_cred.c                          \
        release_name.c                          \
        release_oid.c                           \
 -      set_name_attribute.c                    \
        set_cred_option.c                       \
        set_sec_context_option.c                \
        store_cred.c                            \
        unwrap.c                                \
        unwrap_iov.c                            \
 -      util_base64.c                           \
        util_buffer.c                           \
        util_context.c                          \
        util_cksum.c                            \
@@@ -82,7 -90,6 +96,7 @@@
        util_krb.c                              \
        util_lucid.c                            \
        util_mech.c                             \
 +      util_moonshot.c                         \
        util_name.c                             \
        util_oid.c                              \
        util_ordering.c                         \
        wrap_iov_length.c                       \
        wrap_size_limit.c
  
 -BUILT_SOURCES = gsseap_err.c radsec_err.c
 -
  if GSSEAP_ENABLE_ACCEPTOR
 -mech_eap_la_SOURCES += util_attr.cpp util_json.cpp util_radius.cpp util_shib.cpp util_saml.cpp
 +
 +mech_eap_la_SOURCES +=                                \
 +      accept_sec_context.c                    \
 +      delete_name_attribute.c                 \
 +      export_name_composite.c                 \
 +      get_name_attribute.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
 +
  if GSSEAP_ENABLE_REAUTH
  mech_eap_la_SOURCES += util_reauth.c
  
@@@ -138,6 -124,9 +152,6 @@@ radius_ad_la_SOURCES = util_adshim.
  endif
  endif
  
 -if TARGET_WINDOWS
 -mech_eap_la_LDFLAGS += -debug
 -else
  gsseap_err.h gsseap_err.c: gsseap_err.et
        $(COMPILE_ET) $<
  
@@@ -148,4 -137,4 +162,3 @@@ radsec_err.c: radsec_err.
  
  clean-generic:
        rm -f gsseap_err.[ch] radsec_err.[ch]
 -endif
@@@ -36,7 -36,7 +36,7 @@@
  
  #include "gssapiP_eap.h"
  
 -OM_uint32 KRB5_CALLCONV
 +OM_uint32 GSSAPI_CALLCONV
  gss_delete_sec_context(OM_uint32 *minor,
                         gss_ctx_id_t *context_handle,
                         gss_buffer_t output_token)
@@@ -67,7 -67,7 +67,7 @@@
          iov[1].buffer.value = NULL;
          iov[1].buffer.length = 0;
  
-         major = gssEapWrapOrGetMIC(minor, ctx, FALSE, FALSE,
+         major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
                                     iov, 2, TOK_TYPE_DELETE_CONTEXT);
          if (GSS_ERROR(major)) {
              GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
@@@ -43,7 -43,7 +43,7 @@@ struct gss_eap_status_info 
  };
  
  void
 -gssEapDestroyStatusInfo(struct gss_eap_status_infop)
 +gssEapDestroyStatusInfo(struct gss_eap_status_info *p)
  {
      struct gss_eap_status_info *next;
  
@@@ -65,10 -65,10 +65,10 @@@ static voi
  saveStatusInfoNoCopy(OM_uint32 minor, char *message)
  {
      struct gss_eap_status_info **next = NULL, *p=NULL;
 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
  
 -    struct gss_eap_thread_local_data* tld = gssEapGetThreadLocalData();
      if (tld != NULL) {
 -        for (p = tld->status_info; p != NULL; p = p->next) {
 +        for (p = tld->statusInfo; p != NULL; p = p->next) {
              if (p->code == minor) {
                  /* Set message in-place */
                  if (p->message != NULL)
@@@ -78,9 -78,9 +78,9 @@@
              }
              next = &p->next;
          }
 -
          p = GSSEAP_CALLOC(1, sizeof(*p));
      }
 +
      if (p == NULL) {
          if (message != NULL)
              GSSEAP_FREE(message);
      if (next != NULL)
          *next = p;
      else
 -        tld->status_info = p;
 +        tld->statusInfo = p;
  }
  
  static const char *
  getStatusInfo(OM_uint32 minor)
  {
      struct gss_eap_status_info *p;
 -    struct gss_eap_thread_local_data *tld=gssEapGetThreadLocalData();
 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
 +
      if (tld != NULL) {
 -        for (p = tld->status_info;
 -             p != NULL;
 -             p = p->next) {
 +        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 KRB5_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)
 +OM_uint32
 +gssEapDisplayStatus(OM_uint32 *minor,
 +                    OM_uint32 status_value,
 +                    gss_buffer_t status_string)
  {
      OM_uint32 major;
      krb5_context krbContext = NULL;
      status_string->length = 0;
      status_string->value = NULL;
  
 -    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;
 -    }
 -
      errMsg = getStatusInfo(status_value);
      if (errMsg == NULL) {
          GSSEAP_KRB_INIT(&krbContext);
  
      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);
 +}
@@@ -36,7 -36,6 +36,7 @@@
   */
  
  #include "gssapiP_eap.h"
 +
  #ifdef GSSEAP_ENABLE_ACCEPTOR
  static OM_uint32
  gssEapExportPartialContext(OM_uint32 *minor,
@@@ -47,7 -46,6 +47,6 @@@
      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) {
@@@ -60,7 -58,6 +59,6 @@@
          }
          serverLen = strlen(serverBuf);
      }
      length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
  
      token->value = GSSEAP_MALLOC(length);
@@@ -138,7 -135,6 +136,7 @@@ gssEapExportSecContext(OM_uint32 *minor
          if (GSS_ERROR(major))
              goto cleanup;
      }
 +
  #ifdef GSSEAP_ENABLE_ACCEPTOR
      /*
       * The partial context is only transmitted for unestablished acceptor
@@@ -212,7 -208,7 +210,7 @@@ cleanup
      return major;
  }
  
 -OM_uint32 KRB5_CALLCONV
 +OM_uint32 GSSAPI_CALLCONV
  gss_export_sec_context(OM_uint32 *minor,
                         gss_ctx_id_t *context_handle,
                         gss_buffer_t interprocess_token)
diff --combined mech_eap/gssapiP_eap.h
  #include <assert.h>
  #include <string.h>
  #include <errno.h>
 -#if defined(HAVE_UNISTD_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>
 -#if defined(HAVE_SYS_PARAM_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>
@@@ -89,21 -78,28 +89,25 @@@ typedef const gss_OID_desc *gss_const_O
  #include <eap_common/eap_common.h>
  #include <wpabuf.h>
  
- /* FreeRADIUS headers */
  #ifdef GSSEAP_ENABLE_ACCEPTOR
+ /* FreeRADIUS headers */
  #ifdef __cplusplus
  extern "C" {
  #define operator fr_operator
  #endif
  #include <freeradius/libradius.h>
  #include <freeradius/radius.h>
 -////Because freeradius/autoconf.h is evil!
 -////#undef uint16_t
 -////#undef uint32_t
 -////#undef uint8_t
+ #undef pid_t
++/* libradsec headers */
  #include <radsec/radsec.h>
  #include <radsec/request.h>
  #ifdef __cplusplus
  #undef operator
  }
  #endif
 -#endif /*GSSEAP_ENABLE_ACCEPTOR*/
 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
  
  #include "gsseap_err.h"
  #include "radsec_err.h"
@@@ -131,16 -127,14 +135,16 @@@ struct gss_name_struc
      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_DEFAULT_IDENTITY          0x00040000
 -#define CRED_FLAG_PASSWORD                  0x00080000
 -#define CRED_FLAG_DEFAULT_CCACHE            0x00100000
 +#define CRED_FLAG_PASSWORD                  0x00040000
 +#define CRED_FLAG_DEFAULT_CCACHE            0x00080000
 +#define CRED_FLAG_RESOLVED                  0x00100000
  #define CRED_FLAG_PUBLIC_MASK               0x0000FFFF
  
  #ifdef HAVE_HEIMDAL_VERSION
@@@ -152,15 -146,11 +156,15 @@@ struct gss_cred_id_struc
      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;
 -    char *radiusConfigFile;
 -    char *radiusConfigStanza;
 +    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;
@@@ -222,7 -212,7 +226,7 @@@ struct gss_ctx_id_struc
      time_t expiryTime;
      uint64_t sendSeq, recvSeq;
      void *seqState;
 -    gss_cred_id_t defaultCred;
 +    gss_cred_id_t cred;
      union {
          struct gss_eap_initiator_ctx initiator;
          #define initiatorCtx         ctxU.initiator
          #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 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,
@@@ -321,18 -279,9 +325,18 @@@ rfc4121Flags(gss_ctx_id_t ctx, int rece
  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)
 +
  /* export_sec_context.c */
  OM_uint32
  gssEapExportSecContext(OM_uint32 *minor,
                         gss_buffer_t token);
  
  
 +/* eap_mech.c */
 +void
 +gssEapInitiatorInit(void);
 +
 +void
 +gssEapFinalize(void);
 +
  #ifdef __cplusplus
  }
  #endif
@@@ -114,7 -114,7 +114,7 @@@ gssEapImportPartialContext(OM_uint32 *m
  
      return GSS_S_COMPLETE;
  }
- #endif
+ #endif /* GSSEAP_ENABLE_ACCEPTOR */
  
  static OM_uint32
  importMechanismOid(OM_uint32 *minor,
@@@ -305,7 -305,6 +305,7 @@@ gssEapImportContext(OM_uint32 *minor
      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
          if (GSS_ERROR(major))
              return major;
      }
 -#endif
  
  #ifdef GSSEAP_DEBUG
      assert(remain == 0);
  #endif
- #endif
++#endif /* GSSEAP_ENABLE_ACCEPTOR */
  
      major = GSS_S_COMPLETE;
      *minor = 0;
      return major;
  }
  
 -OM_uint32 KRB5_CALLCONV
 +OM_uint32 GSSAPI_CALLCONV
  gss_import_sec_context(OM_uint32 *minor,
                         gss_buffer_t interprocess_token,
                         gss_ctx_id_t *context_handle)
diff --combined mech_eap/util.h
  #ifndef _UTIL_H_
  #define _UTIL_H_ 1
  
 -#if defined(HAVE_SYS_PARAM_H)
 +#ifdef HAVE_SYS_PARAM_H
  #include <sys/param.h>
  #endif
 -#if defined(HAVE_STDINT_H)
 +#ifdef HAVE_STDINT_H
  #include <stdint.h>
  #endif
  #include <string.h>
@@@ -72,9 -72,8 +72,9 @@@
  
  #include <krb5.h>
  
 -#if defined(WIN32)
 -#define inline  __inline
 +#ifdef WIN32
 +#define inline __inline
 +#define snprintf _snprintf
  #endif
  
  #ifdef __cplusplus
@@@ -85,25 -84,44 +85,25 @@@ extern "C" 
  #define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
  #endif
  
- #if !defined(WIN32) && (!(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)))
+ #if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
 -#define GSSEAP_UNUSED __attribute__ ((__unused__)) 
 +#define GSSEAP_UNUSED __attribute__ ((__unused__))
  #else
  #define GSSEAP_UNUSED
  #endif
  
 -#if !defined(WIN32)
 -#define GSSEAP_CONSTRUCTOR  __attribute__((constructor))
 -#define GSSEAP_DESTRUCTOR   __attribute__((destructor))
 -#else
 -#define GSSEAP_CONSTRUCTOR
 -#define GSSEAP_DESTRUCTOR
 -#endif
 -
 -/* thread local storage */
 -struct gss_eap_status_info;
 -
 -struct gss_eap_thread_local_data
 -{
 -      krb5_context context;
 -      struct gss_eap_status_info* status_info;
 -};
 -
 -struct gss_eap_thread_local_data* 
 -gssEapGetThreadLocalData();
 -
 -void 
 -gssEapDestroyStatusInfo(struct gss_eap_status_info* status);
 -
 -void 
 -gssEapDestroyKrbContext(krb5_context context);
 -
  /* 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,
@@@ -114,13 -132,6 +114,13 @@@ 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)
  {
@@@ -201,17 -212,12 +201,17 @@@ enum gss_eap_token_type 
  #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
 +
  OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
  OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
  
@@@ -234,26 -240,14 +234,26 @@@ 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,
 -                  const gss_buffer_t password,
                    OM_uint32 timeReq,
                    const gss_OID_set desiredMechs,
                    int cred_usage,
                    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
@@@ -514,17 -492,6 +514,17 @@@ 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
@@@ -706,29 -673,16 +706,29 @@@ voi
  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,
 -                        gss_buffer_set_t extensions,
 -                        OM_uint32 *types,
 +                        struct gss_eap_token_buffer_set *tokens,
                          gss_buffer_t buffer);
  OM_uint32
  gssEapDecodeInnerTokens(OM_uint32 *minor,
                          const gss_buffer_t buffer,
 -                        gss_buffer_set_t *pExtensions,
 -                        OM_uint32 **pTypes);
 +                        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);
@@@ -754,18 -708,6 +754,18 @@@ verifyTokenHeader(OM_uint32 *minor
  #define GSSEAP_FREE                     free
  #define GSSEAP_REALLOC                  realloc
  
 +#ifndef GSSAPI_CALLCONV
 +#define GSSAPI_CALLCONV                 KRB5_CALLCONV
 +#endif
 +
 +#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 {            \
          assert(0 && "not implemented");                 \
          *minor = ENOSYS;                                \
      } while (0)
  
  #ifdef WIN32
 +
  #include <winbase.h>
 -#define GSSEAP_MUTEX                    CRITICAL_SECTION
 -// wrapper for EnterCriticalSection() to provide return value
 -inline int win32_mutex_init(CRITICAL_SECTION* m)
 -{
 -      EnterCriticalSection(m);
 -      return 0;
 -}
  
 -#define GSSEAP_MUTEX_INIT(m)            win32_mutex_init((m))
 +#define GSSEAP_GET_LAST_ERROR()               (GetLastError())
 +
 +#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))
  
- /* XXX yet to implement thread-local wrappers */
++/* Thread-local is handled separately */
 +
 +#define GSSEAP_THREAD_ONCE              INIT_ONCE
 +#define GSSEAP_ONCE(o, i)               InitOnceExecuteOnce((o), (i))
 +#define GSSEAP_ONCE_INITIALIZER         INIT_ONCE_STATIC_INIT
 +
  #else
 +
  #include <pthread.h>
  
 -#define GSSEAP_MUTEX                    pthread_mutex_t
 -#define GSSEAP_MUTEX_INITIALIZER        PTHREAD_MUTEX_INITIALIZER
 +#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_THREAD_ONCE              pthread_once_t
  #define GSSEAP_ONCE(o, i)               pthread_once((o), (i))
  #define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
 -#endif
 +
 +#endif /* WIN32 */
  
  /* Helper functions */
  static inline void
@@@ -964,23 -899,6 +962,23 @@@ gssBufferToKrbData(gss_buffer_t buffer
      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"
 -#endif
  #include "util_base64.h"
- #endif
++#endif /* GSSEAP_ENABLE_ACCEPTOR */
  #ifdef GSSEAP_ENABLE_REAUTH
  #include "util_reauth.h"
  #endif
diff --combined mech_eap/util_context.c
@@@ -52,13 -52,12 +52,13 @@@ gssEapAllocContext(OM_uint32 *minor
      }
  
      if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
 -        *minor = errno;
 +        *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
@@@ -71,7 -70,8 +71,7 @@@
                      GSS_C_INTEG_FLAG    |   /* integrity */
                      GSS_C_CONF_FLAG     |   /* confidentiality */
                      GSS_C_SEQUENCE_FLAG |   /* sequencing */
 -                    GSS_C_REPLAY_FLAG|      /* replay detection */
 -      GSS_C_MUTUAL_FLAG; /*xxx big hack */
 +                    GSS_C_REPLAY_FLAG;      /* replay detection */
  
      *pCtx = ctx;
  
@@@ -100,7 -100,7 +100,7 @@@ releaseAcceptorContext(struct gss_eap_a
      if (ctx->vps != NULL)
          gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
  }
- #endif
+ #endif /* GSSEAP_ENABLE_ACCEPTOR */
  
  OM_uint32
  gssEapReleaseContext(OM_uint32 *minor,
      if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
          gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
      } else
--#endif
++#endif /* GSSEAP_ENABLE_REAUTH */
      if (CTX_IS_INITIATOR(ctx)) {
          releaseInitiatorContext(&ctx->initiatorCtx);
 -    } else {
 +    }
  #ifdef GSSEAP_ENABLE_ACCEPTOR
 +    else {
          releaseAcceptorContext(&ctx->acceptorCtx);
 -#endif
      }
- #endif
++#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->defaultCred);
 +    gssEapReleaseCred(&tmpMinor, &ctx->cred);
  
      GSSEAP_MUTEX_DESTROY(&ctx->mutex);
  
@@@ -156,8 -155,6 +156,8 @@@ gssEapMakeToken(OM_uint32 *minor
  {
      unsigned char *p;
  
 +    assert(ctx->mechanismUsed != GSS_C_NO_OID);
 +
      outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
      outputToken->value = GSSEAP_MALLOC(outputToken->length);
      if (outputToken->value == NULL) {
@@@ -235,149 -232,3 +235,149 @@@ gssEapContextTime(OM_uint32 *minor
  
      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;
 +
 +    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 */
 +    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) {
 +        assert(tokenMIC->length >= 16);
 +
 +        assert(i < 2 + (3 * tokens->buffers.count));
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
 +        iov[i].buffer.length = 16;
 +        iov[i].buffer.value = tokenMIC->value;
 +        i++;
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_TRAILER;
 +        iov[i].buffer.length = tokenMIC->length - 16;
 +        iov[i].buffer.value = (unsigned char *)tokenMIC->value + 16;
 +        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 --combined mech_eap/util_cred.c
  
  #include "gssapiP_eap.h"
  
 -#if defined(WIN32)
 -/*This didn't work for me(Alexey) when Visual Studio 2005 Express is used: */
 -#include <Shlobj.h>
 -/*This didn't work for me(Kevin) when Visual Studio 2010 Express is used: */
 -/*#include <ShFolder.h>*/
 -
 -#if !defined(snprintf)
 -#define snprintf  _snprintf
 -#endif
 -
 +#ifdef WIN32
- #include <shlobj.h>
++# include <shlobj.h>     /* may need to use ShFolder.h instead */
++# include <stdio.h>
  #else
--#include <pwd.h>
++# include <pwd.h>
  #endif
 -#include <stdio.h> /* for BUFSIZ */
  
  OM_uint32
  gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
@@@ -57,7 -66,7 +58,7 @@@
      }
  
      if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
 -        *minor = errno;
 +        *minor = GSSEAP_GET_LAST_ERROR();
          gssEapReleaseCred(&tmpMinor, &cred);
          return GSS_S_FAILURE;
      }
      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)
  {
      GSSEAP_KRB_INIT(&krbContext);
  
      gssEapReleaseName(&tmpMinor, &cred->name);
 +    gssEapReleaseName(&tmpMinor, &cred->target);
  
 -    if (cred->password.value != NULL) {
 -        memset(cred->password.value, 0, cred->password.length);
 -        GSSEAP_FREE(cred->password.value);
 -    }
 +    zeroAndReleasePassword(&cred->password);
  
 -    if (cred->radiusConfigFile != NULL)
 -        GSSEAP_FREE(cred->radiusConfigFile);
 -    if (cred->radiusConfigStanza != NULL)
 -        GSSEAP_FREE(cred->radiusConfigStanza);
 +    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) {
  }
  
  static OM_uint32
 -readDefaultIdentityAndCreds(OM_uint32 *minor,
 -                            gss_buffer_t defaultIdentity,
 -                            gss_buffer_t defaultCreds)
 +readStaticIdentityFile(OM_uint32 *minor,
 +                       gss_buffer_t defaultIdentity,
 +                       gss_buffer_t defaultPassword)
  {
      OM_uint32 major, tmpMinor;
      FILE *fp = NULL;
      char buf[BUFSIZ];
      char *ccacheName;
 -#if !defined(WIN32)
 -    char pwbuf[BUFSIZ];
 +    int i = 0;
 +#ifndef WIN32
      struct passwd *pw = NULL, pwd;
 +    char pwbuf[BUFSIZ];
  #endif
  
      defaultIdentity->length = 0;
      defaultIdentity->value = NULL;
  
 -    defaultCreds->length = 0;
 -    defaultCreds->value = NULL;
 +    if (defaultPassword != GSS_C_NO_BUFFER) {
 +        defaultPassword->length = 0;
 +        defaultPassword->value = NULL;
 +    }
  
      ccacheName = getenv("GSSEAP_IDENTITY");
      if (ccacheName == NULL) {
 -#if !defined(WIN32)
 -        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
 -            pw == NULL || pw->pw_dir == NULL) {
 +#ifdef WIN32
 +        TCHAR szPath[MAX_PATH];
 +
 +        if (!SUCCEEDED(SHGetFolderPath(NULL,
 +                                       CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
 +                                       NULL, /* User access token */
-                                        0,
++                                       0,    /* SHGFP_TYPE_CURRENT */
 +                                       szPath))) {
              major = GSS_S_CRED_UNAVAIL;
-             *minor = GetLastError();
 -            *minor = errno;
++            *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
              goto cleanup;
          }
  
 -        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
 -        ccacheName = buf;
 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
  #else
 -      TCHAR szPath[MAX_PATH];
 -
 -      if(!SUCCEEDED(SHGetFolderPath(NULL,
 -                                    CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
 -                                    NULL, /* User access token */
 -                                    0,    /* == SHGFP_TYPE_CURRENT from ShlObj.h */
 -                                    szPath))) {
 +        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
 +            pw == NULL || pw->pw_dir == NULL) {
              major = GSS_S_CRED_UNAVAIL;
 -////Needs to be correctly converted from the GetLastError();
 -            *minor = errno;
 +            *minor = GSSEAP_GET_LAST_ERROR();
              goto cleanup;
 -      }
 +        }
  
 -        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
 +#endif /* WIN32 */
          ccacheName = buf;
 -#endif
      }
  
      fp = fopen(ccacheName, "r");
                  break;
          }
  
 -        if (defaultIdentity->value == NULL)
 +        if (i == 0)
              dst = defaultIdentity;
 -        else if (defaultCreds->value == NULL)
 -            dst = defaultCreds;
 +        else if (i == 1)
 +            dst = defaultPassword;
          else
              break;
  
 -        major = duplicateBuffer(minor, &src, dst);
 -        if (GSS_ERROR(major))
 -            goto cleanup;
 +        if (dst != GSS_C_NO_BUFFER) {
 +            major = duplicateBuffer(minor, &src, dst);
 +            if (GSS_ERROR(major))
 +                goto cleanup;
 +        }
 +
 +        i++;
      }
  
      if (defaultIdentity->length == 0) {
@@@ -229,29 -222,16 +230,29 @@@ cleanup
  
      if (GSS_ERROR(major)) {
          gss_release_buffer(&tmpMinor, defaultIdentity);
 -        gss_release_buffer(&tmpMinor, defaultCreds);
 +        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,
 -                  const gss_buffer_t password,
                    OM_uint32 timeReq GSSEAP_UNUSED,
                    const gss_OID_set desiredMechs,
                    int credUsage,
  {
      OM_uint32 major, tmpMinor;
      gss_cred_id_t cred;
 -    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
 -    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
 -    gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
 -    gss_OID nameMech = GSS_C_NO_OID;
  
      /* XXX TODO validate with changed set_cred_option API */
      *pCred = GSS_C_NO_CREDENTIAL;
      if (GSS_ERROR(major))
          goto cleanup;
  
 -    if (cred->mechanisms != GSS_C_NO_OID_SET &&
 -        cred->mechanisms->count == 1)
 -        nameMech = &cred->mechanisms->elements[0];
 -
 -    if (cred->flags & CRED_FLAG_INITIATE) {
 -        major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
 -        if (major == GSS_S_COMPLETE) {
 -            major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
 -                                     nameMech, &defaultIdentityName);
 -            if (GSS_ERROR(major))
 -                goto cleanup;
 -        } else if (major != GSS_S_CRED_UNAVAIL)
 -            goto cleanup;
 -    }
 -
      if (desiredName != GSS_C_NO_NAME) {
          GSSEAP_MUTEX_LOCK(&desiredName->mutex);
  
          }
  
          GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
 -
 -        if (defaultIdentityName != GSS_C_NO_NAME) {
 -            int nameEqual;
 -
 -            major = gssEapCompareName(minor, desiredName,
 -                                      defaultIdentityName, &nameEqual);
 -            if (GSS_ERROR(major))
 -                goto cleanup;
 -            else if (nameEqual)
 -                cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
 -        }
 -    } else {
 -        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) {
 -                major = GSS_S_FAILURE;
 -                *minor = GSSEAP_NO_HOSTNAME;
 -                goto cleanup;
 -            }
 -
 -            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))
 -                goto cleanup;
 -        } else if (cred->flags & CRED_FLAG_INITIATE) {
 -            if (defaultIdentityName == GSS_C_NO_NAME) {
 -                major = GSS_S_CRED_UNAVAIL;
 -                *minor = GSSEAP_NO_DEFAULT_IDENTITY;
 -                goto cleanup;
 -            }
 -
 -            cred->name = defaultIdentityName;
 -            defaultIdentityName = GSS_C_NO_NAME;
 -        }
 -        cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
 -    }
 -
 -    assert(cred->name != GSS_C_NO_NAME);
 -
 -    if (password != GSS_C_NO_BUFFER) {
 -        major = duplicateBuffer(minor, password, &cred->password);
 -        if (GSS_ERROR(major))
 -            goto cleanup;
 -
 -        cred->flags |= CRED_FLAG_PASSWORD;
 -    } else if (defaultCreds.value != NULL &&
 -        (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
 -        cred->password = defaultCreds;
 -
 -        defaultCreds.length = 0;
 -        defaultCreds.value = NULL;
 -
 -        cred->flags |= CRED_FLAG_PASSWORD;
 -    } else if (cred->flags & CRED_FLAG_INITIATE) {
 -        /*
 -         * OK, here we need to ask the supplicant if we have creds or it
 -         * will acquire them, so GS2 can know whether to prompt for a
 -         * password or not.
 -         */
 -#if 0
 -        && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
 -#endif
 -        major = GSS_S_CRED_UNAVAIL;
 -        *minor = GSSEAP_NO_DEFAULT_CRED;
 -        goto cleanup;
      }
  
      if (pActualMechs != NULL) {
  cleanup:
      if (GSS_ERROR(major))
          gssEapReleaseCred(&tmpMinor, &cred);
 -    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
 -    gss_release_buffer(&tmpMinor, &defaultIdentity);
 -    if (defaultCreds.value != NULL) {
 -        memset(defaultCreds.value, 0, defaultCreds.length);
 -        gss_release_buffer(&tmpMinor, &defaultCreds);
 -    }
  
      return major;
  }
@@@ -347,72 -424,6 +348,72 @@@ gssEapCredAvailable(gss_cred_id_t cred
      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,
      time_t now, lifetime;
  
      if (name != NULL) {
 -        major = gssEapDuplicateName(minor, cred->name, name);
 +        major = gssEapResolveCredIdentity(minor, cred);
          if (GSS_ERROR(major))
 -            return 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) {
          else
              major = gssEapIndicateMechs(minor, mechanisms);
          if (GSS_ERROR(major))
 -            return major;
 +            goto cleanup;
      }
  
      if (cred->expiryTime == 0) {
      }
  
      if (lifetime == 0) {
 +        major = GSS_S_CREDENTIALS_EXPIRED;
          *minor = GSSEAP_CRED_EXPIRED;
 -        return GSS_S_CREDENTIALS_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;
 +    }
 +
 +    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))
 +            goto cleanup;
 +
 +        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 --combined mech_eap/util_krb.c
@@@ -80,20 -80,20 +80,19 @@@ cleanup
  OM_uint32
  gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
  {
 -    struct gss_eap_thread_local_data* tld;
 +    struct gss_eap_thread_local_data *tld;
 +
      *minor = 0;
  
      tld = gssEapGetThreadLocalData();
 -    if (tld)
 -    {
 -        *context = tld->context;
 +    if (tld != NULL) {
 +        *context = tld->krbContext;
          if (*context == NULL) {
              *minor = initKrbContext(context);
 -            if (*minor == 0) {
 -                tld->context = *context;
 -            }
 +            if (*minor == 0)
 +                tld->krbContext = *context;
          }
      }
      return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
  }
  
@@@ -280,7 -280,7 +279,7 @@@ rfc3961ChecksumTypeForKey(OM_uint32 *mi
  #endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
  
      if (!krb5_c_is_keyed_cksum(*cksumtype)) {
 -        *minor = KRB5KRB_AP_ERR_INAPP_CKSUM;
 +        *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
          return GSS_S_FAILURE;
      }
  
diff --combined mech_eap/util_name.c
@@@ -81,7 -81,7 +81,7 @@@ gssEapAllocName(OM_uint32 *minor, gss_n
      }
  
      if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
 -        *minor = errno;
 +        *minor = GSSEAP_GET_LAST_ERROR();
          gssEapReleaseName(&tmpMinor, &name);
          return GSS_S_FAILURE;
      }
@@@ -112,7 -112,6 +112,6 @@@ gssEapReleaseName(OM_uint32 *minor, gss
      GSSEAP_KRB_INIT(&krbContext);
      krb5_free_principal(krbContext, name->krbPrincipal);
      gssEapReleaseOid(&tmpMinor, &name->mechanismUsed);
  #ifdef GSSEAP_ENABLE_ACCEPTOR
      gssEapReleaseAttrContext(&tmpMinor, name);
  #endif
@@@ -428,18 -427,19 +427,18 @@@ gssEapImportNameInternal(OM_uint32 *min
      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;
 -#ifdef GSSEAP_ENABLE_ACCEPTOR
 +
          major = gssEapImportAttrContext(minor, &buf, name);
 -#else
 -              major = GSS_S_UNAVAILABLE;
 -#endif
          if (GSS_ERROR(major))
              goto cleanup;
      }
 +#endif
  
      major = GSS_S_COMPLETE;
      *minor = 0;
@@@ -569,14 -569,16 +568,14 @@@ gssEapExportNameInternal(OM_uint32 *min
          exportedNameLen += 6 + mech->length;
      }
      exportedNameLen += 4 + nameBuf.length;
 -    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
  #ifdef GSSEAP_ENABLE_ACCEPTOR
 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
          major = gssEapExportAttrContext(minor, name, &attrs);
 -#else
 -              major = GSS_S_UNAVAILABLE;
 -#endif
          if (GSS_ERROR(major))
              goto cleanup;
          exportedNameLen += attrs.length;
      }
 +#endif
  
      exportedName->value = GSSEAP_MALLOC(exportedNameLen);
      if (exportedName->value == NULL) {
@@@ -676,13 -678,15 +675,13 @@@ gssEapCanonicalizeName(OM_uint32 *minor
          goto cleanup;
      }
  
 -    if (input_name->attrCtx != NULL) {
  #ifdef GSSEAP_ENABLE_ACCEPTOR
 +    if (input_name->attrCtx != NULL) {
          major = gssEapDuplicateAttrContext(minor, input_name, name);
 -#else
 -              major = GSS_S_UNAVAILABLE;
 -#endif
          if (GSS_ERROR(major))
              goto cleanup;
      }
 +#endif
  
      *dest_name = name;
  
diff --combined mech_eap/util_radius.h
@@@ -154,6 -154,7 +154,7 @@@ OM_uint3
  gssEapRadiusMapError(OM_uint32 *minor,
                       struct rs_error *err);
  
 -////This really need to be a function call on Windows
++/* 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_SAML_AAA_ASSERTION               132
  #define PW_MS_WINDOWS_AUTH_DATA             133
  
 -#define IS_RADIUS_ERROR(code)               ((code) >= ERROR_TABLE_BASE_rse && \
 -                                             (code) <= ERROR_TABLE_BASE_rse + RSE_TIMEOUT_IO)
 -
  #ifdef __cplusplus
  }
  #endif
diff --combined mech_eap/util_tld.c
   * SUCH DAMAGE.
   */
  
 -/* Access all thread-local data through these methods which 
 - * use pthreads to manage thread-local memory on Unix and TlsFoo() on Windows.
 - * This would be more flexible, scalable, and extensible 
 - * if implemented through a callback interface, but given that 
 - * there are currently only two 'clients', hard-coding seems more 
 - * straightforward
 +/*
-  * Thread local data abstraction.
++ * 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_datatld)
 +destroyThreadLocalData(struct gss_eap_thread_local_data *tld)
  {
 -    if (tld->status_info)
 -        gssEapDestroyStatusInfo(tld->status_info);
 -    if (tld->context)
 -        gssEapDestroyKrbContext(tld->context);
 +    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()
 +/*
 + * 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;
  
  /* Access thread-local data */
  struct gss_eap_thread_local_data *
 -gssEapGetThreadLocalData()
 +gssEapGetThreadLocalData(void)
  {
      return TlsGetValue(tlsIndex);
  }
 - 
 -/* DllMain() is the entry-point function for this DLL. */
 -BOOL WINAPI DllMain(HINSTANCE hDLL, /* DLL module handle */
 -    DWORD reason,                    /* reason called */
 -    LPVOID reserved)                 /* reserved */
 -{ 
 +
 +BOOL WINAPI
 +DllMain(HINSTANCE hDLL,     /* DLL module handle */
 +        DWORD reason,       /* reason called */
 +        LPVOID reserved)    /* reserved */
 +{
      struct gss_eap_thread_local_data *tlsData;
  
 -    switch (reason) 
 -    { 
 -        // The DLL is loading due to process 
 -        // initialization or a call to LoadLibrary. 
 -        case DLL_PROCESS_ATTACH: 
 +    switch (reason) {
 +        case DLL_PROCESS_ATTACH:
              /* Allocate a TLS index. */
 -            if ((tlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
 -                return FALSE; 
 +            gssEapInitiatorInit();
 +            tlsIndex = TlsAlloc();
 +            if (tlsIndex == TLS_OUT_OF_INDEXES)
 +                return FALSE;
              /* No break: Initialize the index for first thread.*/
 - 
 -        /* The attached process creates a new thread. */
 -        case DLL_THREAD_ATTACH: 
 +        case DLL_THREAD_ATTACH:
              /* Initialize the TLS index for this thread. */
              tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
 -            if (tlsData != NULL) 
 -                TlsSetValue(tlsIndex, tlsData); 
 - 
 -            break; 
 - 
 -        /* The thread of the attached process terminates. */
 -        case DLL_THREAD_DETACH: 
 +            if (tlsData != NULL)
 +                TlsSetValue(tlsIndex, tlsData);
 +            break;
 +        case DLL_THREAD_DETACH:
              /* Release the allocated memory for this thread. */
 -            tlsData = TlsGetValue(tlsIndex); 
 -            if (tlsData != NULL) 
 -            {
 -                destroyThreadLocalData(tlsData); 
 +            tlsData = TlsGetValue(tlsIndex);
 +            if (tlsData != NULL) {
 +                destroyThreadLocalData(tlsData);
                  TlsSetValue(tlsIndex, NULL);
              }
 - 
 -            break; 
 - 
 -        /* DLL unload due to process termination or FreeLibrary. */
 -        case DLL_PROCESS_DETACH: 
 +            break;
 +        case DLL_PROCESS_DETACH:
              /* Release the allocated memory for this thread. */
 -            tlsData = TlsGetValue(tlsIndex); 
 -            if (tlsData != NULL) 
 -                destroyThreadLocalData(tlsData); 
 +            tlsData = TlsGetValue(tlsIndex);
 +            if (tlsData != NULL)
 +                destroyThreadLocalData(tlsData);
              /* Release the TLS index. */
 -            TlsFree(tlsIndex); 
 -            break; 
 - 
 -        default: 
 -            break; 
 -    } 
 - 
 -    return TRUE; 
 -    UNREFERENCED_PARAMETER(hDLL); 
 -    UNREFERENCED_PARAMETER(reserved); 
 +            TlsFree(tlsIndex);
 +            gssEapFinalize();
 +            break;
 +        default:
 +            break;
 +    }
 +
 +    return TRUE;
 +    UNREFERENCED_PARAMETER(hDLL);
 +    UNREFERENCED_PARAMETER(reserved);
  }
  
  #else /* WIN32 */
  
 -/* PTHREAD implementation */
 +/* pthreads implementation */
 +
  static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER;
  static GSSEAP_THREAD_KEY tldKey;
 -static void 
 -pthreadDestroyThreadLocalData(void* arg)
 +
 +static void
 +pthreadDestroyThreadLocalData(void *arg)
  {
      struct gss_eap_thread_local_data* tld = arg;
 -    if (tld)
 -    {
 +
 +    if (tld != NULL)
          destroyThreadLocalData(tld);
 -    }
  }
  
 -static void 
 +static void
  createThreadLocalDataKey(void)
  {
      GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData);
  }
  
 -struct gss_eap_thread_local_data * 
 +struct gss_eap_thread_local_data *
  gssEapGetThreadLocalData()
  {
      struct gss_eap_thread_local_data *tld;
 +
      GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey);
 +
      tld = GSSEAP_GETSPECIFIC(tldKey);
 -    if (!tld)
 -    {
 +    if (tld == NULL) {
          tld = GSSEAP_CALLOC(1, sizeof(*tld));
 +        if (tld == NULL)
 +            return NULL;
 +
          GSSEAP_SETSPECIFIC(tldKey, tld);
      }
 +
      return tld;
  }
  #endif /* WIN32 */