From: Sam hartman Date: Fri, 16 Sep 2011 18:56:38 +0000 (+0100) Subject: Update libeap to include make dist X-Git-Tag: 0.9.2~122^2~1 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=commitdiff_plain;h=527a687917e60958777a01ca7a458888bee341b8;hp=3c6800594dbfcba5d36cfa5556288eae999f83ba Update libeap to include make dist --- diff --git a/.gitignore b/.gitignore index 4a1ad86..c4992b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,12 @@ -*.o -*.d -*~ -wpa_supplicant/eapol_test -wpa_supplicant/preauth_test -wpa_supplicant/wpa_cli -wpa_supplicant/wpa_passphrase -wpa_supplicant/wpa_supplicant -wpa_supplicant/wpa_priv -wpa_supplicant/wpa_gui/Makefile -wpa_supplicant/wpa_gui/wpa_gui -wpa_supplicant/wpa_gui-qt4/Makefile -wpa_supplicant/wpa_gui-qt4/wpa_gui -hostapd/hostapd -hostapd/hostapd_cli -hostapd/hlr_auc_gw -hostapd/nt_password_hash +Makefile.in +aclocal.m4 +autom4te.cache +configure +config.* +ltmain.sh +libtool +depcomp +m4 +!m4/minuso.m4 +build-aux +!build-aux/compile diff --git a/Makefile.am b/Makefile.am index 163e4ff..b4ca11c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,211 +1,3 @@ AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils -noinst_HEADERS = \ - src/common/defs.h \ - src/common/eapol_common.h \ - src/common/ieee802_11_common.h \ - src/common/ieee802_11_defs.h \ - src/common/privsep_commands.h \ - src/common/version.h \ - src/common/wpa_common.h \ - src/common/wpa_ctrl.h - -EXTRA_DIST = src/tls/libtommath.c - -SOURCES_BOTH = src/eap_common/eap_peap_common.c -SOURCES_BOTH += src/eap_common/eap_psk_common.c -SOURCES_BOTH += src/eap_common/eap_pax_common.c -SOURCES_BOTH += src/eap_common/eap_sake_common.c -SOURCES_BOTH += src/eap_common/eap_gpsk_common.c -SOURCES_BOTH += src/eap_common/chap.c \ -src/eap_common/chap.h \ - src/eap_common/eap_common.h \ - src/eap_common/eap_defs.h \ - src/eap_common/eap_fast_common.h \ - src/eap_common/eap_gpsk_common.h \ - src/eap_common/eap_ikev2_common.h \ - src/eap_common/eap_pax_common.h \ - src/eap_common/eap_peap_common.h \ - src/eap_common/eap_psk_common.h \ - src/eap_common/eap_pwd_common.h \ - src/eap_common/eap_sake_common.h \ - src/eap_common/eap_sim_common.h \ - src/eap_common/eap_tlv_common.h \ - src/eap_common/eap_ttls.h \ - src/eap_common/eap_wsc_common.h \ - src/eap_common/ikev2_common.h - - -SOURCES_peer = src/eap_peer/eap_tls.c -SOURCES_peer += src/eap_peer/eap_peap.c -SOURCES_peer += src/eap_peer/eap_ttls.c -SOURCES_peer += src/eap_peer/eap_md5.c -SOURCES_peer += src/eap_peer/eap_mschapv2.c -SOURCES_peer += src/eap_peer/mschapv2.c -SOURCES_peer += src/eap_peer/eap_otp.c -SOURCES_peer += src/eap_peer/eap_gtc.c -SOURCES_peer += src/eap_peer/eap_leap.c -SOURCES_peer += src/eap_peer/eap_psk.c -SOURCES_peer += src/eap_peer/eap_pax.c -SOURCES_peer += src/eap_peer/eap_sake.c -SOURCES_peer += src/eap_peer/eap_gpsk.c -SOURCES_peer += src/eap_peer/eap.c -SOURCES_peer += src/eap_common/eap_common.c -SOURCES_peer += src/eap_peer/eap_methods.c -SOURCES_peer += src/eap_peer/eap_tls_common.c \ - src/eap_peer/eap_config.h \ - src/eap_peer/eap_fast_pac.h \ - src/eap_peer/eap.h \ - src/eap_peer/eap_i.h \ - src/eap_peer/eap_methods.h \ - src/eap_peer/eap_tls_common.h \ - src/eap_peer/ikev2.h \ - src/eap_peer/mschapv2.h \ - src/eap_peer/tncc.h - -CFLAGS += -DEAP_TLS -CFLAGS += -DEAP_PEAP -CFLAGS += -DEAP_TTLS -CFLAGS += -DEAP_MD5 -CFLAGS += -DEAP_MSCHAPv2 -CFLAGS += -DEAP_GTC -CFLAGS += -DEAP_OTP -CFLAGS += -DEAP_LEAP -CFLAGS += -DEAP_PSK -CFLAGS += -DEAP_PAX -CFLAGS += -DEAP_SAKE -CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256 - -CFLAGS += -DEAP_SERVER_IDENTITY -CFLAGS += -DEAP_SERVER_TLS -CFLAGS += -DEAP_SERVER_PEAP -CFLAGS += -DEAP_SERVER_TTLS -CFLAGS += -DEAP_SERVER_MD5 -CFLAGS += -DEAP_SERVER_MSCHAPV2 -CFLAGS += -DEAP_SERVER_GTC -CFLAGS += -DEAP_SERVER_PSK -CFLAGS += -DEAP_SERVER_PAX -CFLAGS += -DEAP_SERVER_SAKE -CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 - -CFLAGS += -DIEEE8021X_EAPOL -CFLAGS += -DCONFIG_IPV6 - -CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -CFLAGS += -DCONFIG_CRYPTO_INTERNAL -CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT - -UTILS_SRCS = src/utils/base64.c \ - src/utils/common.c \ - src/utils/ip_addr.c \ - src/utils/radiotap.c \ - src/utils/trace.c \ - src/utils/uuid.c \ - src/utils/wpa_debug.c \ - src/utils/wpabuf.c \ - src/utils/os_unix.c \ - src/utils/base64.h \ - src/utils/build_config.h \ - src/utils/common.h \ - src/utils/eloop.h \ - src/utils/includes.h \ - src/utils/ip_addr.h \ - src/utils/list.h \ - src/utils/os.h \ - src/utils/pcsc_funcs.h \ - src/utils/radiotap.h \ - src/utils/radiotap_iter.h \ - src/utils/state_machine.h \ - src/utils/trace.h \ - src/utils/uuid.h \ - src/utils/wpabuf.h \ - src/utils/wpa_debug.h - - -CRYPTO_SRCS = \ - src/crypto/aes-cbc.c \ - src/crypto/aes-ctr.c \ - src/crypto/aes-eax.c \ - src/crypto/aes-encblock.c \ - src/crypto/aes-internal.c \ - src/crypto/aes-internal-dec.c \ - src/crypto/aes-internal-enc.c \ - src/crypto/aes-omac1.c \ - src/crypto/aes-unwrap.c \ - src/crypto/aes-wrap.c \ - src/crypto/des-internal.c \ - src/crypto/dh_group5.c \ - src/crypto/dh_groups.c \ - src/crypto/md4-internal.c \ - src/crypto/md5.c \ - src/crypto/md5-internal.c \ - src/crypto/md5-non-fips.c \ - src/crypto/milenage.c \ - src/crypto/ms_funcs.c \ - src/crypto/rc4.c \ - src/crypto/sha1.c \ - src/crypto/sha1-internal.c \ - src/crypto/sha1-pbkdf2.c \ - src/crypto/sha1-tlsprf.c \ - src/crypto/sha1-tprf.c \ - src/crypto/sha256.c \ - src/crypto/sha256-internal.c \ - src/crypto/crypto_internal.c \ - src/crypto/crypto_internal-cipher.c \ - src/crypto/crypto_internal-modexp.c \ - src/crypto/crypto_internal-rsa.c \ - src/crypto/tls_internal.c \ - src/crypto/fips_prf_internal.c \ - src/crypto/aes.h \ - src/crypto/aes_i.h \ - src/crypto/aes_wrap.h \ - src/crypto/crypto.h \ - src/crypto/des_i.h \ - src/crypto/dh_group5.h \ - src/crypto/dh_groups.h \ - src/crypto/md5.h \ - src/crypto/md5_i.h \ - src/crypto/milenage.h \ - src/crypto/ms_funcs.h \ - src/crypto/sha1.h \ - src/crypto/sha1_i.h \ - src/crypto/sha256.h \ - src/crypto/tls.h - - -TLS_SRCS = \ - src/tls/asn1.c \ - src/tls/bignum.c \ - src/tls/pkcs1.c \ - src/tls/pkcs5.c \ - src/tls/pkcs8.c \ - src/tls/rsa.c \ - src/tls/tlsv1_client.c \ - src/tls/tlsv1_client_read.c \ - src/tls/tlsv1_client_write.c \ - src/tls/tlsv1_common.c \ - src/tls/tlsv1_cred.c \ - src/tls/tlsv1_record.c \ - src/tls/tlsv1_server.c \ - src/tls/tlsv1_server_read.c \ - src/tls/tlsv1_server_write.c \ - src/tls/x509v3.c \ - src/tls/asn1.h \ - src/tls/bignum.h \ - src/tls/pkcs1.h \ - src/tls/pkcs5.h \ - src/tls/pkcs8.h \ - src/tls/rsa.h \ - src/tls/tlsv1_client.h \ - src/tls/tlsv1_client_i.h \ - src/tls/tlsv1_common.h \ - src/tls/tlsv1_cred.h \ - src/tls/tlsv1_record.h \ - src/tls/tlsv1_server.h \ - src/tls/tlsv1_server_i.h \ - src/tls/x509v3.h - -libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) $(TLS_SRCS) - -noinst_LTLIBRARIES = libeap.la +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = libeap mech_eap diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..a626e8a --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,366 @@ +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 /usr/local ; 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_LIBS="-L$check_krb5_dir/lib/ -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_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_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= +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 --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..bac481c --- /dev/null +++ b/build-aux/compile @@ -0,0 +1,310 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2010-11-15.09; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010 Free Software +# Foundation, Inc. +# Written by Tom Tromey . +# +# 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, see . + +# 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 or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Win32 hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + 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'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l*) + lib=${1#-l} + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + set x "$@" "$dir/$lib.dll.lib" + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + set x "$@" "$dir/$lib.lib" + break + fi + done + IFS=$save_IFS + + test "$found" != yes && set x "$@" "$lib.lib" + shift + ;; + -L*) + func_file_conv "${1#-L}" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +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 . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +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..ab84b42 --- /dev/null +++ b/configure.ac @@ -0,0 +1,91 @@ +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]) +AC_OUTPUT diff --git a/libeap/.gitignore b/libeap/.gitignore new file mode 100644 index 0000000..4a1ad86 --- /dev/null +++ b/libeap/.gitignore @@ -0,0 +1,17 @@ +*.o +*.d +*~ +wpa_supplicant/eapol_test +wpa_supplicant/preauth_test +wpa_supplicant/wpa_cli +wpa_supplicant/wpa_passphrase +wpa_supplicant/wpa_supplicant +wpa_supplicant/wpa_priv +wpa_supplicant/wpa_gui/Makefile +wpa_supplicant/wpa_gui/wpa_gui +wpa_supplicant/wpa_gui-qt4/Makefile +wpa_supplicant/wpa_gui-qt4/wpa_gui +hostapd/hostapd +hostapd/hostapd_cli +hostapd/hlr_auc_gw +hostapd/nt_password_hash diff --git a/COPYING b/libeap/COPYING similarity index 100% rename from COPYING rename to libeap/COPYING diff --git a/FAQ b/libeap/FAQ similarity index 100% rename from FAQ rename to libeap/FAQ diff --git a/libeap/Makefile.am b/libeap/Makefile.am new file mode 100644 index 0000000..163e4ff --- /dev/null +++ b/libeap/Makefile.am @@ -0,0 +1,211 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils +noinst_HEADERS = \ + src/common/defs.h \ + src/common/eapol_common.h \ + src/common/ieee802_11_common.h \ + src/common/ieee802_11_defs.h \ + src/common/privsep_commands.h \ + src/common/version.h \ + src/common/wpa_common.h \ + src/common/wpa_ctrl.h + +EXTRA_DIST = src/tls/libtommath.c + +SOURCES_BOTH = src/eap_common/eap_peap_common.c +SOURCES_BOTH += src/eap_common/eap_psk_common.c +SOURCES_BOTH += src/eap_common/eap_pax_common.c +SOURCES_BOTH += src/eap_common/eap_sake_common.c +SOURCES_BOTH += src/eap_common/eap_gpsk_common.c +SOURCES_BOTH += src/eap_common/chap.c \ +src/eap_common/chap.h \ + src/eap_common/eap_common.h \ + src/eap_common/eap_defs.h \ + src/eap_common/eap_fast_common.h \ + src/eap_common/eap_gpsk_common.h \ + src/eap_common/eap_ikev2_common.h \ + src/eap_common/eap_pax_common.h \ + src/eap_common/eap_peap_common.h \ + src/eap_common/eap_psk_common.h \ + src/eap_common/eap_pwd_common.h \ + src/eap_common/eap_sake_common.h \ + src/eap_common/eap_sim_common.h \ + src/eap_common/eap_tlv_common.h \ + src/eap_common/eap_ttls.h \ + src/eap_common/eap_wsc_common.h \ + src/eap_common/ikev2_common.h + + +SOURCES_peer = src/eap_peer/eap_tls.c +SOURCES_peer += src/eap_peer/eap_peap.c +SOURCES_peer += src/eap_peer/eap_ttls.c +SOURCES_peer += src/eap_peer/eap_md5.c +SOURCES_peer += src/eap_peer/eap_mschapv2.c +SOURCES_peer += src/eap_peer/mschapv2.c +SOURCES_peer += src/eap_peer/eap_otp.c +SOURCES_peer += src/eap_peer/eap_gtc.c +SOURCES_peer += src/eap_peer/eap_leap.c +SOURCES_peer += src/eap_peer/eap_psk.c +SOURCES_peer += src/eap_peer/eap_pax.c +SOURCES_peer += src/eap_peer/eap_sake.c +SOURCES_peer += src/eap_peer/eap_gpsk.c +SOURCES_peer += src/eap_peer/eap.c +SOURCES_peer += src/eap_common/eap_common.c +SOURCES_peer += src/eap_peer/eap_methods.c +SOURCES_peer += src/eap_peer/eap_tls_common.c \ + src/eap_peer/eap_config.h \ + src/eap_peer/eap_fast_pac.h \ + src/eap_peer/eap.h \ + src/eap_peer/eap_i.h \ + src/eap_peer/eap_methods.h \ + src/eap_peer/eap_tls_common.h \ + src/eap_peer/ikev2.h \ + src/eap_peer/mschapv2.h \ + src/eap_peer/tncc.h + +CFLAGS += -DEAP_TLS +CFLAGS += -DEAP_PEAP +CFLAGS += -DEAP_TTLS +CFLAGS += -DEAP_MD5 +CFLAGS += -DEAP_MSCHAPv2 +CFLAGS += -DEAP_GTC +CFLAGS += -DEAP_OTP +CFLAGS += -DEAP_LEAP +CFLAGS += -DEAP_PSK +CFLAGS += -DEAP_PAX +CFLAGS += -DEAP_SAKE +CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256 + +CFLAGS += -DEAP_SERVER_IDENTITY +CFLAGS += -DEAP_SERVER_TLS +CFLAGS += -DEAP_SERVER_PEAP +CFLAGS += -DEAP_SERVER_TTLS +CFLAGS += -DEAP_SERVER_MD5 +CFLAGS += -DEAP_SERVER_MSCHAPV2 +CFLAGS += -DEAP_SERVER_GTC +CFLAGS += -DEAP_SERVER_PSK +CFLAGS += -DEAP_SERVER_PAX +CFLAGS += -DEAP_SERVER_SAKE +CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 + +CFLAGS += -DIEEE8021X_EAPOL +CFLAGS += -DCONFIG_IPV6 + +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT + +UTILS_SRCS = src/utils/base64.c \ + src/utils/common.c \ + src/utils/ip_addr.c \ + src/utils/radiotap.c \ + src/utils/trace.c \ + src/utils/uuid.c \ + src/utils/wpa_debug.c \ + src/utils/wpabuf.c \ + src/utils/os_unix.c \ + src/utils/base64.h \ + src/utils/build_config.h \ + src/utils/common.h \ + src/utils/eloop.h \ + src/utils/includes.h \ + src/utils/ip_addr.h \ + src/utils/list.h \ + src/utils/os.h \ + src/utils/pcsc_funcs.h \ + src/utils/radiotap.h \ + src/utils/radiotap_iter.h \ + src/utils/state_machine.h \ + src/utils/trace.h \ + src/utils/uuid.h \ + src/utils/wpabuf.h \ + src/utils/wpa_debug.h + + +CRYPTO_SRCS = \ + src/crypto/aes-cbc.c \ + src/crypto/aes-ctr.c \ + src/crypto/aes-eax.c \ + src/crypto/aes-encblock.c \ + src/crypto/aes-internal.c \ + src/crypto/aes-internal-dec.c \ + src/crypto/aes-internal-enc.c \ + src/crypto/aes-omac1.c \ + src/crypto/aes-unwrap.c \ + src/crypto/aes-wrap.c \ + src/crypto/des-internal.c \ + src/crypto/dh_group5.c \ + src/crypto/dh_groups.c \ + src/crypto/md4-internal.c \ + src/crypto/md5.c \ + src/crypto/md5-internal.c \ + src/crypto/md5-non-fips.c \ + src/crypto/milenage.c \ + src/crypto/ms_funcs.c \ + src/crypto/rc4.c \ + src/crypto/sha1.c \ + src/crypto/sha1-internal.c \ + src/crypto/sha1-pbkdf2.c \ + src/crypto/sha1-tlsprf.c \ + src/crypto/sha1-tprf.c \ + src/crypto/sha256.c \ + src/crypto/sha256-internal.c \ + src/crypto/crypto_internal.c \ + src/crypto/crypto_internal-cipher.c \ + src/crypto/crypto_internal-modexp.c \ + src/crypto/crypto_internal-rsa.c \ + src/crypto/tls_internal.c \ + src/crypto/fips_prf_internal.c \ + src/crypto/aes.h \ + src/crypto/aes_i.h \ + src/crypto/aes_wrap.h \ + src/crypto/crypto.h \ + src/crypto/des_i.h \ + src/crypto/dh_group5.h \ + src/crypto/dh_groups.h \ + src/crypto/md5.h \ + src/crypto/md5_i.h \ + src/crypto/milenage.h \ + src/crypto/ms_funcs.h \ + src/crypto/sha1.h \ + src/crypto/sha1_i.h \ + src/crypto/sha256.h \ + src/crypto/tls.h + + +TLS_SRCS = \ + src/tls/asn1.c \ + src/tls/bignum.c \ + src/tls/pkcs1.c \ + src/tls/pkcs5.c \ + src/tls/pkcs8.c \ + src/tls/rsa.c \ + src/tls/tlsv1_client.c \ + src/tls/tlsv1_client_read.c \ + src/tls/tlsv1_client_write.c \ + src/tls/tlsv1_common.c \ + src/tls/tlsv1_cred.c \ + src/tls/tlsv1_record.c \ + src/tls/tlsv1_server.c \ + src/tls/tlsv1_server_read.c \ + src/tls/tlsv1_server_write.c \ + src/tls/x509v3.c \ + src/tls/asn1.h \ + src/tls/bignum.h \ + src/tls/pkcs1.h \ + src/tls/pkcs5.h \ + src/tls/pkcs8.h \ + src/tls/rsa.h \ + src/tls/tlsv1_client.h \ + src/tls/tlsv1_client_i.h \ + src/tls/tlsv1_common.h \ + src/tls/tlsv1_cred.h \ + src/tls/tlsv1_record.h \ + src/tls/tlsv1_server.h \ + src/tls/tlsv1_server_i.h \ + src/tls/x509v3.h + +libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) $(TLS_SRCS) + +noinst_LTLIBRARIES = libeap.la diff --git a/README b/libeap/README similarity index 100% rename from README rename to libeap/README diff --git a/build_nsis.sh b/libeap/build_nsis.sh similarity index 100% rename from build_nsis.sh rename to libeap/build_nsis.sh diff --git a/build_release b/libeap/build_release similarity index 100% rename from build_release rename to libeap/build_release diff --git a/doc/.gitignore b/libeap/doc/.gitignore similarity index 100% rename from doc/.gitignore rename to libeap/doc/.gitignore diff --git a/doc/Makefile b/libeap/doc/Makefile similarity index 100% rename from doc/Makefile rename to libeap/doc/Makefile diff --git a/doc/code_structure.doxygen b/libeap/doc/code_structure.doxygen similarity index 100% rename from doc/code_structure.doxygen rename to libeap/doc/code_structure.doxygen diff --git a/doc/ctrl_iface.doxygen b/libeap/doc/ctrl_iface.doxygen similarity index 100% rename from doc/ctrl_iface.doxygen rename to libeap/doc/ctrl_iface.doxygen diff --git a/doc/dbus.doxygen b/libeap/doc/dbus.doxygen similarity index 100% rename from doc/dbus.doxygen rename to libeap/doc/dbus.doxygen diff --git a/doc/directories.doxygen b/libeap/doc/directories.doxygen similarity index 100% rename from doc/directories.doxygen rename to libeap/doc/directories.doxygen diff --git a/doc/doxygen.conf b/libeap/doc/doxygen.conf similarity index 100% rename from doc/doxygen.conf rename to libeap/doc/doxygen.conf diff --git a/doc/driver_wrapper.doxygen b/libeap/doc/driver_wrapper.doxygen similarity index 100% rename from doc/driver_wrapper.doxygen rename to libeap/doc/driver_wrapper.doxygen diff --git a/doc/eap.doxygen b/libeap/doc/eap.doxygen similarity index 100% rename from doc/eap.doxygen rename to libeap/doc/eap.doxygen diff --git a/doc/eap_server.doxygen b/libeap/doc/eap_server.doxygen similarity index 100% rename from doc/eap_server.doxygen rename to libeap/doc/eap_server.doxygen diff --git a/doc/hostapd.fig b/libeap/doc/hostapd.fig similarity index 100% rename from doc/hostapd.fig rename to libeap/doc/hostapd.fig diff --git a/doc/hostapd_ctrl_iface.doxygen b/libeap/doc/hostapd_ctrl_iface.doxygen similarity index 100% rename from doc/hostapd_ctrl_iface.doxygen rename to libeap/doc/hostapd_ctrl_iface.doxygen diff --git a/doc/kerneldoc2doxygen.pl b/libeap/doc/kerneldoc2doxygen.pl similarity index 100% rename from doc/kerneldoc2doxygen.pl rename to libeap/doc/kerneldoc2doxygen.pl diff --git a/doc/mainpage.doxygen b/libeap/doc/mainpage.doxygen similarity index 100% rename from doc/mainpage.doxygen rename to libeap/doc/mainpage.doxygen diff --git a/doc/porting.doxygen b/libeap/doc/porting.doxygen similarity index 100% rename from doc/porting.doxygen rename to libeap/doc/porting.doxygen diff --git a/doc/testing_tools.doxygen b/libeap/doc/testing_tools.doxygen similarity index 100% rename from doc/testing_tools.doxygen rename to libeap/doc/testing_tools.doxygen diff --git a/doc/wpa_supplicant.fig b/libeap/doc/wpa_supplicant.fig similarity index 100% rename from doc/wpa_supplicant.fig rename to libeap/doc/wpa_supplicant.fig diff --git a/eap_example/.gitignore b/libeap/eap_example/.gitignore similarity index 100% rename from eap_example/.gitignore rename to libeap/eap_example/.gitignore diff --git a/eap_example/Makefile b/libeap/eap_example/Makefile similarity index 100% rename from eap_example/Makefile rename to libeap/eap_example/Makefile diff --git a/eap_example/README b/libeap/eap_example/README similarity index 100% rename from eap_example/README rename to libeap/eap_example/README diff --git a/eap_example/ca.pem b/libeap/eap_example/ca.pem similarity index 100% rename from eap_example/ca.pem rename to libeap/eap_example/ca.pem diff --git a/eap_example/eap_example.c b/libeap/eap_example/eap_example.c similarity index 100% rename from eap_example/eap_example.c rename to libeap/eap_example/eap_example.c diff --git a/eap_example/eap_example_peer.c b/libeap/eap_example/eap_example_peer.c similarity index 100% rename from eap_example/eap_example_peer.c rename to libeap/eap_example/eap_example_peer.c diff --git a/eap_example/eap_example_server.c b/libeap/eap_example/eap_example_server.c similarity index 100% rename from eap_example/eap_example_server.c rename to libeap/eap_example/eap_example_server.c diff --git a/eap_example/server-key.pem b/libeap/eap_example/server-key.pem similarity index 100% rename from eap_example/server-key.pem rename to libeap/eap_example/server-key.pem diff --git a/eap_example/server.key b/libeap/eap_example/server.key similarity index 100% rename from eap_example/server.key rename to libeap/eap_example/server.key diff --git a/eap_example/server.pem b/libeap/eap_example/server.pem similarity index 100% rename from eap_example/server.pem rename to libeap/eap_example/server.pem diff --git a/hostapd/ChangeLog b/libeap/hostapd/ChangeLog similarity index 100% rename from hostapd/ChangeLog rename to libeap/hostapd/ChangeLog diff --git a/hostapd/Makefile b/libeap/hostapd/Makefile similarity index 100% rename from hostapd/Makefile rename to libeap/hostapd/Makefile diff --git a/hostapd/README b/libeap/hostapd/README similarity index 100% rename from hostapd/README rename to libeap/hostapd/README diff --git a/hostapd/README-WPS b/libeap/hostapd/README-WPS similarity index 100% rename from hostapd/README-WPS rename to libeap/hostapd/README-WPS diff --git a/hostapd/config_file.c b/libeap/hostapd/config_file.c similarity index 100% rename from hostapd/config_file.c rename to libeap/hostapd/config_file.c diff --git a/hostapd/config_file.h b/libeap/hostapd/config_file.h similarity index 100% rename from hostapd/config_file.h rename to libeap/hostapd/config_file.h diff --git a/hostapd/ctrl_iface.c b/libeap/hostapd/ctrl_iface.c similarity index 100% rename from hostapd/ctrl_iface.c rename to libeap/hostapd/ctrl_iface.c diff --git a/hostapd/ctrl_iface.h b/libeap/hostapd/ctrl_iface.h similarity index 100% rename from hostapd/ctrl_iface.h rename to libeap/hostapd/ctrl_iface.h diff --git a/hostapd/defconfig b/libeap/hostapd/defconfig similarity index 100% rename from hostapd/defconfig rename to libeap/hostapd/defconfig diff --git a/hostapd/dump_state.c b/libeap/hostapd/dump_state.c similarity index 100% rename from hostapd/dump_state.c rename to libeap/hostapd/dump_state.c diff --git a/hostapd/dump_state.h b/libeap/hostapd/dump_state.h similarity index 100% rename from hostapd/dump_state.h rename to libeap/hostapd/dump_state.h diff --git a/hostapd/eap_register.c b/libeap/hostapd/eap_register.c similarity index 100% rename from hostapd/eap_register.c rename to libeap/hostapd/eap_register.c diff --git a/hostapd/eap_register.h b/libeap/hostapd/eap_register.h similarity index 100% rename from hostapd/eap_register.h rename to libeap/hostapd/eap_register.h diff --git a/hostapd/eap_testing.txt b/libeap/hostapd/eap_testing.txt similarity index 100% rename from hostapd/eap_testing.txt rename to libeap/hostapd/eap_testing.txt diff --git a/hostapd/hlr_auc_gw.c b/libeap/hostapd/hlr_auc_gw.c similarity index 100% rename from hostapd/hlr_auc_gw.c rename to libeap/hostapd/hlr_auc_gw.c diff --git a/hostapd/hlr_auc_gw.milenage_db b/libeap/hostapd/hlr_auc_gw.milenage_db similarity index 100% rename from hostapd/hlr_auc_gw.milenage_db rename to libeap/hostapd/hlr_auc_gw.milenage_db diff --git a/hostapd/hostapd.8 b/libeap/hostapd/hostapd.8 similarity index 100% rename from hostapd/hostapd.8 rename to libeap/hostapd/hostapd.8 diff --git a/hostapd/hostapd.accept b/libeap/hostapd/hostapd.accept similarity index 100% rename from hostapd/hostapd.accept rename to libeap/hostapd/hostapd.accept diff --git a/hostapd/hostapd.conf b/libeap/hostapd/hostapd.conf similarity index 100% rename from hostapd/hostapd.conf rename to libeap/hostapd/hostapd.conf diff --git a/hostapd/hostapd.deny b/libeap/hostapd/hostapd.deny similarity index 100% rename from hostapd/hostapd.deny rename to libeap/hostapd/hostapd.deny diff --git a/hostapd/hostapd.eap_user b/libeap/hostapd/hostapd.eap_user similarity index 100% rename from hostapd/hostapd.eap_user rename to libeap/hostapd/hostapd.eap_user diff --git a/hostapd/hostapd.radius_clients b/libeap/hostapd/hostapd.radius_clients similarity index 100% rename from hostapd/hostapd.radius_clients rename to libeap/hostapd/hostapd.radius_clients diff --git a/hostapd/hostapd.sim_db b/libeap/hostapd/hostapd.sim_db similarity index 100% rename from hostapd/hostapd.sim_db rename to libeap/hostapd/hostapd.sim_db diff --git a/hostapd/hostapd.vlan b/libeap/hostapd/hostapd.vlan similarity index 100% rename from hostapd/hostapd.vlan rename to libeap/hostapd/hostapd.vlan diff --git a/hostapd/hostapd.wpa_psk b/libeap/hostapd/hostapd.wpa_psk similarity index 100% rename from hostapd/hostapd.wpa_psk rename to libeap/hostapd/hostapd.wpa_psk diff --git a/hostapd/hostapd_cli.1 b/libeap/hostapd/hostapd_cli.1 similarity index 100% rename from hostapd/hostapd_cli.1 rename to libeap/hostapd/hostapd_cli.1 diff --git a/hostapd/hostapd_cli.c b/libeap/hostapd/hostapd_cli.c similarity index 100% rename from hostapd/hostapd_cli.c rename to libeap/hostapd/hostapd_cli.c diff --git a/hostapd/logwatch/README b/libeap/hostapd/logwatch/README similarity index 100% rename from hostapd/logwatch/README rename to libeap/hostapd/logwatch/README diff --git a/hostapd/logwatch/hostapd b/libeap/hostapd/logwatch/hostapd similarity index 100% rename from hostapd/logwatch/hostapd rename to libeap/hostapd/logwatch/hostapd diff --git a/hostapd/logwatch/hostapd.conf b/libeap/hostapd/logwatch/hostapd.conf similarity index 100% rename from hostapd/logwatch/hostapd.conf rename to libeap/hostapd/logwatch/hostapd.conf diff --git a/hostapd/main.c b/libeap/hostapd/main.c similarity index 100% rename from hostapd/main.c rename to libeap/hostapd/main.c diff --git a/hostapd/nt_password_hash.c b/libeap/hostapd/nt_password_hash.c similarity index 100% rename from hostapd/nt_password_hash.c rename to libeap/hostapd/nt_password_hash.c diff --git a/hostapd/wired.conf b/libeap/hostapd/wired.conf similarity index 100% rename from hostapd/wired.conf rename to libeap/hostapd/wired.conf diff --git a/mac80211_hwsim/README b/libeap/mac80211_hwsim/README similarity index 100% rename from mac80211_hwsim/README rename to libeap/mac80211_hwsim/README diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf b/libeap/mac80211_hwsim/hostapd.conf similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf rename to libeap/mac80211_hwsim/hostapd.conf diff --git a/mac80211_hwsim/hostapd.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf similarity index 100% rename from mac80211_hwsim/hostapd.conf rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/test.txt b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/test.txt rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt diff --git a/mac80211_hwsim/wpa_supplicant.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf similarity index 100% rename from mac80211_hwsim/wpa_supplicant.conf rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.accept b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.accept rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.conf b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.conf rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.vlan b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.vlan rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan diff --git a/mac80211_hwsim/tests/0002-vlan/test.txt b/libeap/mac80211_hwsim/tests/0002-vlan/test.txt similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/test.txt rename to libeap/mac80211_hwsim/tests/0002-vlan/test.txt diff --git a/mac80211_hwsim/tools/Makefile b/libeap/mac80211_hwsim/tools/Makefile similarity index 100% rename from mac80211_hwsim/tools/Makefile rename to libeap/mac80211_hwsim/tools/Makefile diff --git a/mac80211_hwsim/tools/hwsim_test.c b/libeap/mac80211_hwsim/tools/hwsim_test.c similarity index 100% rename from mac80211_hwsim/tools/hwsim_test.c rename to libeap/mac80211_hwsim/tools/hwsim_test.c diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf b/libeap/mac80211_hwsim/wpa_supplicant.conf similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf rename to libeap/mac80211_hwsim/wpa_supplicant.conf diff --git a/patches/openssl-0.9.8-tls-extensions.patch b/libeap/patches/openssl-0.9.8-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8-tls-extensions.patch rename to libeap/patches/openssl-0.9.8-tls-extensions.patch diff --git a/patches/openssl-0.9.8d-tls-extensions.patch b/libeap/patches/openssl-0.9.8d-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8d-tls-extensions.patch rename to libeap/patches/openssl-0.9.8d-tls-extensions.patch diff --git a/patches/openssl-0.9.8e-tls-extensions.patch b/libeap/patches/openssl-0.9.8e-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8e-tls-extensions.patch rename to libeap/patches/openssl-0.9.8e-tls-extensions.patch diff --git a/patches/openssl-0.9.8g-tls-extensions.patch b/libeap/patches/openssl-0.9.8g-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8g-tls-extensions.patch rename to libeap/patches/openssl-0.9.8g-tls-extensions.patch diff --git a/patches/openssl-0.9.8h-tls-extensions.patch b/libeap/patches/openssl-0.9.8h-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8h-tls-extensions.patch rename to libeap/patches/openssl-0.9.8h-tls-extensions.patch diff --git a/patches/openssl-0.9.8i-tls-extensions.patch b/libeap/patches/openssl-0.9.8i-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8i-tls-extensions.patch rename to libeap/patches/openssl-0.9.8i-tls-extensions.patch diff --git a/patches/openssl-0.9.9-session-ticket.patch b/libeap/patches/openssl-0.9.9-session-ticket.patch similarity index 100% rename from patches/openssl-0.9.9-session-ticket.patch rename to libeap/patches/openssl-0.9.9-session-ticket.patch diff --git a/radius_example/.gitignore b/libeap/radius_example/.gitignore similarity index 100% rename from radius_example/.gitignore rename to libeap/radius_example/.gitignore diff --git a/radius_example/Makefile b/libeap/radius_example/Makefile similarity index 100% rename from radius_example/Makefile rename to libeap/radius_example/Makefile diff --git a/radius_example/README b/libeap/radius_example/README similarity index 100% rename from radius_example/README rename to libeap/radius_example/README diff --git a/radius_example/radius_example.c b/libeap/radius_example/radius_example.c similarity index 100% rename from radius_example/radius_example.c rename to libeap/radius_example/radius_example.c diff --git a/src/Makefile b/libeap/src/Makefile similarity index 100% rename from src/Makefile rename to libeap/src/Makefile diff --git a/src/wps/Makefile b/libeap/src/ap/Makefile similarity index 100% rename from src/wps/Makefile rename to libeap/src/ap/Makefile diff --git a/src/ap/accounting.c b/libeap/src/ap/accounting.c similarity index 100% rename from src/ap/accounting.c rename to libeap/src/ap/accounting.c diff --git a/src/ap/accounting.h b/libeap/src/ap/accounting.h similarity index 100% rename from src/ap/accounting.h rename to libeap/src/ap/accounting.h diff --git a/src/ap/ap_config.c b/libeap/src/ap/ap_config.c similarity index 100% rename from src/ap/ap_config.c rename to libeap/src/ap/ap_config.c diff --git a/src/ap/ap_config.h b/libeap/src/ap/ap_config.h similarity index 100% rename from src/ap/ap_config.h rename to libeap/src/ap/ap_config.h diff --git a/src/ap/ap_drv_ops.c b/libeap/src/ap/ap_drv_ops.c similarity index 100% rename from src/ap/ap_drv_ops.c rename to libeap/src/ap/ap_drv_ops.c diff --git a/src/ap/ap_drv_ops.h b/libeap/src/ap/ap_drv_ops.h similarity index 100% rename from src/ap/ap_drv_ops.h rename to libeap/src/ap/ap_drv_ops.h diff --git a/src/ap/ap_list.c b/libeap/src/ap/ap_list.c similarity index 100% rename from src/ap/ap_list.c rename to libeap/src/ap/ap_list.c diff --git a/src/ap/ap_list.h b/libeap/src/ap/ap_list.h similarity index 100% rename from src/ap/ap_list.h rename to libeap/src/ap/ap_list.h diff --git a/src/ap/ap_mlme.c b/libeap/src/ap/ap_mlme.c similarity index 100% rename from src/ap/ap_mlme.c rename to libeap/src/ap/ap_mlme.c diff --git a/src/ap/ap_mlme.h b/libeap/src/ap/ap_mlme.h similarity index 100% rename from src/ap/ap_mlme.h rename to libeap/src/ap/ap_mlme.h diff --git a/src/ap/authsrv.c b/libeap/src/ap/authsrv.c similarity index 100% rename from src/ap/authsrv.c rename to libeap/src/ap/authsrv.c diff --git a/src/ap/authsrv.h b/libeap/src/ap/authsrv.h similarity index 100% rename from src/ap/authsrv.h rename to libeap/src/ap/authsrv.h diff --git a/src/ap/beacon.c b/libeap/src/ap/beacon.c similarity index 100% rename from src/ap/beacon.c rename to libeap/src/ap/beacon.c diff --git a/src/ap/beacon.h b/libeap/src/ap/beacon.h similarity index 100% rename from src/ap/beacon.h rename to libeap/src/ap/beacon.h diff --git a/src/ap/ctrl_iface_ap.c b/libeap/src/ap/ctrl_iface_ap.c similarity index 100% rename from src/ap/ctrl_iface_ap.c rename to libeap/src/ap/ctrl_iface_ap.c diff --git a/src/ap/ctrl_iface_ap.h b/libeap/src/ap/ctrl_iface_ap.h similarity index 100% rename from src/ap/ctrl_iface_ap.h rename to libeap/src/ap/ctrl_iface_ap.h diff --git a/src/ap/drv_callbacks.c b/libeap/src/ap/drv_callbacks.c similarity index 100% rename from src/ap/drv_callbacks.c rename to libeap/src/ap/drv_callbacks.c diff --git a/src/ap/hostapd.c b/libeap/src/ap/hostapd.c similarity index 100% rename from src/ap/hostapd.c rename to libeap/src/ap/hostapd.c diff --git a/src/ap/hostapd.h b/libeap/src/ap/hostapd.h similarity index 100% rename from src/ap/hostapd.h rename to libeap/src/ap/hostapd.h diff --git a/src/ap/hw_features.c b/libeap/src/ap/hw_features.c similarity index 100% rename from src/ap/hw_features.c rename to libeap/src/ap/hw_features.c diff --git a/src/ap/hw_features.h b/libeap/src/ap/hw_features.h similarity index 100% rename from src/ap/hw_features.h rename to libeap/src/ap/hw_features.h diff --git a/src/ap/iapp.c b/libeap/src/ap/iapp.c similarity index 100% rename from src/ap/iapp.c rename to libeap/src/ap/iapp.c diff --git a/src/ap/iapp.h b/libeap/src/ap/iapp.h similarity index 100% rename from src/ap/iapp.h rename to libeap/src/ap/iapp.h diff --git a/src/ap/ieee802_11.c b/libeap/src/ap/ieee802_11.c similarity index 100% rename from src/ap/ieee802_11.c rename to libeap/src/ap/ieee802_11.c diff --git a/src/ap/ieee802_11.h b/libeap/src/ap/ieee802_11.h similarity index 100% rename from src/ap/ieee802_11.h rename to libeap/src/ap/ieee802_11.h diff --git a/src/ap/ieee802_11_auth.c b/libeap/src/ap/ieee802_11_auth.c similarity index 100% rename from src/ap/ieee802_11_auth.c rename to libeap/src/ap/ieee802_11_auth.c diff --git a/src/ap/ieee802_11_auth.h b/libeap/src/ap/ieee802_11_auth.h similarity index 100% rename from src/ap/ieee802_11_auth.h rename to libeap/src/ap/ieee802_11_auth.h diff --git a/src/ap/ieee802_11_ht.c b/libeap/src/ap/ieee802_11_ht.c similarity index 100% rename from src/ap/ieee802_11_ht.c rename to libeap/src/ap/ieee802_11_ht.c diff --git a/src/ap/ieee802_1x.c b/libeap/src/ap/ieee802_1x.c similarity index 100% rename from src/ap/ieee802_1x.c rename to libeap/src/ap/ieee802_1x.c diff --git a/src/ap/ieee802_1x.h b/libeap/src/ap/ieee802_1x.h similarity index 100% rename from src/ap/ieee802_1x.h rename to libeap/src/ap/ieee802_1x.h diff --git a/src/ap/p2p_hostapd.c b/libeap/src/ap/p2p_hostapd.c similarity index 100% rename from src/ap/p2p_hostapd.c rename to libeap/src/ap/p2p_hostapd.c diff --git a/src/ap/p2p_hostapd.h b/libeap/src/ap/p2p_hostapd.h similarity index 100% rename from src/ap/p2p_hostapd.h rename to libeap/src/ap/p2p_hostapd.h diff --git a/src/ap/peerkey_auth.c b/libeap/src/ap/peerkey_auth.c similarity index 100% rename from src/ap/peerkey_auth.c rename to libeap/src/ap/peerkey_auth.c diff --git a/src/ap/pmksa_cache_auth.c b/libeap/src/ap/pmksa_cache_auth.c similarity index 100% rename from src/ap/pmksa_cache_auth.c rename to libeap/src/ap/pmksa_cache_auth.c diff --git a/src/ap/pmksa_cache_auth.h b/libeap/src/ap/pmksa_cache_auth.h similarity index 100% rename from src/ap/pmksa_cache_auth.h rename to libeap/src/ap/pmksa_cache_auth.h diff --git a/src/ap/preauth_auth.c b/libeap/src/ap/preauth_auth.c similarity index 100% rename from src/ap/preauth_auth.c rename to libeap/src/ap/preauth_auth.c diff --git a/src/ap/preauth_auth.h b/libeap/src/ap/preauth_auth.h similarity index 100% rename from src/ap/preauth_auth.h rename to libeap/src/ap/preauth_auth.h diff --git a/src/ap/sta_info.c b/libeap/src/ap/sta_info.c similarity index 100% rename from src/ap/sta_info.c rename to libeap/src/ap/sta_info.c diff --git a/src/ap/sta_info.h b/libeap/src/ap/sta_info.h similarity index 100% rename from src/ap/sta_info.h rename to libeap/src/ap/sta_info.h diff --git a/src/ap/tkip_countermeasures.c b/libeap/src/ap/tkip_countermeasures.c similarity index 100% rename from src/ap/tkip_countermeasures.c rename to libeap/src/ap/tkip_countermeasures.c diff --git a/src/ap/tkip_countermeasures.h b/libeap/src/ap/tkip_countermeasures.h similarity index 100% rename from src/ap/tkip_countermeasures.h rename to libeap/src/ap/tkip_countermeasures.h diff --git a/src/ap/utils.c b/libeap/src/ap/utils.c similarity index 100% rename from src/ap/utils.c rename to libeap/src/ap/utils.c diff --git a/src/ap/vlan_init.c b/libeap/src/ap/vlan_init.c similarity index 100% rename from src/ap/vlan_init.c rename to libeap/src/ap/vlan_init.c diff --git a/src/ap/vlan_init.h b/libeap/src/ap/vlan_init.h similarity index 100% rename from src/ap/vlan_init.h rename to libeap/src/ap/vlan_init.h diff --git a/src/ap/wmm.c b/libeap/src/ap/wmm.c similarity index 100% rename from src/ap/wmm.c rename to libeap/src/ap/wmm.c diff --git a/src/ap/wmm.h b/libeap/src/ap/wmm.h similarity index 100% rename from src/ap/wmm.h rename to libeap/src/ap/wmm.h diff --git a/src/ap/wpa_auth.c b/libeap/src/ap/wpa_auth.c similarity index 100% rename from src/ap/wpa_auth.c rename to libeap/src/ap/wpa_auth.c diff --git a/src/ap/wpa_auth.h b/libeap/src/ap/wpa_auth.h similarity index 100% rename from src/ap/wpa_auth.h rename to libeap/src/ap/wpa_auth.h diff --git a/src/ap/wpa_auth_ft.c b/libeap/src/ap/wpa_auth_ft.c similarity index 100% rename from src/ap/wpa_auth_ft.c rename to libeap/src/ap/wpa_auth_ft.c diff --git a/src/ap/wpa_auth_glue.c b/libeap/src/ap/wpa_auth_glue.c similarity index 100% rename from src/ap/wpa_auth_glue.c rename to libeap/src/ap/wpa_auth_glue.c diff --git a/src/ap/wpa_auth_glue.h b/libeap/src/ap/wpa_auth_glue.h similarity index 100% rename from src/ap/wpa_auth_glue.h rename to libeap/src/ap/wpa_auth_glue.h diff --git a/src/ap/wpa_auth_i.h b/libeap/src/ap/wpa_auth_i.h similarity index 100% rename from src/ap/wpa_auth_i.h rename to libeap/src/ap/wpa_auth_i.h diff --git a/src/ap/wpa_auth_ie.c b/libeap/src/ap/wpa_auth_ie.c similarity index 100% rename from src/ap/wpa_auth_ie.c rename to libeap/src/ap/wpa_auth_ie.c diff --git a/src/ap/wpa_auth_ie.h b/libeap/src/ap/wpa_auth_ie.h similarity index 100% rename from src/ap/wpa_auth_ie.h rename to libeap/src/ap/wpa_auth_ie.h diff --git a/src/ap/wps_hostapd.c b/libeap/src/ap/wps_hostapd.c similarity index 100% rename from src/ap/wps_hostapd.c rename to libeap/src/ap/wps_hostapd.c diff --git a/src/ap/wps_hostapd.h b/libeap/src/ap/wps_hostapd.h similarity index 100% rename from src/ap/wps_hostapd.h rename to libeap/src/ap/wps_hostapd.h diff --git a/src/rsn_supp/Makefile b/libeap/src/common/Makefile similarity index 100% rename from src/rsn_supp/Makefile rename to libeap/src/common/Makefile diff --git a/src/common/defs.h b/libeap/src/common/defs.h similarity index 100% rename from src/common/defs.h rename to libeap/src/common/defs.h diff --git a/src/common/eapol_common.h b/libeap/src/common/eapol_common.h similarity index 100% rename from src/common/eapol_common.h rename to libeap/src/common/eapol_common.h diff --git a/src/common/ieee802_11_common.c b/libeap/src/common/ieee802_11_common.c similarity index 100% rename from src/common/ieee802_11_common.c rename to libeap/src/common/ieee802_11_common.c diff --git a/src/common/ieee802_11_common.h b/libeap/src/common/ieee802_11_common.h similarity index 100% rename from src/common/ieee802_11_common.h rename to libeap/src/common/ieee802_11_common.h diff --git a/src/common/ieee802_11_defs.h b/libeap/src/common/ieee802_11_defs.h similarity index 100% rename from src/common/ieee802_11_defs.h rename to libeap/src/common/ieee802_11_defs.h diff --git a/src/common/privsep_commands.h b/libeap/src/common/privsep_commands.h similarity index 100% rename from src/common/privsep_commands.h rename to libeap/src/common/privsep_commands.h diff --git a/src/common/version.h b/libeap/src/common/version.h similarity index 100% rename from src/common/version.h rename to libeap/src/common/version.h diff --git a/src/common/wpa_common.c b/libeap/src/common/wpa_common.c similarity index 100% rename from src/common/wpa_common.c rename to libeap/src/common/wpa_common.c diff --git a/src/common/wpa_common.h b/libeap/src/common/wpa_common.h similarity index 100% rename from src/common/wpa_common.h rename to libeap/src/common/wpa_common.h diff --git a/src/common/wpa_ctrl.c b/libeap/src/common/wpa_ctrl.c similarity index 100% rename from src/common/wpa_ctrl.c rename to libeap/src/common/wpa_ctrl.c diff --git a/src/common/wpa_ctrl.h b/libeap/src/common/wpa_ctrl.h similarity index 100% rename from src/common/wpa_ctrl.h rename to libeap/src/common/wpa_ctrl.h diff --git a/src/crypto/.gitignore b/libeap/src/crypto/.gitignore similarity index 100% rename from src/crypto/.gitignore rename to libeap/src/crypto/.gitignore diff --git a/src/crypto/Makefile b/libeap/src/crypto/Makefile similarity index 100% rename from src/crypto/Makefile rename to libeap/src/crypto/Makefile diff --git a/src/crypto/aes-cbc.c b/libeap/src/crypto/aes-cbc.c similarity index 100% rename from src/crypto/aes-cbc.c rename to libeap/src/crypto/aes-cbc.c diff --git a/src/crypto/aes-ctr.c b/libeap/src/crypto/aes-ctr.c similarity index 100% rename from src/crypto/aes-ctr.c rename to libeap/src/crypto/aes-ctr.c diff --git a/src/crypto/aes-eax.c b/libeap/src/crypto/aes-eax.c similarity index 100% rename from src/crypto/aes-eax.c rename to libeap/src/crypto/aes-eax.c diff --git a/src/crypto/aes-encblock.c b/libeap/src/crypto/aes-encblock.c similarity index 100% rename from src/crypto/aes-encblock.c rename to libeap/src/crypto/aes-encblock.c diff --git a/src/crypto/aes-internal-dec.c b/libeap/src/crypto/aes-internal-dec.c similarity index 100% rename from src/crypto/aes-internal-dec.c rename to libeap/src/crypto/aes-internal-dec.c diff --git a/src/crypto/aes-internal-enc.c b/libeap/src/crypto/aes-internal-enc.c similarity index 100% rename from src/crypto/aes-internal-enc.c rename to libeap/src/crypto/aes-internal-enc.c diff --git a/src/crypto/aes-internal.c b/libeap/src/crypto/aes-internal.c similarity index 100% rename from src/crypto/aes-internal.c rename to libeap/src/crypto/aes-internal.c diff --git a/src/crypto/aes-omac1.c b/libeap/src/crypto/aes-omac1.c similarity index 100% rename from src/crypto/aes-omac1.c rename to libeap/src/crypto/aes-omac1.c diff --git a/src/crypto/aes-unwrap.c b/libeap/src/crypto/aes-unwrap.c similarity index 100% rename from src/crypto/aes-unwrap.c rename to libeap/src/crypto/aes-unwrap.c diff --git a/src/crypto/aes-wrap.c b/libeap/src/crypto/aes-wrap.c similarity index 100% rename from src/crypto/aes-wrap.c rename to libeap/src/crypto/aes-wrap.c diff --git a/src/crypto/aes.h b/libeap/src/crypto/aes.h similarity index 100% rename from src/crypto/aes.h rename to libeap/src/crypto/aes.h diff --git a/src/crypto/aes_i.h b/libeap/src/crypto/aes_i.h similarity index 100% rename from src/crypto/aes_i.h rename to libeap/src/crypto/aes_i.h diff --git a/src/crypto/aes_wrap.h b/libeap/src/crypto/aes_wrap.h similarity index 100% rename from src/crypto/aes_wrap.h rename to libeap/src/crypto/aes_wrap.h diff --git a/src/crypto/crypto.h b/libeap/src/crypto/crypto.h similarity index 100% rename from src/crypto/crypto.h rename to libeap/src/crypto/crypto.h diff --git a/src/crypto/crypto_cryptoapi.c b/libeap/src/crypto/crypto_cryptoapi.c similarity index 100% rename from src/crypto/crypto_cryptoapi.c rename to libeap/src/crypto/crypto_cryptoapi.c diff --git a/src/crypto/crypto_gnutls.c b/libeap/src/crypto/crypto_gnutls.c similarity index 100% rename from src/crypto/crypto_gnutls.c rename to libeap/src/crypto/crypto_gnutls.c diff --git a/src/crypto/crypto_internal-cipher.c b/libeap/src/crypto/crypto_internal-cipher.c similarity index 100% rename from src/crypto/crypto_internal-cipher.c rename to libeap/src/crypto/crypto_internal-cipher.c diff --git a/src/crypto/crypto_internal-modexp.c b/libeap/src/crypto/crypto_internal-modexp.c similarity index 100% rename from src/crypto/crypto_internal-modexp.c rename to libeap/src/crypto/crypto_internal-modexp.c diff --git a/src/crypto/crypto_internal-rsa.c b/libeap/src/crypto/crypto_internal-rsa.c similarity index 100% rename from src/crypto/crypto_internal-rsa.c rename to libeap/src/crypto/crypto_internal-rsa.c diff --git a/src/crypto/crypto_internal.c b/libeap/src/crypto/crypto_internal.c similarity index 100% rename from src/crypto/crypto_internal.c rename to libeap/src/crypto/crypto_internal.c diff --git a/src/crypto/crypto_libtomcrypt.c b/libeap/src/crypto/crypto_libtomcrypt.c similarity index 100% rename from src/crypto/crypto_libtomcrypt.c rename to libeap/src/crypto/crypto_libtomcrypt.c diff --git a/src/crypto/crypto_none.c b/libeap/src/crypto/crypto_none.c similarity index 100% rename from src/crypto/crypto_none.c rename to libeap/src/crypto/crypto_none.c diff --git a/src/crypto/crypto_nss.c b/libeap/src/crypto/crypto_nss.c similarity index 100% rename from src/crypto/crypto_nss.c rename to libeap/src/crypto/crypto_nss.c diff --git a/src/crypto/crypto_openssl.c b/libeap/src/crypto/crypto_openssl.c similarity index 100% rename from src/crypto/crypto_openssl.c rename to libeap/src/crypto/crypto_openssl.c diff --git a/src/crypto/des-internal.c b/libeap/src/crypto/des-internal.c similarity index 100% rename from src/crypto/des-internal.c rename to libeap/src/crypto/des-internal.c diff --git a/src/crypto/des_i.h b/libeap/src/crypto/des_i.h similarity index 100% rename from src/crypto/des_i.h rename to libeap/src/crypto/des_i.h diff --git a/src/crypto/dh_group5.c b/libeap/src/crypto/dh_group5.c similarity index 100% rename from src/crypto/dh_group5.c rename to libeap/src/crypto/dh_group5.c diff --git a/src/crypto/dh_group5.h b/libeap/src/crypto/dh_group5.h similarity index 100% rename from src/crypto/dh_group5.h rename to libeap/src/crypto/dh_group5.h diff --git a/src/crypto/dh_groups.c b/libeap/src/crypto/dh_groups.c similarity index 100% rename from src/crypto/dh_groups.c rename to libeap/src/crypto/dh_groups.c diff --git a/src/crypto/dh_groups.h b/libeap/src/crypto/dh_groups.h similarity index 100% rename from src/crypto/dh_groups.h rename to libeap/src/crypto/dh_groups.h diff --git a/src/crypto/fips_prf_cryptoapi.c b/libeap/src/crypto/fips_prf_cryptoapi.c similarity index 100% rename from src/crypto/fips_prf_cryptoapi.c rename to libeap/src/crypto/fips_prf_cryptoapi.c diff --git a/src/crypto/fips_prf_gnutls.c b/libeap/src/crypto/fips_prf_gnutls.c similarity index 100% rename from src/crypto/fips_prf_gnutls.c rename to libeap/src/crypto/fips_prf_gnutls.c diff --git a/src/crypto/fips_prf_internal.c b/libeap/src/crypto/fips_prf_internal.c similarity index 100% rename from src/crypto/fips_prf_internal.c rename to libeap/src/crypto/fips_prf_internal.c diff --git a/src/crypto/fips_prf_nss.c b/libeap/src/crypto/fips_prf_nss.c similarity index 100% rename from src/crypto/fips_prf_nss.c rename to libeap/src/crypto/fips_prf_nss.c diff --git a/src/crypto/fips_prf_openssl.c b/libeap/src/crypto/fips_prf_openssl.c similarity index 100% rename from src/crypto/fips_prf_openssl.c rename to libeap/src/crypto/fips_prf_openssl.c diff --git a/src/crypto/md4-internal.c b/libeap/src/crypto/md4-internal.c similarity index 100% rename from src/crypto/md4-internal.c rename to libeap/src/crypto/md4-internal.c diff --git a/src/crypto/md5-internal.c b/libeap/src/crypto/md5-internal.c similarity index 100% rename from src/crypto/md5-internal.c rename to libeap/src/crypto/md5-internal.c diff --git a/src/crypto/md5-non-fips.c b/libeap/src/crypto/md5-non-fips.c similarity index 100% rename from src/crypto/md5-non-fips.c rename to libeap/src/crypto/md5-non-fips.c diff --git a/src/crypto/md5.c b/libeap/src/crypto/md5.c similarity index 100% rename from src/crypto/md5.c rename to libeap/src/crypto/md5.c diff --git a/src/crypto/md5.h b/libeap/src/crypto/md5.h similarity index 100% rename from src/crypto/md5.h rename to libeap/src/crypto/md5.h diff --git a/src/crypto/md5_i.h b/libeap/src/crypto/md5_i.h similarity index 100% rename from src/crypto/md5_i.h rename to libeap/src/crypto/md5_i.h diff --git a/src/crypto/milenage.c b/libeap/src/crypto/milenage.c similarity index 100% rename from src/crypto/milenage.c rename to libeap/src/crypto/milenage.c diff --git a/src/crypto/milenage.h b/libeap/src/crypto/milenage.h similarity index 100% rename from src/crypto/milenage.h rename to libeap/src/crypto/milenage.h diff --git a/src/crypto/ms_funcs.c b/libeap/src/crypto/ms_funcs.c similarity index 100% rename from src/crypto/ms_funcs.c rename to libeap/src/crypto/ms_funcs.c diff --git a/src/crypto/ms_funcs.h b/libeap/src/crypto/ms_funcs.h similarity index 100% rename from src/crypto/ms_funcs.h rename to libeap/src/crypto/ms_funcs.h diff --git a/src/crypto/rc4.c b/libeap/src/crypto/rc4.c similarity index 100% rename from src/crypto/rc4.c rename to libeap/src/crypto/rc4.c diff --git a/src/crypto/sha1-internal.c b/libeap/src/crypto/sha1-internal.c similarity index 100% rename from src/crypto/sha1-internal.c rename to libeap/src/crypto/sha1-internal.c diff --git a/src/crypto/sha1-pbkdf2.c b/libeap/src/crypto/sha1-pbkdf2.c similarity index 100% rename from src/crypto/sha1-pbkdf2.c rename to libeap/src/crypto/sha1-pbkdf2.c diff --git a/src/crypto/sha1-tlsprf.c b/libeap/src/crypto/sha1-tlsprf.c similarity index 100% rename from src/crypto/sha1-tlsprf.c rename to libeap/src/crypto/sha1-tlsprf.c diff --git a/src/crypto/sha1-tprf.c b/libeap/src/crypto/sha1-tprf.c similarity index 100% rename from src/crypto/sha1-tprf.c rename to libeap/src/crypto/sha1-tprf.c diff --git a/src/crypto/sha1.c b/libeap/src/crypto/sha1.c similarity index 100% rename from src/crypto/sha1.c rename to libeap/src/crypto/sha1.c diff --git a/src/crypto/sha1.h b/libeap/src/crypto/sha1.h similarity index 100% rename from src/crypto/sha1.h rename to libeap/src/crypto/sha1.h diff --git a/src/crypto/sha1_i.h b/libeap/src/crypto/sha1_i.h similarity index 100% rename from src/crypto/sha1_i.h rename to libeap/src/crypto/sha1_i.h diff --git a/src/crypto/sha256-internal.c b/libeap/src/crypto/sha256-internal.c similarity index 100% rename from src/crypto/sha256-internal.c rename to libeap/src/crypto/sha256-internal.c diff --git a/src/crypto/sha256.c b/libeap/src/crypto/sha256.c similarity index 100% rename from src/crypto/sha256.c rename to libeap/src/crypto/sha256.c diff --git a/src/crypto/sha256.h b/libeap/src/crypto/sha256.h similarity index 100% rename from src/crypto/sha256.h rename to libeap/src/crypto/sha256.h diff --git a/src/crypto/tls.h b/libeap/src/crypto/tls.h similarity index 100% rename from src/crypto/tls.h rename to libeap/src/crypto/tls.h diff --git a/src/crypto/tls_gnutls.c b/libeap/src/crypto/tls_gnutls.c similarity index 100% rename from src/crypto/tls_gnutls.c rename to libeap/src/crypto/tls_gnutls.c diff --git a/src/crypto/tls_internal.c b/libeap/src/crypto/tls_internal.c similarity index 100% rename from src/crypto/tls_internal.c rename to libeap/src/crypto/tls_internal.c diff --git a/src/crypto/tls_none.c b/libeap/src/crypto/tls_none.c similarity index 100% rename from src/crypto/tls_none.c rename to libeap/src/crypto/tls_none.c diff --git a/src/crypto/tls_nss.c b/libeap/src/crypto/tls_nss.c similarity index 100% rename from src/crypto/tls_nss.c rename to libeap/src/crypto/tls_nss.c diff --git a/src/crypto/tls_openssl.c b/libeap/src/crypto/tls_openssl.c similarity index 100% rename from src/crypto/tls_openssl.c rename to libeap/src/crypto/tls_openssl.c diff --git a/src/crypto/tls_schannel.c b/libeap/src/crypto/tls_schannel.c similarity index 100% rename from src/crypto/tls_schannel.c rename to libeap/src/crypto/tls_schannel.c diff --git a/src/drivers/.gitignore b/libeap/src/drivers/.gitignore similarity index 100% rename from src/drivers/.gitignore rename to libeap/src/drivers/.gitignore diff --git a/src/drivers/Apple80211.h b/libeap/src/drivers/Apple80211.h similarity index 100% rename from src/drivers/Apple80211.h rename to libeap/src/drivers/Apple80211.h diff --git a/src/drivers/Makefile b/libeap/src/drivers/Makefile similarity index 100% rename from src/drivers/Makefile rename to libeap/src/drivers/Makefile diff --git a/src/drivers/MobileApple80211.c b/libeap/src/drivers/MobileApple80211.c similarity index 100% rename from src/drivers/MobileApple80211.c rename to libeap/src/drivers/MobileApple80211.c diff --git a/src/drivers/MobileApple80211.h b/libeap/src/drivers/MobileApple80211.h similarity index 100% rename from src/drivers/MobileApple80211.h rename to libeap/src/drivers/MobileApple80211.h diff --git a/src/drivers/driver.h b/libeap/src/drivers/driver.h similarity index 100% rename from src/drivers/driver.h rename to libeap/src/drivers/driver.h diff --git a/src/drivers/driver_atheros.c b/libeap/src/drivers/driver_atheros.c similarity index 100% rename from src/drivers/driver_atheros.c rename to libeap/src/drivers/driver_atheros.c diff --git a/src/drivers/driver_atmel.c b/libeap/src/drivers/driver_atmel.c similarity index 100% rename from src/drivers/driver_atmel.c rename to libeap/src/drivers/driver_atmel.c diff --git a/src/drivers/driver_broadcom.c b/libeap/src/drivers/driver_broadcom.c similarity index 100% rename from src/drivers/driver_broadcom.c rename to libeap/src/drivers/driver_broadcom.c diff --git a/src/drivers/driver_bsd.c b/libeap/src/drivers/driver_bsd.c similarity index 100% rename from src/drivers/driver_bsd.c rename to libeap/src/drivers/driver_bsd.c diff --git a/src/drivers/driver_hostap.c b/libeap/src/drivers/driver_hostap.c similarity index 100% rename from src/drivers/driver_hostap.c rename to libeap/src/drivers/driver_hostap.c diff --git a/src/drivers/driver_hostap.h b/libeap/src/drivers/driver_hostap.h similarity index 100% rename from src/drivers/driver_hostap.h rename to libeap/src/drivers/driver_hostap.h diff --git a/src/drivers/driver_iphone.m b/libeap/src/drivers/driver_iphone.m similarity index 100% rename from src/drivers/driver_iphone.m rename to libeap/src/drivers/driver_iphone.m diff --git a/src/drivers/driver_ipw.c b/libeap/src/drivers/driver_ipw.c similarity index 100% rename from src/drivers/driver_ipw.c rename to libeap/src/drivers/driver_ipw.c diff --git a/src/drivers/driver_madwifi.c b/libeap/src/drivers/driver_madwifi.c similarity index 100% rename from src/drivers/driver_madwifi.c rename to libeap/src/drivers/driver_madwifi.c diff --git a/src/drivers/driver_ndis.c b/libeap/src/drivers/driver_ndis.c similarity index 100% rename from src/drivers/driver_ndis.c rename to libeap/src/drivers/driver_ndis.c diff --git a/src/drivers/driver_ndis.h b/libeap/src/drivers/driver_ndis.h similarity index 100% rename from src/drivers/driver_ndis.h rename to libeap/src/drivers/driver_ndis.h diff --git a/src/drivers/driver_ndis_.c b/libeap/src/drivers/driver_ndis_.c similarity index 100% rename from src/drivers/driver_ndis_.c rename to libeap/src/drivers/driver_ndis_.c diff --git a/src/drivers/driver_ndiswrapper.c b/libeap/src/drivers/driver_ndiswrapper.c similarity index 100% rename from src/drivers/driver_ndiswrapper.c rename to libeap/src/drivers/driver_ndiswrapper.c diff --git a/src/drivers/driver_nl80211.c b/libeap/src/drivers/driver_nl80211.c similarity index 100% rename from src/drivers/driver_nl80211.c rename to libeap/src/drivers/driver_nl80211.c diff --git a/src/drivers/driver_none.c b/libeap/src/drivers/driver_none.c similarity index 100% rename from src/drivers/driver_none.c rename to libeap/src/drivers/driver_none.c diff --git a/src/drivers/driver_osx.m b/libeap/src/drivers/driver_osx.m similarity index 100% rename from src/drivers/driver_osx.m rename to libeap/src/drivers/driver_osx.m diff --git a/src/drivers/driver_privsep.c b/libeap/src/drivers/driver_privsep.c similarity index 100% rename from src/drivers/driver_privsep.c rename to libeap/src/drivers/driver_privsep.c diff --git a/src/drivers/driver_ralink.c b/libeap/src/drivers/driver_ralink.c similarity index 100% rename from src/drivers/driver_ralink.c rename to libeap/src/drivers/driver_ralink.c diff --git a/src/drivers/driver_ralink.h b/libeap/src/drivers/driver_ralink.h similarity index 100% rename from src/drivers/driver_ralink.h rename to libeap/src/drivers/driver_ralink.h diff --git a/src/drivers/driver_roboswitch.c b/libeap/src/drivers/driver_roboswitch.c similarity index 100% rename from src/drivers/driver_roboswitch.c rename to libeap/src/drivers/driver_roboswitch.c diff --git a/src/drivers/driver_test.c b/libeap/src/drivers/driver_test.c similarity index 100% rename from src/drivers/driver_test.c rename to libeap/src/drivers/driver_test.c diff --git a/src/drivers/driver_wext.c b/libeap/src/drivers/driver_wext.c similarity index 100% rename from src/drivers/driver_wext.c rename to libeap/src/drivers/driver_wext.c diff --git a/src/drivers/driver_wext.h b/libeap/src/drivers/driver_wext.h similarity index 100% rename from src/drivers/driver_wext.h rename to libeap/src/drivers/driver_wext.h diff --git a/src/drivers/driver_wired.c b/libeap/src/drivers/driver_wired.c similarity index 100% rename from src/drivers/driver_wired.c rename to libeap/src/drivers/driver_wired.c diff --git a/src/drivers/drivers.c b/libeap/src/drivers/drivers.c similarity index 100% rename from src/drivers/drivers.c rename to libeap/src/drivers/drivers.c diff --git a/src/drivers/drivers.mak b/libeap/src/drivers/drivers.mak similarity index 100% rename from src/drivers/drivers.mak rename to libeap/src/drivers/drivers.mak diff --git a/src/drivers/linux_ioctl.c b/libeap/src/drivers/linux_ioctl.c similarity index 100% rename from src/drivers/linux_ioctl.c rename to libeap/src/drivers/linux_ioctl.c diff --git a/src/drivers/linux_ioctl.h b/libeap/src/drivers/linux_ioctl.h similarity index 100% rename from src/drivers/linux_ioctl.h rename to libeap/src/drivers/linux_ioctl.h diff --git a/src/drivers/ndis_events.c b/libeap/src/drivers/ndis_events.c similarity index 100% rename from src/drivers/ndis_events.c rename to libeap/src/drivers/ndis_events.c diff --git a/src/drivers/netlink.c b/libeap/src/drivers/netlink.c similarity index 100% rename from src/drivers/netlink.c rename to libeap/src/drivers/netlink.c diff --git a/src/drivers/netlink.h b/libeap/src/drivers/netlink.h similarity index 100% rename from src/drivers/netlink.h rename to libeap/src/drivers/netlink.h diff --git a/src/drivers/nl80211_copy.h b/libeap/src/drivers/nl80211_copy.h similarity index 100% rename from src/drivers/nl80211_copy.h rename to libeap/src/drivers/nl80211_copy.h diff --git a/src/drivers/priv_netlink.h b/libeap/src/drivers/priv_netlink.h similarity index 100% rename from src/drivers/priv_netlink.h rename to libeap/src/drivers/priv_netlink.h diff --git a/src/drivers/rfkill.c b/libeap/src/drivers/rfkill.c similarity index 100% rename from src/drivers/rfkill.c rename to libeap/src/drivers/rfkill.c diff --git a/src/drivers/rfkill.h b/libeap/src/drivers/rfkill.h similarity index 100% rename from src/drivers/rfkill.h rename to libeap/src/drivers/rfkill.h diff --git a/src/drivers/wireless_copy.h b/libeap/src/drivers/wireless_copy.h similarity index 100% rename from src/drivers/wireless_copy.h rename to libeap/src/drivers/wireless_copy.h diff --git a/src/l2_packet/Makefile b/libeap/src/eap_common/Makefile similarity index 100% rename from src/l2_packet/Makefile rename to libeap/src/eap_common/Makefile diff --git a/src/eap_common/chap.c b/libeap/src/eap_common/chap.c similarity index 100% rename from src/eap_common/chap.c rename to libeap/src/eap_common/chap.c diff --git a/src/eap_common/chap.h b/libeap/src/eap_common/chap.h similarity index 100% rename from src/eap_common/chap.h rename to libeap/src/eap_common/chap.h diff --git a/src/eap_common/eap_common.c b/libeap/src/eap_common/eap_common.c similarity index 100% rename from src/eap_common/eap_common.c rename to libeap/src/eap_common/eap_common.c diff --git a/src/eap_common/eap_common.h b/libeap/src/eap_common/eap_common.h similarity index 100% rename from src/eap_common/eap_common.h rename to libeap/src/eap_common/eap_common.h diff --git a/src/eap_common/eap_defs.h b/libeap/src/eap_common/eap_defs.h similarity index 100% rename from src/eap_common/eap_defs.h rename to libeap/src/eap_common/eap_defs.h diff --git a/src/eap_common/eap_fast_common.c b/libeap/src/eap_common/eap_fast_common.c similarity index 100% rename from src/eap_common/eap_fast_common.c rename to libeap/src/eap_common/eap_fast_common.c diff --git a/src/eap_common/eap_fast_common.h b/libeap/src/eap_common/eap_fast_common.h similarity index 100% rename from src/eap_common/eap_fast_common.h rename to libeap/src/eap_common/eap_fast_common.h diff --git a/src/eap_common/eap_gpsk_common.c b/libeap/src/eap_common/eap_gpsk_common.c similarity index 100% rename from src/eap_common/eap_gpsk_common.c rename to libeap/src/eap_common/eap_gpsk_common.c diff --git a/src/eap_common/eap_gpsk_common.h b/libeap/src/eap_common/eap_gpsk_common.h similarity index 100% rename from src/eap_common/eap_gpsk_common.h rename to libeap/src/eap_common/eap_gpsk_common.h diff --git a/src/eap_common/eap_ikev2_common.c b/libeap/src/eap_common/eap_ikev2_common.c similarity index 100% rename from src/eap_common/eap_ikev2_common.c rename to libeap/src/eap_common/eap_ikev2_common.c diff --git a/src/eap_common/eap_ikev2_common.h b/libeap/src/eap_common/eap_ikev2_common.h similarity index 100% rename from src/eap_common/eap_ikev2_common.h rename to libeap/src/eap_common/eap_ikev2_common.h diff --git a/src/eap_common/eap_pax_common.c b/libeap/src/eap_common/eap_pax_common.c similarity index 100% rename from src/eap_common/eap_pax_common.c rename to libeap/src/eap_common/eap_pax_common.c diff --git a/src/eap_common/eap_pax_common.h b/libeap/src/eap_common/eap_pax_common.h similarity index 100% rename from src/eap_common/eap_pax_common.h rename to libeap/src/eap_common/eap_pax_common.h diff --git a/src/eap_common/eap_peap_common.c b/libeap/src/eap_common/eap_peap_common.c similarity index 100% rename from src/eap_common/eap_peap_common.c rename to libeap/src/eap_common/eap_peap_common.c diff --git a/src/eap_common/eap_peap_common.h b/libeap/src/eap_common/eap_peap_common.h similarity index 100% rename from src/eap_common/eap_peap_common.h rename to libeap/src/eap_common/eap_peap_common.h diff --git a/src/eap_common/eap_psk_common.c b/libeap/src/eap_common/eap_psk_common.c similarity index 100% rename from src/eap_common/eap_psk_common.c rename to libeap/src/eap_common/eap_psk_common.c diff --git a/src/eap_common/eap_psk_common.h b/libeap/src/eap_common/eap_psk_common.h similarity index 100% rename from src/eap_common/eap_psk_common.h rename to libeap/src/eap_common/eap_psk_common.h diff --git a/src/eap_common/eap_pwd_common.c b/libeap/src/eap_common/eap_pwd_common.c similarity index 100% rename from src/eap_common/eap_pwd_common.c rename to libeap/src/eap_common/eap_pwd_common.c diff --git a/src/eap_common/eap_pwd_common.h b/libeap/src/eap_common/eap_pwd_common.h similarity index 100% rename from src/eap_common/eap_pwd_common.h rename to libeap/src/eap_common/eap_pwd_common.h diff --git a/src/eap_common/eap_sake_common.c b/libeap/src/eap_common/eap_sake_common.c similarity index 100% rename from src/eap_common/eap_sake_common.c rename to libeap/src/eap_common/eap_sake_common.c diff --git a/src/eap_common/eap_sake_common.h b/libeap/src/eap_common/eap_sake_common.h similarity index 100% rename from src/eap_common/eap_sake_common.h rename to libeap/src/eap_common/eap_sake_common.h diff --git a/src/eap_common/eap_sim_common.c b/libeap/src/eap_common/eap_sim_common.c similarity index 100% rename from src/eap_common/eap_sim_common.c rename to libeap/src/eap_common/eap_sim_common.c diff --git a/src/eap_common/eap_sim_common.h b/libeap/src/eap_common/eap_sim_common.h similarity index 100% rename from src/eap_common/eap_sim_common.h rename to libeap/src/eap_common/eap_sim_common.h diff --git a/src/eap_common/eap_tlv_common.h b/libeap/src/eap_common/eap_tlv_common.h similarity index 100% rename from src/eap_common/eap_tlv_common.h rename to libeap/src/eap_common/eap_tlv_common.h diff --git a/src/eap_common/eap_ttls.h b/libeap/src/eap_common/eap_ttls.h similarity index 100% rename from src/eap_common/eap_ttls.h rename to libeap/src/eap_common/eap_ttls.h diff --git a/src/eap_common/eap_wsc_common.c b/libeap/src/eap_common/eap_wsc_common.c similarity index 100% rename from src/eap_common/eap_wsc_common.c rename to libeap/src/eap_common/eap_wsc_common.c diff --git a/src/eap_common/eap_wsc_common.h b/libeap/src/eap_common/eap_wsc_common.h similarity index 100% rename from src/eap_common/eap_wsc_common.h rename to libeap/src/eap_common/eap_wsc_common.h diff --git a/src/eap_common/ikev2_common.c b/libeap/src/eap_common/ikev2_common.c similarity index 100% rename from src/eap_common/ikev2_common.c rename to libeap/src/eap_common/ikev2_common.c diff --git a/src/eap_common/ikev2_common.h b/libeap/src/eap_common/ikev2_common.h similarity index 100% rename from src/eap_common/ikev2_common.h rename to libeap/src/eap_common/ikev2_common.h diff --git a/src/eap_peer/Makefile b/libeap/src/eap_peer/Makefile similarity index 100% rename from src/eap_peer/Makefile rename to libeap/src/eap_peer/Makefile diff --git a/src/eap_peer/eap.c b/libeap/src/eap_peer/eap.c similarity index 100% rename from src/eap_peer/eap.c rename to libeap/src/eap_peer/eap.c diff --git a/src/eap_peer/eap.h b/libeap/src/eap_peer/eap.h similarity index 100% rename from src/eap_peer/eap.h rename to libeap/src/eap_peer/eap.h diff --git a/src/eap_peer/eap_aka.c b/libeap/src/eap_peer/eap_aka.c similarity index 100% rename from src/eap_peer/eap_aka.c rename to libeap/src/eap_peer/eap_aka.c diff --git a/src/eap_peer/eap_config.h b/libeap/src/eap_peer/eap_config.h similarity index 100% rename from src/eap_peer/eap_config.h rename to libeap/src/eap_peer/eap_config.h diff --git a/src/eap_peer/eap_fast.c b/libeap/src/eap_peer/eap_fast.c similarity index 100% rename from src/eap_peer/eap_fast.c rename to libeap/src/eap_peer/eap_fast.c diff --git a/src/eap_peer/eap_fast_pac.c b/libeap/src/eap_peer/eap_fast_pac.c similarity index 100% rename from src/eap_peer/eap_fast_pac.c rename to libeap/src/eap_peer/eap_fast_pac.c diff --git a/src/eap_peer/eap_fast_pac.h b/libeap/src/eap_peer/eap_fast_pac.h similarity index 100% rename from src/eap_peer/eap_fast_pac.h rename to libeap/src/eap_peer/eap_fast_pac.h diff --git a/src/eap_peer/eap_gpsk.c b/libeap/src/eap_peer/eap_gpsk.c similarity index 100% rename from src/eap_peer/eap_gpsk.c rename to libeap/src/eap_peer/eap_gpsk.c diff --git a/src/eap_peer/eap_gtc.c b/libeap/src/eap_peer/eap_gtc.c similarity index 100% rename from src/eap_peer/eap_gtc.c rename to libeap/src/eap_peer/eap_gtc.c diff --git a/src/eap_peer/eap_i.h b/libeap/src/eap_peer/eap_i.h similarity index 100% rename from src/eap_peer/eap_i.h rename to libeap/src/eap_peer/eap_i.h diff --git a/src/eap_peer/eap_ikev2.c b/libeap/src/eap_peer/eap_ikev2.c similarity index 100% rename from src/eap_peer/eap_ikev2.c rename to libeap/src/eap_peer/eap_ikev2.c diff --git a/src/eap_peer/eap_leap.c b/libeap/src/eap_peer/eap_leap.c similarity index 100% rename from src/eap_peer/eap_leap.c rename to libeap/src/eap_peer/eap_leap.c diff --git a/src/eap_peer/eap_md5.c b/libeap/src/eap_peer/eap_md5.c similarity index 100% rename from src/eap_peer/eap_md5.c rename to libeap/src/eap_peer/eap_md5.c diff --git a/src/eap_peer/eap_methods.c b/libeap/src/eap_peer/eap_methods.c similarity index 100% rename from src/eap_peer/eap_methods.c rename to libeap/src/eap_peer/eap_methods.c diff --git a/src/eap_peer/eap_methods.h b/libeap/src/eap_peer/eap_methods.h similarity index 100% rename from src/eap_peer/eap_methods.h rename to libeap/src/eap_peer/eap_methods.h diff --git a/src/eap_peer/eap_mschapv2.c b/libeap/src/eap_peer/eap_mschapv2.c similarity index 100% rename from src/eap_peer/eap_mschapv2.c rename to libeap/src/eap_peer/eap_mschapv2.c diff --git a/src/eap_peer/eap_otp.c b/libeap/src/eap_peer/eap_otp.c similarity index 100% rename from src/eap_peer/eap_otp.c rename to libeap/src/eap_peer/eap_otp.c diff --git a/src/eap_peer/eap_pax.c b/libeap/src/eap_peer/eap_pax.c similarity index 100% rename from src/eap_peer/eap_pax.c rename to libeap/src/eap_peer/eap_pax.c diff --git a/src/eap_peer/eap_peap.c b/libeap/src/eap_peer/eap_peap.c similarity index 100% rename from src/eap_peer/eap_peap.c rename to libeap/src/eap_peer/eap_peap.c diff --git a/src/eap_peer/eap_psk.c b/libeap/src/eap_peer/eap_psk.c similarity index 100% rename from src/eap_peer/eap_psk.c rename to libeap/src/eap_peer/eap_psk.c diff --git a/src/eap_peer/eap_pwd.c b/libeap/src/eap_peer/eap_pwd.c similarity index 100% rename from src/eap_peer/eap_pwd.c rename to libeap/src/eap_peer/eap_pwd.c diff --git a/src/eap_peer/eap_sake.c b/libeap/src/eap_peer/eap_sake.c similarity index 100% rename from src/eap_peer/eap_sake.c rename to libeap/src/eap_peer/eap_sake.c diff --git a/src/eap_peer/eap_sim.c b/libeap/src/eap_peer/eap_sim.c similarity index 100% rename from src/eap_peer/eap_sim.c rename to libeap/src/eap_peer/eap_sim.c diff --git a/src/eap_peer/eap_tls.c b/libeap/src/eap_peer/eap_tls.c similarity index 100% rename from src/eap_peer/eap_tls.c rename to libeap/src/eap_peer/eap_tls.c diff --git a/src/eap_peer/eap_tls_common.c b/libeap/src/eap_peer/eap_tls_common.c similarity index 100% rename from src/eap_peer/eap_tls_common.c rename to libeap/src/eap_peer/eap_tls_common.c diff --git a/src/eap_peer/eap_tls_common.h b/libeap/src/eap_peer/eap_tls_common.h similarity index 100% rename from src/eap_peer/eap_tls_common.h rename to libeap/src/eap_peer/eap_tls_common.h diff --git a/src/eap_peer/eap_tnc.c b/libeap/src/eap_peer/eap_tnc.c similarity index 100% rename from src/eap_peer/eap_tnc.c rename to libeap/src/eap_peer/eap_tnc.c diff --git a/src/eap_peer/eap_ttls.c b/libeap/src/eap_peer/eap_ttls.c similarity index 100% rename from src/eap_peer/eap_ttls.c rename to libeap/src/eap_peer/eap_ttls.c diff --git a/src/eap_peer/eap_vendor_test.c b/libeap/src/eap_peer/eap_vendor_test.c similarity index 100% rename from src/eap_peer/eap_vendor_test.c rename to libeap/src/eap_peer/eap_vendor_test.c diff --git a/src/eap_peer/eap_wsc.c b/libeap/src/eap_peer/eap_wsc.c similarity index 100% rename from src/eap_peer/eap_wsc.c rename to libeap/src/eap_peer/eap_wsc.c diff --git a/src/eap_peer/ikev2.c b/libeap/src/eap_peer/ikev2.c similarity index 100% rename from src/eap_peer/ikev2.c rename to libeap/src/eap_peer/ikev2.c diff --git a/src/eap_peer/ikev2.h b/libeap/src/eap_peer/ikev2.h similarity index 100% rename from src/eap_peer/ikev2.h rename to libeap/src/eap_peer/ikev2.h diff --git a/src/eap_peer/mschapv2.c b/libeap/src/eap_peer/mschapv2.c similarity index 100% rename from src/eap_peer/mschapv2.c rename to libeap/src/eap_peer/mschapv2.c diff --git a/src/eap_peer/mschapv2.h b/libeap/src/eap_peer/mschapv2.h similarity index 100% rename from src/eap_peer/mschapv2.h rename to libeap/src/eap_peer/mschapv2.h diff --git a/src/eap_peer/tncc.c b/libeap/src/eap_peer/tncc.c similarity index 100% rename from src/eap_peer/tncc.c rename to libeap/src/eap_peer/tncc.c diff --git a/src/eap_peer/tncc.h b/libeap/src/eap_peer/tncc.h similarity index 100% rename from src/eap_peer/tncc.h rename to libeap/src/eap_peer/tncc.h diff --git a/src/eapol_supp/Makefile b/libeap/src/eap_server/Makefile similarity index 100% rename from src/eapol_supp/Makefile rename to libeap/src/eap_server/Makefile diff --git a/src/eap_server/eap.h b/libeap/src/eap_server/eap.h similarity index 100% rename from src/eap_server/eap.h rename to libeap/src/eap_server/eap.h diff --git a/src/eap_server/eap_i.h b/libeap/src/eap_server/eap_i.h similarity index 100% rename from src/eap_server/eap_i.h rename to libeap/src/eap_server/eap_i.h diff --git a/src/eap_server/eap_methods.h b/libeap/src/eap_server/eap_methods.h similarity index 100% rename from src/eap_server/eap_methods.h rename to libeap/src/eap_server/eap_methods.h diff --git a/src/eap_server/eap_server.c b/libeap/src/eap_server/eap_server.c similarity index 100% rename from src/eap_server/eap_server.c rename to libeap/src/eap_server/eap_server.c diff --git a/src/eap_server/eap_server_aka.c b/libeap/src/eap_server/eap_server_aka.c similarity index 100% rename from src/eap_server/eap_server_aka.c rename to libeap/src/eap_server/eap_server_aka.c diff --git a/src/eap_server/eap_server_fast.c b/libeap/src/eap_server/eap_server_fast.c similarity index 100% rename from src/eap_server/eap_server_fast.c rename to libeap/src/eap_server/eap_server_fast.c diff --git a/src/eap_server/eap_server_gpsk.c b/libeap/src/eap_server/eap_server_gpsk.c similarity index 100% rename from src/eap_server/eap_server_gpsk.c rename to libeap/src/eap_server/eap_server_gpsk.c diff --git a/src/eap_server/eap_server_gtc.c b/libeap/src/eap_server/eap_server_gtc.c similarity index 100% rename from src/eap_server/eap_server_gtc.c rename to libeap/src/eap_server/eap_server_gtc.c diff --git a/src/eap_server/eap_server_identity.c b/libeap/src/eap_server/eap_server_identity.c similarity index 100% rename from src/eap_server/eap_server_identity.c rename to libeap/src/eap_server/eap_server_identity.c diff --git a/src/eap_server/eap_server_ikev2.c b/libeap/src/eap_server/eap_server_ikev2.c similarity index 100% rename from src/eap_server/eap_server_ikev2.c rename to libeap/src/eap_server/eap_server_ikev2.c diff --git a/src/eap_server/eap_server_md5.c b/libeap/src/eap_server/eap_server_md5.c similarity index 100% rename from src/eap_server/eap_server_md5.c rename to libeap/src/eap_server/eap_server_md5.c diff --git a/src/eap_server/eap_server_methods.c b/libeap/src/eap_server/eap_server_methods.c similarity index 100% rename from src/eap_server/eap_server_methods.c rename to libeap/src/eap_server/eap_server_methods.c diff --git a/src/eap_server/eap_server_mschapv2.c b/libeap/src/eap_server/eap_server_mschapv2.c similarity index 100% rename from src/eap_server/eap_server_mschapv2.c rename to libeap/src/eap_server/eap_server_mschapv2.c diff --git a/src/eap_server/eap_server_pax.c b/libeap/src/eap_server/eap_server_pax.c similarity index 100% rename from src/eap_server/eap_server_pax.c rename to libeap/src/eap_server/eap_server_pax.c diff --git a/src/eap_server/eap_server_peap.c b/libeap/src/eap_server/eap_server_peap.c similarity index 100% rename from src/eap_server/eap_server_peap.c rename to libeap/src/eap_server/eap_server_peap.c diff --git a/src/eap_server/eap_server_psk.c b/libeap/src/eap_server/eap_server_psk.c similarity index 100% rename from src/eap_server/eap_server_psk.c rename to libeap/src/eap_server/eap_server_psk.c diff --git a/src/eap_server/eap_server_pwd.c b/libeap/src/eap_server/eap_server_pwd.c similarity index 100% rename from src/eap_server/eap_server_pwd.c rename to libeap/src/eap_server/eap_server_pwd.c diff --git a/src/eap_server/eap_server_sake.c b/libeap/src/eap_server/eap_server_sake.c similarity index 100% rename from src/eap_server/eap_server_sake.c rename to libeap/src/eap_server/eap_server_sake.c diff --git a/src/eap_server/eap_server_sim.c b/libeap/src/eap_server/eap_server_sim.c similarity index 100% rename from src/eap_server/eap_server_sim.c rename to libeap/src/eap_server/eap_server_sim.c diff --git a/src/eap_server/eap_server_tls.c b/libeap/src/eap_server/eap_server_tls.c similarity index 100% rename from src/eap_server/eap_server_tls.c rename to libeap/src/eap_server/eap_server_tls.c diff --git a/src/eap_server/eap_server_tls_common.c b/libeap/src/eap_server/eap_server_tls_common.c similarity index 100% rename from src/eap_server/eap_server_tls_common.c rename to libeap/src/eap_server/eap_server_tls_common.c diff --git a/src/eap_server/eap_server_tnc.c b/libeap/src/eap_server/eap_server_tnc.c similarity index 100% rename from src/eap_server/eap_server_tnc.c rename to libeap/src/eap_server/eap_server_tnc.c diff --git a/src/eap_server/eap_server_ttls.c b/libeap/src/eap_server/eap_server_ttls.c similarity index 100% rename from src/eap_server/eap_server_ttls.c rename to libeap/src/eap_server/eap_server_ttls.c diff --git a/src/eap_server/eap_server_vendor_test.c b/libeap/src/eap_server/eap_server_vendor_test.c similarity index 100% rename from src/eap_server/eap_server_vendor_test.c rename to libeap/src/eap_server/eap_server_vendor_test.c diff --git a/src/eap_server/eap_server_wsc.c b/libeap/src/eap_server/eap_server_wsc.c similarity index 100% rename from src/eap_server/eap_server_wsc.c rename to libeap/src/eap_server/eap_server_wsc.c diff --git a/src/eap_server/eap_sim_db.c b/libeap/src/eap_server/eap_sim_db.c similarity index 100% rename from src/eap_server/eap_sim_db.c rename to libeap/src/eap_server/eap_sim_db.c diff --git a/src/eap_server/eap_sim_db.h b/libeap/src/eap_server/eap_sim_db.h similarity index 100% rename from src/eap_server/eap_sim_db.h rename to libeap/src/eap_server/eap_sim_db.h diff --git a/src/eap_server/eap_tls_common.h b/libeap/src/eap_server/eap_tls_common.h similarity index 100% rename from src/eap_server/eap_tls_common.h rename to libeap/src/eap_server/eap_tls_common.h diff --git a/src/eap_server/ikev2.c b/libeap/src/eap_server/ikev2.c similarity index 100% rename from src/eap_server/ikev2.c rename to libeap/src/eap_server/ikev2.c diff --git a/src/eap_server/ikev2.h b/libeap/src/eap_server/ikev2.h similarity index 100% rename from src/eap_server/ikev2.h rename to libeap/src/eap_server/ikev2.h diff --git a/src/eap_server/tncs.c b/libeap/src/eap_server/tncs.c similarity index 100% rename from src/eap_server/tncs.c rename to libeap/src/eap_server/tncs.c diff --git a/src/eap_server/tncs.h b/libeap/src/eap_server/tncs.h similarity index 100% rename from src/eap_server/tncs.h rename to libeap/src/eap_server/tncs.h diff --git a/src/eapol_auth/Makefile b/libeap/src/eapol_auth/Makefile similarity index 100% rename from src/eapol_auth/Makefile rename to libeap/src/eapol_auth/Makefile diff --git a/src/eapol_auth/eapol_auth_dump.c b/libeap/src/eapol_auth/eapol_auth_dump.c similarity index 100% rename from src/eapol_auth/eapol_auth_dump.c rename to libeap/src/eapol_auth/eapol_auth_dump.c diff --git a/src/eapol_auth/eapol_auth_sm.c b/libeap/src/eapol_auth/eapol_auth_sm.c similarity index 100% rename from src/eapol_auth/eapol_auth_sm.c rename to libeap/src/eapol_auth/eapol_auth_sm.c diff --git a/src/eapol_auth/eapol_auth_sm.h b/libeap/src/eapol_auth/eapol_auth_sm.h similarity index 100% rename from src/eapol_auth/eapol_auth_sm.h rename to libeap/src/eapol_auth/eapol_auth_sm.h diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/libeap/src/eapol_auth/eapol_auth_sm_i.h similarity index 100% rename from src/eapol_auth/eapol_auth_sm_i.h rename to libeap/src/eapol_auth/eapol_auth_sm_i.h diff --git a/src/eap_server/Makefile b/libeap/src/eapol_supp/Makefile similarity index 100% rename from src/eap_server/Makefile rename to libeap/src/eapol_supp/Makefile diff --git a/src/eapol_supp/eapol_supp_sm.c b/libeap/src/eapol_supp/eapol_supp_sm.c similarity index 100% rename from src/eapol_supp/eapol_supp_sm.c rename to libeap/src/eapol_supp/eapol_supp_sm.c diff --git a/src/eapol_supp/eapol_supp_sm.h b/libeap/src/eapol_supp/eapol_supp_sm.h similarity index 100% rename from src/eapol_supp/eapol_supp_sm.h rename to libeap/src/eapol_supp/eapol_supp_sm.h diff --git a/src/eap_common/Makefile b/libeap/src/l2_packet/Makefile similarity index 100% rename from src/eap_common/Makefile rename to libeap/src/l2_packet/Makefile diff --git a/src/l2_packet/l2_packet.h b/libeap/src/l2_packet/l2_packet.h similarity index 100% rename from src/l2_packet/l2_packet.h rename to libeap/src/l2_packet/l2_packet.h diff --git a/src/l2_packet/l2_packet_freebsd.c b/libeap/src/l2_packet/l2_packet_freebsd.c similarity index 100% rename from src/l2_packet/l2_packet_freebsd.c rename to libeap/src/l2_packet/l2_packet_freebsd.c diff --git a/src/l2_packet/l2_packet_linux.c b/libeap/src/l2_packet/l2_packet_linux.c similarity index 100% rename from src/l2_packet/l2_packet_linux.c rename to libeap/src/l2_packet/l2_packet_linux.c diff --git a/src/l2_packet/l2_packet_ndis.c b/libeap/src/l2_packet/l2_packet_ndis.c similarity index 100% rename from src/l2_packet/l2_packet_ndis.c rename to libeap/src/l2_packet/l2_packet_ndis.c diff --git a/src/l2_packet/l2_packet_none.c b/libeap/src/l2_packet/l2_packet_none.c similarity index 100% rename from src/l2_packet/l2_packet_none.c rename to libeap/src/l2_packet/l2_packet_none.c diff --git a/src/l2_packet/l2_packet_pcap.c b/libeap/src/l2_packet/l2_packet_pcap.c similarity index 100% rename from src/l2_packet/l2_packet_pcap.c rename to libeap/src/l2_packet/l2_packet_pcap.c diff --git a/src/l2_packet/l2_packet_privsep.c b/libeap/src/l2_packet/l2_packet_privsep.c similarity index 100% rename from src/l2_packet/l2_packet_privsep.c rename to libeap/src/l2_packet/l2_packet_privsep.c diff --git a/src/l2_packet/l2_packet_winpcap.c b/libeap/src/l2_packet/l2_packet_winpcap.c similarity index 100% rename from src/l2_packet/l2_packet_winpcap.c rename to libeap/src/l2_packet/l2_packet_winpcap.c diff --git a/src/lib.rules b/libeap/src/lib.rules similarity index 100% rename from src/lib.rules rename to libeap/src/lib.rules diff --git a/src/p2p/Makefile b/libeap/src/p2p/Makefile similarity index 100% rename from src/p2p/Makefile rename to libeap/src/p2p/Makefile diff --git a/src/p2p/p2p.c b/libeap/src/p2p/p2p.c similarity index 100% rename from src/p2p/p2p.c rename to libeap/src/p2p/p2p.c diff --git a/src/p2p/p2p.h b/libeap/src/p2p/p2p.h similarity index 100% rename from src/p2p/p2p.h rename to libeap/src/p2p/p2p.h diff --git a/src/p2p/p2p_build.c b/libeap/src/p2p/p2p_build.c similarity index 100% rename from src/p2p/p2p_build.c rename to libeap/src/p2p/p2p_build.c diff --git a/src/p2p/p2p_dev_disc.c b/libeap/src/p2p/p2p_dev_disc.c similarity index 100% rename from src/p2p/p2p_dev_disc.c rename to libeap/src/p2p/p2p_dev_disc.c diff --git a/src/p2p/p2p_go_neg.c b/libeap/src/p2p/p2p_go_neg.c similarity index 100% rename from src/p2p/p2p_go_neg.c rename to libeap/src/p2p/p2p_go_neg.c diff --git a/src/p2p/p2p_group.c b/libeap/src/p2p/p2p_group.c similarity index 100% rename from src/p2p/p2p_group.c rename to libeap/src/p2p/p2p_group.c diff --git a/src/p2p/p2p_i.h b/libeap/src/p2p/p2p_i.h similarity index 100% rename from src/p2p/p2p_i.h rename to libeap/src/p2p/p2p_i.h diff --git a/src/p2p/p2p_invitation.c b/libeap/src/p2p/p2p_invitation.c similarity index 100% rename from src/p2p/p2p_invitation.c rename to libeap/src/p2p/p2p_invitation.c diff --git a/src/p2p/p2p_parse.c b/libeap/src/p2p/p2p_parse.c similarity index 100% rename from src/p2p/p2p_parse.c rename to libeap/src/p2p/p2p_parse.c diff --git a/src/p2p/p2p_pd.c b/libeap/src/p2p/p2p_pd.c similarity index 100% rename from src/p2p/p2p_pd.c rename to libeap/src/p2p/p2p_pd.c diff --git a/src/p2p/p2p_sd.c b/libeap/src/p2p/p2p_sd.c similarity index 100% rename from src/p2p/p2p_sd.c rename to libeap/src/p2p/p2p_sd.c diff --git a/src/p2p/p2p_utils.c b/libeap/src/p2p/p2p_utils.c similarity index 100% rename from src/p2p/p2p_utils.c rename to libeap/src/p2p/p2p_utils.c diff --git a/src/radius/.gitignore b/libeap/src/radius/.gitignore similarity index 100% rename from src/radius/.gitignore rename to libeap/src/radius/.gitignore diff --git a/src/radius/Makefile b/libeap/src/radius/Makefile similarity index 100% rename from src/radius/Makefile rename to libeap/src/radius/Makefile diff --git a/src/radius/radius.c b/libeap/src/radius/radius.c similarity index 100% rename from src/radius/radius.c rename to libeap/src/radius/radius.c diff --git a/src/radius/radius.h b/libeap/src/radius/radius.h similarity index 100% rename from src/radius/radius.h rename to libeap/src/radius/radius.h diff --git a/src/radius/radius_client.c b/libeap/src/radius/radius_client.c similarity index 100% rename from src/radius/radius_client.c rename to libeap/src/radius/radius_client.c diff --git a/src/radius/radius_client.h b/libeap/src/radius/radius_client.h similarity index 100% rename from src/radius/radius_client.h rename to libeap/src/radius/radius_client.h diff --git a/src/radius/radius_server.c b/libeap/src/radius/radius_server.c similarity index 100% rename from src/radius/radius_server.c rename to libeap/src/radius/radius_server.c diff --git a/src/radius/radius_server.h b/libeap/src/radius/radius_server.h similarity index 100% rename from src/radius/radius_server.h rename to libeap/src/radius/radius_server.h diff --git a/src/common/Makefile b/libeap/src/rsn_supp/Makefile similarity index 100% rename from src/common/Makefile rename to libeap/src/rsn_supp/Makefile diff --git a/src/rsn_supp/peerkey.c b/libeap/src/rsn_supp/peerkey.c similarity index 100% rename from src/rsn_supp/peerkey.c rename to libeap/src/rsn_supp/peerkey.c diff --git a/src/rsn_supp/peerkey.h b/libeap/src/rsn_supp/peerkey.h similarity index 100% rename from src/rsn_supp/peerkey.h rename to libeap/src/rsn_supp/peerkey.h diff --git a/src/rsn_supp/pmksa_cache.c b/libeap/src/rsn_supp/pmksa_cache.c similarity index 100% rename from src/rsn_supp/pmksa_cache.c rename to libeap/src/rsn_supp/pmksa_cache.c diff --git a/src/rsn_supp/pmksa_cache.h b/libeap/src/rsn_supp/pmksa_cache.h similarity index 100% rename from src/rsn_supp/pmksa_cache.h rename to libeap/src/rsn_supp/pmksa_cache.h diff --git a/src/rsn_supp/preauth.c b/libeap/src/rsn_supp/preauth.c similarity index 100% rename from src/rsn_supp/preauth.c rename to libeap/src/rsn_supp/preauth.c diff --git a/src/rsn_supp/preauth.h b/libeap/src/rsn_supp/preauth.h similarity index 100% rename from src/rsn_supp/preauth.h rename to libeap/src/rsn_supp/preauth.h diff --git a/src/rsn_supp/wpa.c b/libeap/src/rsn_supp/wpa.c similarity index 100% rename from src/rsn_supp/wpa.c rename to libeap/src/rsn_supp/wpa.c diff --git a/src/rsn_supp/wpa.h b/libeap/src/rsn_supp/wpa.h similarity index 100% rename from src/rsn_supp/wpa.h rename to libeap/src/rsn_supp/wpa.h diff --git a/src/rsn_supp/wpa_ft.c b/libeap/src/rsn_supp/wpa_ft.c similarity index 100% rename from src/rsn_supp/wpa_ft.c rename to libeap/src/rsn_supp/wpa_ft.c diff --git a/src/rsn_supp/wpa_i.h b/libeap/src/rsn_supp/wpa_i.h similarity index 100% rename from src/rsn_supp/wpa_i.h rename to libeap/src/rsn_supp/wpa_i.h diff --git a/src/rsn_supp/wpa_ie.c b/libeap/src/rsn_supp/wpa_ie.c similarity index 100% rename from src/rsn_supp/wpa_ie.c rename to libeap/src/rsn_supp/wpa_ie.c diff --git a/src/rsn_supp/wpa_ie.h b/libeap/src/rsn_supp/wpa_ie.h similarity index 100% rename from src/rsn_supp/wpa_ie.h rename to libeap/src/rsn_supp/wpa_ie.h diff --git a/src/tls/.gitignore b/libeap/src/tls/.gitignore similarity index 100% rename from src/tls/.gitignore rename to libeap/src/tls/.gitignore diff --git a/src/tls/Makefile b/libeap/src/tls/Makefile similarity index 100% rename from src/tls/Makefile rename to libeap/src/tls/Makefile diff --git a/src/tls/asn1.c b/libeap/src/tls/asn1.c similarity index 100% rename from src/tls/asn1.c rename to libeap/src/tls/asn1.c diff --git a/src/tls/asn1.h b/libeap/src/tls/asn1.h similarity index 100% rename from src/tls/asn1.h rename to libeap/src/tls/asn1.h diff --git a/src/tls/bignum.c b/libeap/src/tls/bignum.c similarity index 100% rename from src/tls/bignum.c rename to libeap/src/tls/bignum.c diff --git a/src/tls/bignum.h b/libeap/src/tls/bignum.h similarity index 100% rename from src/tls/bignum.h rename to libeap/src/tls/bignum.h diff --git a/src/tls/libtommath.c b/libeap/src/tls/libtommath.c similarity index 100% rename from src/tls/libtommath.c rename to libeap/src/tls/libtommath.c diff --git a/src/tls/pkcs1.c b/libeap/src/tls/pkcs1.c similarity index 100% rename from src/tls/pkcs1.c rename to libeap/src/tls/pkcs1.c diff --git a/src/tls/pkcs1.h b/libeap/src/tls/pkcs1.h similarity index 100% rename from src/tls/pkcs1.h rename to libeap/src/tls/pkcs1.h diff --git a/src/tls/pkcs5.c b/libeap/src/tls/pkcs5.c similarity index 100% rename from src/tls/pkcs5.c rename to libeap/src/tls/pkcs5.c diff --git a/src/tls/pkcs5.h b/libeap/src/tls/pkcs5.h similarity index 100% rename from src/tls/pkcs5.h rename to libeap/src/tls/pkcs5.h diff --git a/src/tls/pkcs8.c b/libeap/src/tls/pkcs8.c similarity index 100% rename from src/tls/pkcs8.c rename to libeap/src/tls/pkcs8.c diff --git a/src/tls/pkcs8.h b/libeap/src/tls/pkcs8.h similarity index 100% rename from src/tls/pkcs8.h rename to libeap/src/tls/pkcs8.h diff --git a/src/tls/rsa.c b/libeap/src/tls/rsa.c similarity index 100% rename from src/tls/rsa.c rename to libeap/src/tls/rsa.c diff --git a/src/tls/rsa.h b/libeap/src/tls/rsa.h similarity index 100% rename from src/tls/rsa.h rename to libeap/src/tls/rsa.h diff --git a/src/tls/tlsv1_client.c b/libeap/src/tls/tlsv1_client.c similarity index 100% rename from src/tls/tlsv1_client.c rename to libeap/src/tls/tlsv1_client.c diff --git a/src/tls/tlsv1_client.h b/libeap/src/tls/tlsv1_client.h similarity index 100% rename from src/tls/tlsv1_client.h rename to libeap/src/tls/tlsv1_client.h diff --git a/src/tls/tlsv1_client_i.h b/libeap/src/tls/tlsv1_client_i.h similarity index 100% rename from src/tls/tlsv1_client_i.h rename to libeap/src/tls/tlsv1_client_i.h diff --git a/src/tls/tlsv1_client_read.c b/libeap/src/tls/tlsv1_client_read.c similarity index 100% rename from src/tls/tlsv1_client_read.c rename to libeap/src/tls/tlsv1_client_read.c diff --git a/src/tls/tlsv1_client_write.c b/libeap/src/tls/tlsv1_client_write.c similarity index 100% rename from src/tls/tlsv1_client_write.c rename to libeap/src/tls/tlsv1_client_write.c diff --git a/src/tls/tlsv1_common.c b/libeap/src/tls/tlsv1_common.c similarity index 100% rename from src/tls/tlsv1_common.c rename to libeap/src/tls/tlsv1_common.c diff --git a/src/tls/tlsv1_common.h b/libeap/src/tls/tlsv1_common.h similarity index 100% rename from src/tls/tlsv1_common.h rename to libeap/src/tls/tlsv1_common.h diff --git a/src/tls/tlsv1_cred.c b/libeap/src/tls/tlsv1_cred.c similarity index 100% rename from src/tls/tlsv1_cred.c rename to libeap/src/tls/tlsv1_cred.c diff --git a/src/tls/tlsv1_cred.h b/libeap/src/tls/tlsv1_cred.h similarity index 100% rename from src/tls/tlsv1_cred.h rename to libeap/src/tls/tlsv1_cred.h diff --git a/src/tls/tlsv1_record.c b/libeap/src/tls/tlsv1_record.c similarity index 100% rename from src/tls/tlsv1_record.c rename to libeap/src/tls/tlsv1_record.c diff --git a/src/tls/tlsv1_record.h b/libeap/src/tls/tlsv1_record.h similarity index 100% rename from src/tls/tlsv1_record.h rename to libeap/src/tls/tlsv1_record.h diff --git a/src/tls/tlsv1_server.c b/libeap/src/tls/tlsv1_server.c similarity index 100% rename from src/tls/tlsv1_server.c rename to libeap/src/tls/tlsv1_server.c diff --git a/src/tls/tlsv1_server.h b/libeap/src/tls/tlsv1_server.h similarity index 100% rename from src/tls/tlsv1_server.h rename to libeap/src/tls/tlsv1_server.h diff --git a/src/tls/tlsv1_server_i.h b/libeap/src/tls/tlsv1_server_i.h similarity index 100% rename from src/tls/tlsv1_server_i.h rename to libeap/src/tls/tlsv1_server_i.h diff --git a/src/tls/tlsv1_server_read.c b/libeap/src/tls/tlsv1_server_read.c similarity index 100% rename from src/tls/tlsv1_server_read.c rename to libeap/src/tls/tlsv1_server_read.c diff --git a/src/tls/tlsv1_server_write.c b/libeap/src/tls/tlsv1_server_write.c similarity index 100% rename from src/tls/tlsv1_server_write.c rename to libeap/src/tls/tlsv1_server_write.c diff --git a/src/tls/x509v3.c b/libeap/src/tls/x509v3.c similarity index 100% rename from src/tls/x509v3.c rename to libeap/src/tls/x509v3.c diff --git a/src/tls/x509v3.h b/libeap/src/tls/x509v3.h similarity index 100% rename from src/tls/x509v3.h rename to libeap/src/tls/x509v3.h diff --git a/src/utils/.gitignore b/libeap/src/utils/.gitignore similarity index 100% rename from src/utils/.gitignore rename to libeap/src/utils/.gitignore diff --git a/src/utils/Makefile b/libeap/src/utils/Makefile similarity index 100% rename from src/utils/Makefile rename to libeap/src/utils/Makefile diff --git a/src/utils/base64.c b/libeap/src/utils/base64.c similarity index 100% rename from src/utils/base64.c rename to libeap/src/utils/base64.c diff --git a/src/utils/base64.h b/libeap/src/utils/base64.h similarity index 100% rename from src/utils/base64.h rename to libeap/src/utils/base64.h diff --git a/src/utils/build_config.h b/libeap/src/utils/build_config.h similarity index 100% rename from src/utils/build_config.h rename to libeap/src/utils/build_config.h diff --git a/src/utils/common.c b/libeap/src/utils/common.c similarity index 100% rename from src/utils/common.c rename to libeap/src/utils/common.c diff --git a/src/utils/common.h b/libeap/src/utils/common.h similarity index 100% rename from src/utils/common.h rename to libeap/src/utils/common.h diff --git a/src/utils/eloop.c b/libeap/src/utils/eloop.c similarity index 100% rename from src/utils/eloop.c rename to libeap/src/utils/eloop.c diff --git a/src/utils/eloop.h b/libeap/src/utils/eloop.h similarity index 100% rename from src/utils/eloop.h rename to libeap/src/utils/eloop.h diff --git a/src/utils/eloop_none.c b/libeap/src/utils/eloop_none.c similarity index 100% rename from src/utils/eloop_none.c rename to libeap/src/utils/eloop_none.c diff --git a/src/utils/eloop_win.c b/libeap/src/utils/eloop_win.c similarity index 100% rename from src/utils/eloop_win.c rename to libeap/src/utils/eloop_win.c diff --git a/src/utils/includes.h b/libeap/src/utils/includes.h similarity index 100% rename from src/utils/includes.h rename to libeap/src/utils/includes.h diff --git a/src/utils/ip_addr.c b/libeap/src/utils/ip_addr.c similarity index 100% rename from src/utils/ip_addr.c rename to libeap/src/utils/ip_addr.c diff --git a/src/utils/ip_addr.h b/libeap/src/utils/ip_addr.h similarity index 100% rename from src/utils/ip_addr.h rename to libeap/src/utils/ip_addr.h diff --git a/src/utils/list.h b/libeap/src/utils/list.h similarity index 100% rename from src/utils/list.h rename to libeap/src/utils/list.h diff --git a/src/utils/os.h b/libeap/src/utils/os.h similarity index 100% rename from src/utils/os.h rename to libeap/src/utils/os.h diff --git a/src/utils/os_internal.c b/libeap/src/utils/os_internal.c similarity index 100% rename from src/utils/os_internal.c rename to libeap/src/utils/os_internal.c diff --git a/src/utils/os_none.c b/libeap/src/utils/os_none.c similarity index 100% rename from src/utils/os_none.c rename to libeap/src/utils/os_none.c diff --git a/src/utils/os_unix.c b/libeap/src/utils/os_unix.c similarity index 100% rename from src/utils/os_unix.c rename to libeap/src/utils/os_unix.c diff --git a/src/utils/os_win32.c b/libeap/src/utils/os_win32.c similarity index 100% rename from src/utils/os_win32.c rename to libeap/src/utils/os_win32.c diff --git a/src/utils/pcsc_funcs.c b/libeap/src/utils/pcsc_funcs.c similarity index 100% rename from src/utils/pcsc_funcs.c rename to libeap/src/utils/pcsc_funcs.c diff --git a/src/utils/pcsc_funcs.h b/libeap/src/utils/pcsc_funcs.h similarity index 100% rename from src/utils/pcsc_funcs.h rename to libeap/src/utils/pcsc_funcs.h diff --git a/src/utils/radiotap.c b/libeap/src/utils/radiotap.c similarity index 100% rename from src/utils/radiotap.c rename to libeap/src/utils/radiotap.c diff --git a/src/utils/radiotap.h b/libeap/src/utils/radiotap.h similarity index 100% rename from src/utils/radiotap.h rename to libeap/src/utils/radiotap.h diff --git a/src/utils/radiotap_iter.h b/libeap/src/utils/radiotap_iter.h similarity index 100% rename from src/utils/radiotap_iter.h rename to libeap/src/utils/radiotap_iter.h diff --git a/src/utils/state_machine.h b/libeap/src/utils/state_machine.h similarity index 100% rename from src/utils/state_machine.h rename to libeap/src/utils/state_machine.h diff --git a/src/utils/trace.c b/libeap/src/utils/trace.c similarity index 100% rename from src/utils/trace.c rename to libeap/src/utils/trace.c diff --git a/src/utils/trace.h b/libeap/src/utils/trace.h similarity index 100% rename from src/utils/trace.h rename to libeap/src/utils/trace.h diff --git a/src/utils/uuid.c b/libeap/src/utils/uuid.c similarity index 100% rename from src/utils/uuid.c rename to libeap/src/utils/uuid.c diff --git a/src/utils/uuid.h b/libeap/src/utils/uuid.h similarity index 100% rename from src/utils/uuid.h rename to libeap/src/utils/uuid.h diff --git a/src/utils/wpa_debug.c b/libeap/src/utils/wpa_debug.c similarity index 100% rename from src/utils/wpa_debug.c rename to libeap/src/utils/wpa_debug.c diff --git a/src/utils/wpa_debug.h b/libeap/src/utils/wpa_debug.h similarity index 100% rename from src/utils/wpa_debug.h rename to libeap/src/utils/wpa_debug.h diff --git a/src/utils/wpabuf.c b/libeap/src/utils/wpabuf.c similarity index 100% rename from src/utils/wpabuf.c rename to libeap/src/utils/wpabuf.c diff --git a/src/utils/wpabuf.h b/libeap/src/utils/wpabuf.h similarity index 100% rename from src/utils/wpabuf.h rename to libeap/src/utils/wpabuf.h diff --git a/src/ap/Makefile b/libeap/src/wps/Makefile similarity index 100% rename from src/ap/Makefile rename to libeap/src/wps/Makefile diff --git a/src/wps/http.h b/libeap/src/wps/http.h similarity index 100% rename from src/wps/http.h rename to libeap/src/wps/http.h diff --git a/src/wps/http_client.c b/libeap/src/wps/http_client.c similarity index 100% rename from src/wps/http_client.c rename to libeap/src/wps/http_client.c diff --git a/src/wps/http_client.h b/libeap/src/wps/http_client.h similarity index 100% rename from src/wps/http_client.h rename to libeap/src/wps/http_client.h diff --git a/src/wps/http_server.c b/libeap/src/wps/http_server.c similarity index 100% rename from src/wps/http_server.c rename to libeap/src/wps/http_server.c diff --git a/src/wps/http_server.h b/libeap/src/wps/http_server.h similarity index 100% rename from src/wps/http_server.h rename to libeap/src/wps/http_server.h diff --git a/src/wps/httpread.c b/libeap/src/wps/httpread.c similarity index 100% rename from src/wps/httpread.c rename to libeap/src/wps/httpread.c diff --git a/src/wps/httpread.h b/libeap/src/wps/httpread.h similarity index 100% rename from src/wps/httpread.h rename to libeap/src/wps/httpread.h diff --git a/src/wps/ndef.c b/libeap/src/wps/ndef.c similarity index 100% rename from src/wps/ndef.c rename to libeap/src/wps/ndef.c diff --git a/src/wps/upnp_xml.c b/libeap/src/wps/upnp_xml.c similarity index 100% rename from src/wps/upnp_xml.c rename to libeap/src/wps/upnp_xml.c diff --git a/src/wps/upnp_xml.h b/libeap/src/wps/upnp_xml.h similarity index 100% rename from src/wps/upnp_xml.h rename to libeap/src/wps/upnp_xml.h diff --git a/src/wps/wps.c b/libeap/src/wps/wps.c similarity index 100% rename from src/wps/wps.c rename to libeap/src/wps/wps.c diff --git a/src/wps/wps.h b/libeap/src/wps/wps.h similarity index 100% rename from src/wps/wps.h rename to libeap/src/wps/wps.h diff --git a/src/wps/wps_attr_build.c b/libeap/src/wps/wps_attr_build.c similarity index 100% rename from src/wps/wps_attr_build.c rename to libeap/src/wps/wps_attr_build.c diff --git a/src/wps/wps_attr_parse.c b/libeap/src/wps/wps_attr_parse.c similarity index 100% rename from src/wps/wps_attr_parse.c rename to libeap/src/wps/wps_attr_parse.c diff --git a/src/wps/wps_attr_process.c b/libeap/src/wps/wps_attr_process.c similarity index 100% rename from src/wps/wps_attr_process.c rename to libeap/src/wps/wps_attr_process.c diff --git a/src/wps/wps_common.c b/libeap/src/wps/wps_common.c similarity index 100% rename from src/wps/wps_common.c rename to libeap/src/wps/wps_common.c diff --git a/src/wps/wps_defs.h b/libeap/src/wps/wps_defs.h similarity index 100% rename from src/wps/wps_defs.h rename to libeap/src/wps/wps_defs.h diff --git a/src/wps/wps_dev_attr.c b/libeap/src/wps/wps_dev_attr.c similarity index 100% rename from src/wps/wps_dev_attr.c rename to libeap/src/wps/wps_dev_attr.c diff --git a/src/wps/wps_dev_attr.h b/libeap/src/wps/wps_dev_attr.h similarity index 100% rename from src/wps/wps_dev_attr.h rename to libeap/src/wps/wps_dev_attr.h diff --git a/src/wps/wps_enrollee.c b/libeap/src/wps/wps_enrollee.c similarity index 100% rename from src/wps/wps_enrollee.c rename to libeap/src/wps/wps_enrollee.c diff --git a/src/wps/wps_er.c b/libeap/src/wps/wps_er.c similarity index 100% rename from src/wps/wps_er.c rename to libeap/src/wps/wps_er.c diff --git a/src/wps/wps_er.h b/libeap/src/wps/wps_er.h similarity index 100% rename from src/wps/wps_er.h rename to libeap/src/wps/wps_er.h diff --git a/src/wps/wps_er_ssdp.c b/libeap/src/wps/wps_er_ssdp.c similarity index 100% rename from src/wps/wps_er_ssdp.c rename to libeap/src/wps/wps_er_ssdp.c diff --git a/src/wps/wps_i.h b/libeap/src/wps/wps_i.h similarity index 100% rename from src/wps/wps_i.h rename to libeap/src/wps/wps_i.h diff --git a/src/wps/wps_nfc.c b/libeap/src/wps/wps_nfc.c similarity index 100% rename from src/wps/wps_nfc.c rename to libeap/src/wps/wps_nfc.c diff --git a/src/wps/wps_nfc_pn531.c b/libeap/src/wps/wps_nfc_pn531.c similarity index 100% rename from src/wps/wps_nfc_pn531.c rename to libeap/src/wps/wps_nfc_pn531.c diff --git a/src/wps/wps_registrar.c b/libeap/src/wps/wps_registrar.c similarity index 100% rename from src/wps/wps_registrar.c rename to libeap/src/wps/wps_registrar.c diff --git a/src/wps/wps_ufd.c b/libeap/src/wps/wps_ufd.c similarity index 100% rename from src/wps/wps_ufd.c rename to libeap/src/wps/wps_ufd.c diff --git a/src/wps/wps_upnp.c b/libeap/src/wps/wps_upnp.c similarity index 100% rename from src/wps/wps_upnp.c rename to libeap/src/wps/wps_upnp.c diff --git a/src/wps/wps_upnp.h b/libeap/src/wps/wps_upnp.h similarity index 100% rename from src/wps/wps_upnp.h rename to libeap/src/wps/wps_upnp.h diff --git a/src/wps/wps_upnp_ap.c b/libeap/src/wps/wps_upnp_ap.c similarity index 100% rename from src/wps/wps_upnp_ap.c rename to libeap/src/wps/wps_upnp_ap.c diff --git a/src/wps/wps_upnp_event.c b/libeap/src/wps/wps_upnp_event.c similarity index 100% rename from src/wps/wps_upnp_event.c rename to libeap/src/wps/wps_upnp_event.c diff --git a/src/wps/wps_upnp_i.h b/libeap/src/wps/wps_upnp_i.h similarity index 100% rename from src/wps/wps_upnp_i.h rename to libeap/src/wps/wps_upnp_i.h diff --git a/src/wps/wps_upnp_ssdp.c b/libeap/src/wps/wps_upnp_ssdp.c similarity index 100% rename from src/wps/wps_upnp_ssdp.c rename to libeap/src/wps/wps_upnp_ssdp.c diff --git a/src/wps/wps_upnp_web.c b/libeap/src/wps/wps_upnp_web.c similarity index 100% rename from src/wps/wps_upnp_web.c rename to libeap/src/wps/wps_upnp_web.c diff --git a/src/wps/wps_validate.c b/libeap/src/wps/wps_validate.c similarity index 100% rename from src/wps/wps_validate.c rename to libeap/src/wps/wps_validate.c diff --git a/testing/compile_wireless_versions b/libeap/testing/compile_wireless_versions similarity index 100% rename from testing/compile_wireless_versions rename to libeap/testing/compile_wireless_versions diff --git a/testing/hostapd-config/arm b/libeap/testing/hostapd-config/arm similarity index 100% rename from testing/hostapd-config/arm rename to libeap/testing/hostapd-config/arm diff --git a/testing/hostapd-config/arm-0.4 b/libeap/testing/hostapd-config/arm-0.4 similarity index 100% rename from testing/hostapd-config/arm-0.4 rename to libeap/testing/hostapd-config/arm-0.4 diff --git a/testing/hostapd-config/freebsd b/libeap/testing/hostapd-config/freebsd similarity index 100% rename from testing/hostapd-config/freebsd rename to libeap/testing/hostapd-config/freebsd diff --git a/testing/hostapd-config/full b/libeap/testing/hostapd-config/full similarity index 100% rename from testing/hostapd-config/full rename to libeap/testing/hostapd-config/full diff --git a/testing/hostapd-config/full-0.4 b/libeap/testing/hostapd-config/full-0.4 similarity index 100% rename from testing/hostapd-config/full-0.4 rename to libeap/testing/hostapd-config/full-0.4 diff --git a/testing/hostapd-config/gcc-cvs b/libeap/testing/hostapd-config/gcc-cvs similarity index 100% rename from testing/hostapd-config/gcc-cvs rename to libeap/testing/hostapd-config/gcc-cvs diff --git a/testing/hostapd-config/minimal b/libeap/testing/hostapd-config/minimal similarity index 100% rename from testing/hostapd-config/minimal rename to libeap/testing/hostapd-config/minimal diff --git a/testing/hostapd-config/minimal-0.4 b/libeap/testing/hostapd-config/minimal-0.4 similarity index 100% rename from testing/hostapd-config/minimal-0.4 rename to libeap/testing/hostapd-config/minimal-0.4 diff --git a/testing/hostapd-config/noeap b/libeap/testing/hostapd-config/noeap similarity index 100% rename from testing/hostapd-config/noeap rename to libeap/testing/hostapd-config/noeap diff --git a/testing/hostapd-config/noeap-0.4 b/libeap/testing/hostapd-config/noeap-0.4 similarity index 100% rename from testing/hostapd-config/noeap-0.4 rename to libeap/testing/hostapd-config/noeap-0.4 diff --git a/testing/hostapd-config/x86_64 b/libeap/testing/hostapd-config/x86_64 similarity index 100% rename from testing/hostapd-config/x86_64 rename to libeap/testing/hostapd-config/x86_64 diff --git a/testing/run-hostapd b/libeap/testing/run-hostapd similarity index 100% rename from testing/run-hostapd rename to libeap/testing/run-hostapd diff --git a/testing/run-hostapd-0.3 b/libeap/testing/run-hostapd-0.3 similarity index 100% rename from testing/run-hostapd-0.3 rename to libeap/testing/run-hostapd-0.3 diff --git a/testing/run-hostapd-0.4 b/libeap/testing/run-hostapd-0.4 similarity index 100% rename from testing/run-hostapd-0.4 rename to libeap/testing/run-hostapd-0.4 diff --git a/testing/run-wpa_supplicant b/libeap/testing/run-wpa_supplicant similarity index 100% rename from testing/run-wpa_supplicant rename to libeap/testing/run-wpa_supplicant diff --git a/testing/run-wpa_supplicant-0.3 b/libeap/testing/run-wpa_supplicant-0.3 similarity index 100% rename from testing/run-wpa_supplicant-0.3 rename to libeap/testing/run-wpa_supplicant-0.3 diff --git a/testing/run-wpa_supplicant-0.4 b/libeap/testing/run-wpa_supplicant-0.4 similarity index 100% rename from testing/run-wpa_supplicant-0.4 rename to libeap/testing/run-wpa_supplicant-0.4 diff --git a/testing/wireless/iw_handler-2.h b/libeap/testing/wireless/iw_handler-2.h similarity index 100% rename from testing/wireless/iw_handler-2.h rename to libeap/testing/wireless/iw_handler-2.h diff --git a/testing/wireless/iw_handler-3.h b/libeap/testing/wireless/iw_handler-3.h similarity index 100% rename from testing/wireless/iw_handler-3.h rename to libeap/testing/wireless/iw_handler-3.h diff --git a/testing/wireless/iw_handler-4.h b/libeap/testing/wireless/iw_handler-4.h similarity index 100% rename from testing/wireless/iw_handler-4.h rename to libeap/testing/wireless/iw_handler-4.h diff --git a/testing/wireless/iw_handler-5.h b/libeap/testing/wireless/iw_handler-5.h similarity index 100% rename from testing/wireless/iw_handler-5.h rename to libeap/testing/wireless/iw_handler-5.h diff --git a/testing/wireless/iw_handler-6.h b/libeap/testing/wireless/iw_handler-6.h similarity index 100% rename from testing/wireless/iw_handler-6.h rename to libeap/testing/wireless/iw_handler-6.h diff --git a/testing/wireless/iw_handler-7.h b/libeap/testing/wireless/iw_handler-7.h similarity index 100% rename from testing/wireless/iw_handler-7.h rename to libeap/testing/wireless/iw_handler-7.h diff --git a/testing/wireless/wireless-10.h b/libeap/testing/wireless/wireless-10.h similarity index 100% rename from testing/wireless/wireless-10.h rename to libeap/testing/wireless/wireless-10.h diff --git a/testing/wireless/wireless-11.h b/libeap/testing/wireless/wireless-11.h similarity index 100% rename from testing/wireless/wireless-11.h rename to libeap/testing/wireless/wireless-11.h diff --git a/testing/wireless/wireless-12.h b/libeap/testing/wireless/wireless-12.h similarity index 100% rename from testing/wireless/wireless-12.h rename to libeap/testing/wireless/wireless-12.h diff --git a/testing/wireless/wireless-13.h b/libeap/testing/wireless/wireless-13.h similarity index 100% rename from testing/wireless/wireless-13.h rename to libeap/testing/wireless/wireless-13.h diff --git a/testing/wireless/wireless-14.h b/libeap/testing/wireless/wireless-14.h similarity index 100% rename from testing/wireless/wireless-14.h rename to libeap/testing/wireless/wireless-14.h diff --git a/testing/wireless/wireless-15.h b/libeap/testing/wireless/wireless-15.h similarity index 100% rename from testing/wireless/wireless-15.h rename to libeap/testing/wireless/wireless-15.h diff --git a/testing/wireless/wireless-16.h b/libeap/testing/wireless/wireless-16.h similarity index 100% rename from testing/wireless/wireless-16.h rename to libeap/testing/wireless/wireless-16.h diff --git a/testing/wireless/wireless-17.h b/libeap/testing/wireless/wireless-17.h similarity index 100% rename from testing/wireless/wireless-17.h rename to libeap/testing/wireless/wireless-17.h diff --git a/testing/wireless/wireless-18.h b/libeap/testing/wireless/wireless-18.h similarity index 100% rename from testing/wireless/wireless-18.h rename to libeap/testing/wireless/wireless-18.h diff --git a/testing/wireless/wireless-19.h b/libeap/testing/wireless/wireless-19.h similarity index 100% rename from testing/wireless/wireless-19.h rename to libeap/testing/wireless/wireless-19.h diff --git a/testing/wireless/wireless-6.h b/libeap/testing/wireless/wireless-6.h similarity index 100% rename from testing/wireless/wireless-6.h rename to libeap/testing/wireless/wireless-6.h diff --git a/testing/wireless/wireless-8.h b/libeap/testing/wireless/wireless-8.h similarity index 100% rename from testing/wireless/wireless-8.h rename to libeap/testing/wireless/wireless-8.h diff --git a/testing/wireless/wireless-9.h b/libeap/testing/wireless/wireless-9.h similarity index 100% rename from testing/wireless/wireless-9.h rename to libeap/testing/wireless/wireless-9.h diff --git a/testing/wpa_supplicant-config/arm b/libeap/testing/wpa_supplicant-config/arm similarity index 100% rename from testing/wpa_supplicant-config/arm rename to libeap/testing/wpa_supplicant-config/arm diff --git a/testing/wpa_supplicant-config/default b/libeap/testing/wpa_supplicant-config/default similarity index 100% rename from testing/wpa_supplicant-config/default rename to libeap/testing/wpa_supplicant-config/default diff --git a/testing/wpa_supplicant-config/default-0.3 b/libeap/testing/wpa_supplicant-config/default-0.3 similarity index 100% rename from testing/wpa_supplicant-config/default-0.3 rename to libeap/testing/wpa_supplicant-config/default-0.3 diff --git a/testing/wpa_supplicant-config/dyneap b/libeap/testing/wpa_supplicant-config/dyneap similarity index 100% rename from testing/wpa_supplicant-config/dyneap rename to libeap/testing/wpa_supplicant-config/dyneap diff --git a/testing/wpa_supplicant-config/freebsd b/libeap/testing/wpa_supplicant-config/freebsd similarity index 100% rename from testing/wpa_supplicant-config/freebsd rename to libeap/testing/wpa_supplicant-config/freebsd diff --git a/testing/wpa_supplicant-config/gcc-cvs b/libeap/testing/wpa_supplicant-config/gcc-cvs similarity index 100% rename from testing/wpa_supplicant-config/gcc-cvs rename to libeap/testing/wpa_supplicant-config/gcc-cvs diff --git a/testing/wpa_supplicant-config/minimal b/libeap/testing/wpa_supplicant-config/minimal similarity index 100% rename from testing/wpa_supplicant-config/minimal rename to libeap/testing/wpa_supplicant-config/minimal diff --git a/testing/wpa_supplicant-config/minimal-wpa b/libeap/testing/wpa_supplicant-config/minimal-wpa similarity index 100% rename from testing/wpa_supplicant-config/minimal-wpa rename to libeap/testing/wpa_supplicant-config/minimal-wpa diff --git a/testing/wpa_supplicant-config/windows b/libeap/testing/wpa_supplicant-config/windows similarity index 100% rename from testing/wpa_supplicant-config/windows rename to libeap/testing/wpa_supplicant-config/windows diff --git a/testing/wpa_supplicant-config/windows-0.3 b/libeap/testing/wpa_supplicant-config/windows-0.3 similarity index 100% rename from testing/wpa_supplicant-config/windows-0.3 rename to libeap/testing/wpa_supplicant-config/windows-0.3 diff --git a/testing/wpa_supplicant-config/windows-0.4 b/libeap/testing/wpa_supplicant-config/windows-0.4 similarity index 100% rename from testing/wpa_supplicant-config/windows-0.4 rename to libeap/testing/wpa_supplicant-config/windows-0.4 diff --git a/testing/wpa_supplicant-config/windows2 b/libeap/testing/wpa_supplicant-config/windows2 similarity index 100% rename from testing/wpa_supplicant-config/windows2 rename to libeap/testing/wpa_supplicant-config/windows2 diff --git a/testing/wpa_supplicant-config/windows2-0.3 b/libeap/testing/wpa_supplicant-config/windows2-0.3 similarity index 100% rename from testing/wpa_supplicant-config/windows2-0.3 rename to libeap/testing/wpa_supplicant-config/windows2-0.3 diff --git a/testing/wpa_supplicant-config/windows2-0.4 b/libeap/testing/wpa_supplicant-config/windows2-0.4 similarity index 100% rename from testing/wpa_supplicant-config/windows2-0.4 rename to libeap/testing/wpa_supplicant-config/windows2-0.4 diff --git a/testing/wpa_supplicant-config/x86_64 b/libeap/testing/wpa_supplicant-config/x86_64 similarity index 100% rename from testing/wpa_supplicant-config/x86_64 rename to libeap/testing/wpa_supplicant-config/x86_64 diff --git a/tests/.gitignore b/libeap/tests/.gitignore similarity index 100% rename from tests/.gitignore rename to libeap/tests/.gitignore diff --git a/tests/Makefile b/libeap/tests/Makefile similarity index 100% rename from tests/Makefile rename to libeap/tests/Makefile diff --git a/tests/test-aes.c b/libeap/tests/test-aes.c similarity index 100% rename from tests/test-aes.c rename to libeap/tests/test-aes.c diff --git a/tests/test-asn1.c b/libeap/tests/test-asn1.c similarity index 100% rename from tests/test-asn1.c rename to libeap/tests/test-asn1.c diff --git a/tests/test-base64.c b/libeap/tests/test-base64.c similarity index 100% rename from tests/test-base64.c rename to libeap/tests/test-base64.c diff --git a/tests/test-list.c b/libeap/tests/test-list.c similarity index 100% rename from tests/test-list.c rename to libeap/tests/test-list.c diff --git a/tests/test-md4.c b/libeap/tests/test-md4.c similarity index 100% rename from tests/test-md4.c rename to libeap/tests/test-md4.c diff --git a/tests/test-md5.c b/libeap/tests/test-md5.c similarity index 100% rename from tests/test-md5.c rename to libeap/tests/test-md5.c diff --git a/tests/test-milenage.c b/libeap/tests/test-milenage.c similarity index 100% rename from tests/test-milenage.c rename to libeap/tests/test-milenage.c diff --git a/tests/test-ms_funcs.c b/libeap/tests/test-ms_funcs.c similarity index 100% rename from tests/test-ms_funcs.c rename to libeap/tests/test-ms_funcs.c diff --git a/tests/test-sha1.c b/libeap/tests/test-sha1.c similarity index 100% rename from tests/test-sha1.c rename to libeap/tests/test-sha1.c diff --git a/tests/test-sha256.c b/libeap/tests/test-sha256.c similarity index 100% rename from tests/test-sha256.c rename to libeap/tests/test-sha256.c diff --git a/tests/test-x509.c b/libeap/tests/test-x509.c similarity index 100% rename from tests/test-x509.c rename to libeap/tests/test-x509.c diff --git a/tests/test-x509v3.c b/libeap/tests/test-x509v3.c similarity index 100% rename from tests/test-x509v3.c rename to libeap/tests/test-x509v3.c diff --git a/tests/test_x509v3_nist.sh b/libeap/tests/test_x509v3_nist.sh similarity index 100% rename from tests/test_x509v3_nist.sh rename to libeap/tests/test_x509v3_nist.sh diff --git a/tests/test_x509v3_nist2.sh b/libeap/tests/test_x509v3_nist2.sh similarity index 100% rename from tests/test_x509v3_nist2.sh rename to libeap/tests/test_x509v3_nist2.sh diff --git a/wpa_supplicant/.gitignore b/libeap/wpa_supplicant/.gitignore similarity index 100% rename from wpa_supplicant/.gitignore rename to libeap/wpa_supplicant/.gitignore diff --git a/wpa_supplicant/ChangeLog b/libeap/wpa_supplicant/ChangeLog similarity index 100% rename from wpa_supplicant/ChangeLog rename to libeap/wpa_supplicant/ChangeLog diff --git a/wpa_supplicant/Makefile b/libeap/wpa_supplicant/Makefile similarity index 100% rename from wpa_supplicant/Makefile rename to libeap/wpa_supplicant/Makefile diff --git a/wpa_supplicant/README b/libeap/wpa_supplicant/README similarity index 100% rename from wpa_supplicant/README rename to libeap/wpa_supplicant/README diff --git a/wpa_supplicant/README-WPS b/libeap/wpa_supplicant/README-WPS similarity index 100% rename from wpa_supplicant/README-WPS rename to libeap/wpa_supplicant/README-WPS diff --git a/wpa_supplicant/README-Windows.txt b/libeap/wpa_supplicant/README-Windows.txt similarity index 100% rename from wpa_supplicant/README-Windows.txt rename to libeap/wpa_supplicant/README-Windows.txt diff --git a/wpa_supplicant/ap.c b/libeap/wpa_supplicant/ap.c similarity index 100% rename from wpa_supplicant/ap.c rename to libeap/wpa_supplicant/ap.c diff --git a/wpa_supplicant/ap.h b/libeap/wpa_supplicant/ap.h similarity index 100% rename from wpa_supplicant/ap.h rename to libeap/wpa_supplicant/ap.h diff --git a/wpa_supplicant/bgscan.c b/libeap/wpa_supplicant/bgscan.c similarity index 100% rename from wpa_supplicant/bgscan.c rename to libeap/wpa_supplicant/bgscan.c diff --git a/wpa_supplicant/bgscan.h b/libeap/wpa_supplicant/bgscan.h similarity index 100% rename from wpa_supplicant/bgscan.h rename to libeap/wpa_supplicant/bgscan.h diff --git a/wpa_supplicant/bgscan_learn.c b/libeap/wpa_supplicant/bgscan_learn.c similarity index 100% rename from wpa_supplicant/bgscan_learn.c rename to libeap/wpa_supplicant/bgscan_learn.c diff --git a/wpa_supplicant/bgscan_simple.c b/libeap/wpa_supplicant/bgscan_simple.c similarity index 100% rename from wpa_supplicant/bgscan_simple.c rename to libeap/wpa_supplicant/bgscan_simple.c diff --git a/wpa_supplicant/blacklist.c b/libeap/wpa_supplicant/blacklist.c similarity index 100% rename from wpa_supplicant/blacklist.c rename to libeap/wpa_supplicant/blacklist.c diff --git a/wpa_supplicant/blacklist.h b/libeap/wpa_supplicant/blacklist.h similarity index 100% rename from wpa_supplicant/blacklist.h rename to libeap/wpa_supplicant/blacklist.h diff --git a/wpa_supplicant/bss.c b/libeap/wpa_supplicant/bss.c similarity index 100% rename from wpa_supplicant/bss.c rename to libeap/wpa_supplicant/bss.c diff --git a/wpa_supplicant/bss.h b/libeap/wpa_supplicant/bss.h similarity index 100% rename from wpa_supplicant/bss.h rename to libeap/wpa_supplicant/bss.h diff --git a/wpa_supplicant/config.c b/libeap/wpa_supplicant/config.c similarity index 100% rename from wpa_supplicant/config.c rename to libeap/wpa_supplicant/config.c diff --git a/wpa_supplicant/config.h b/libeap/wpa_supplicant/config.h similarity index 100% rename from wpa_supplicant/config.h rename to libeap/wpa_supplicant/config.h diff --git a/wpa_supplicant/config_file.c b/libeap/wpa_supplicant/config_file.c similarity index 100% rename from wpa_supplicant/config_file.c rename to libeap/wpa_supplicant/config_file.c diff --git a/wpa_supplicant/config_none.c b/libeap/wpa_supplicant/config_none.c similarity index 100% rename from wpa_supplicant/config_none.c rename to libeap/wpa_supplicant/config_none.c diff --git a/wpa_supplicant/config_ssid.h b/libeap/wpa_supplicant/config_ssid.h similarity index 100% rename from wpa_supplicant/config_ssid.h rename to libeap/wpa_supplicant/config_ssid.h diff --git a/wpa_supplicant/config_winreg.c b/libeap/wpa_supplicant/config_winreg.c similarity index 100% rename from wpa_supplicant/config_winreg.c rename to libeap/wpa_supplicant/config_winreg.c diff --git a/wpa_supplicant/ctrl_iface.c b/libeap/wpa_supplicant/ctrl_iface.c similarity index 100% rename from wpa_supplicant/ctrl_iface.c rename to libeap/wpa_supplicant/ctrl_iface.c diff --git a/wpa_supplicant/ctrl_iface.h b/libeap/wpa_supplicant/ctrl_iface.h similarity index 100% rename from wpa_supplicant/ctrl_iface.h rename to libeap/wpa_supplicant/ctrl_iface.h diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/libeap/wpa_supplicant/ctrl_iface_named_pipe.c similarity index 100% rename from wpa_supplicant/ctrl_iface_named_pipe.c rename to libeap/wpa_supplicant/ctrl_iface_named_pipe.c diff --git a/wpa_supplicant/ctrl_iface_udp.c b/libeap/wpa_supplicant/ctrl_iface_udp.c similarity index 100% rename from wpa_supplicant/ctrl_iface_udp.c rename to libeap/wpa_supplicant/ctrl_iface_udp.c diff --git a/wpa_supplicant/ctrl_iface_unix.c b/libeap/wpa_supplicant/ctrl_iface_unix.c similarity index 100% rename from wpa_supplicant/ctrl_iface_unix.c rename to libeap/wpa_supplicant/ctrl_iface_unix.c diff --git a/wpa_supplicant/dbus/.gitignore b/libeap/wpa_supplicant/dbus/.gitignore similarity index 100% rename from wpa_supplicant/dbus/.gitignore rename to libeap/wpa_supplicant/dbus/.gitignore diff --git a/wpa_supplicant/dbus/Makefile b/libeap/wpa_supplicant/dbus/Makefile similarity index 100% rename from wpa_supplicant/dbus/Makefile rename to libeap/wpa_supplicant/dbus/Makefile diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf similarity index 100% rename from wpa_supplicant/dbus/dbus-wpa_supplicant.conf rename to libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf diff --git a/wpa_supplicant/dbus/dbus_common.c b/libeap/wpa_supplicant/dbus/dbus_common.c similarity index 100% rename from wpa_supplicant/dbus/dbus_common.c rename to libeap/wpa_supplicant/dbus/dbus_common.c diff --git a/wpa_supplicant/dbus/dbus_common.h b/libeap/wpa_supplicant/dbus/dbus_common.h similarity index 100% rename from wpa_supplicant/dbus/dbus_common.h rename to libeap/wpa_supplicant/dbus/dbus_common.h diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/libeap/wpa_supplicant/dbus/dbus_common_i.h similarity index 100% rename from wpa_supplicant/dbus/dbus_common_i.h rename to libeap/wpa_supplicant/dbus/dbus_common_i.h diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/libeap/wpa_supplicant/dbus/dbus_dict_helpers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_dict_helpers.c rename to libeap/wpa_supplicant/dbus/dbus_dict_helpers.c diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/libeap/wpa_supplicant/dbus/dbus_dict_helpers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_dict_helpers.h rename to libeap/wpa_supplicant/dbus/dbus_dict_helpers.h diff --git a/wpa_supplicant/dbus/dbus_new.c b/libeap/wpa_supplicant/dbus/dbus_new.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new.c rename to libeap/wpa_supplicant/dbus/dbus_new.c diff --git a/wpa_supplicant/dbus/dbus_new.h b/libeap/wpa_supplicant/dbus/dbus_new.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new.h rename to libeap/wpa_supplicant/dbus/dbus_new.h diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/libeap/wpa_supplicant/dbus/dbus_new_handlers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers.c rename to libeap/wpa_supplicant/dbus/dbus_new_handlers.c diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/libeap/wpa_supplicant/dbus/dbus_new_handlers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers.h rename to libeap/wpa_supplicant/dbus/dbus_new_handlers.h diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers_wps.c rename to libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/libeap/wpa_supplicant/dbus/dbus_new_helpers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_helpers.c rename to libeap/wpa_supplicant/dbus/dbus_new_helpers.c diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/libeap/wpa_supplicant/dbus/dbus_new_helpers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new_helpers.h rename to libeap/wpa_supplicant/dbus/dbus_new_helpers.h diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/libeap/wpa_supplicant/dbus/dbus_new_introspect.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_introspect.c rename to libeap/wpa_supplicant/dbus/dbus_new_introspect.c diff --git a/wpa_supplicant/dbus/dbus_old.c b/libeap/wpa_supplicant/dbus/dbus_old.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old.c rename to libeap/wpa_supplicant/dbus/dbus_old.c diff --git a/wpa_supplicant/dbus/dbus_old.h b/libeap/wpa_supplicant/dbus/dbus_old.h similarity index 100% rename from wpa_supplicant/dbus/dbus_old.h rename to libeap/wpa_supplicant/dbus/dbus_old.h diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/libeap/wpa_supplicant/dbus/dbus_old_handlers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers.c rename to libeap/wpa_supplicant/dbus/dbus_old_handlers.c diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/libeap/wpa_supplicant/dbus/dbus_old_handlers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers.h rename to libeap/wpa_supplicant/dbus/dbus_old_handlers.h diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers_wps.c rename to libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service b/libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service similarity index 100% rename from wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service rename to libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service b/libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service similarity index 100% rename from wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service rename to libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service diff --git a/wpa_supplicant/defconfig b/libeap/wpa_supplicant/defconfig similarity index 100% rename from wpa_supplicant/defconfig rename to libeap/wpa_supplicant/defconfig diff --git a/wpa_supplicant/doc/docbook/.gitignore b/libeap/wpa_supplicant/doc/docbook/.gitignore similarity index 100% rename from wpa_supplicant/doc/docbook/.gitignore rename to libeap/wpa_supplicant/doc/docbook/.gitignore diff --git a/wpa_supplicant/doc/docbook/Makefile b/libeap/wpa_supplicant/doc/docbook/Makefile similarity index 100% rename from wpa_supplicant/doc/docbook/Makefile rename to libeap/wpa_supplicant/doc/docbook/Makefile diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_background.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_background.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_background.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_cli.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_gui.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_passphrase.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_priv.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_supplicant.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml diff --git a/wpa_supplicant/driver_i.h b/libeap/wpa_supplicant/driver_i.h similarity index 100% rename from wpa_supplicant/driver_i.h rename to libeap/wpa_supplicant/driver_i.h diff --git a/wpa_supplicant/eap_register.c b/libeap/wpa_supplicant/eap_register.c similarity index 100% rename from wpa_supplicant/eap_register.c rename to libeap/wpa_supplicant/eap_register.c diff --git a/wpa_supplicant/eap_testing.txt b/libeap/wpa_supplicant/eap_testing.txt similarity index 100% rename from wpa_supplicant/eap_testing.txt rename to libeap/wpa_supplicant/eap_testing.txt diff --git a/wpa_supplicant/eapol_test.c b/libeap/wpa_supplicant/eapol_test.c similarity index 100% rename from wpa_supplicant/eapol_test.c rename to libeap/wpa_supplicant/eapol_test.c diff --git a/wpa_supplicant/events.c b/libeap/wpa_supplicant/events.c similarity index 100% rename from wpa_supplicant/events.c rename to libeap/wpa_supplicant/events.c diff --git a/wpa_supplicant/examples/60_wpa_supplicant b/libeap/wpa_supplicant/examples/60_wpa_supplicant similarity index 100% rename from wpa_supplicant/examples/60_wpa_supplicant rename to libeap/wpa_supplicant/examples/60_wpa_supplicant diff --git a/wpa_supplicant/examples/ieee8021x.conf b/libeap/wpa_supplicant/examples/ieee8021x.conf similarity index 100% rename from wpa_supplicant/examples/ieee8021x.conf rename to libeap/wpa_supplicant/examples/ieee8021x.conf diff --git a/wpa_supplicant/examples/openCryptoki.conf b/libeap/wpa_supplicant/examples/openCryptoki.conf similarity index 100% rename from wpa_supplicant/examples/openCryptoki.conf rename to libeap/wpa_supplicant/examples/openCryptoki.conf diff --git a/wpa_supplicant/examples/p2p-action-udhcp.sh b/libeap/wpa_supplicant/examples/p2p-action-udhcp.sh similarity index 100% rename from wpa_supplicant/examples/p2p-action-udhcp.sh rename to libeap/wpa_supplicant/examples/p2p-action-udhcp.sh diff --git a/wpa_supplicant/examples/p2p-action.sh b/libeap/wpa_supplicant/examples/p2p-action.sh similarity index 100% rename from wpa_supplicant/examples/p2p-action.sh rename to libeap/wpa_supplicant/examples/p2p-action.sh diff --git a/wpa_supplicant/examples/plaintext.conf b/libeap/wpa_supplicant/examples/plaintext.conf similarity index 100% rename from wpa_supplicant/examples/plaintext.conf rename to libeap/wpa_supplicant/examples/plaintext.conf diff --git a/wpa_supplicant/examples/udhcpd-p2p.conf b/libeap/wpa_supplicant/examples/udhcpd-p2p.conf similarity index 100% rename from wpa_supplicant/examples/udhcpd-p2p.conf rename to libeap/wpa_supplicant/examples/udhcpd-p2p.conf diff --git a/wpa_supplicant/examples/wep.conf b/libeap/wpa_supplicant/examples/wep.conf similarity index 100% rename from wpa_supplicant/examples/wep.conf rename to libeap/wpa_supplicant/examples/wep.conf diff --git a/wpa_supplicant/examples/wpa-psk-tkip.conf b/libeap/wpa_supplicant/examples/wpa-psk-tkip.conf similarity index 100% rename from wpa_supplicant/examples/wpa-psk-tkip.conf rename to libeap/wpa_supplicant/examples/wpa-psk-tkip.conf diff --git a/wpa_supplicant/examples/wpa2-eap-ccmp.conf b/libeap/wpa_supplicant/examples/wpa2-eap-ccmp.conf similarity index 100% rename from wpa_supplicant/examples/wpa2-eap-ccmp.conf rename to libeap/wpa_supplicant/examples/wpa2-eap-ccmp.conf diff --git a/wpa_supplicant/examples/wpas-dbus-new-getall.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-getall.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-getall.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-getall.py diff --git a/wpa_supplicant/examples/wpas-dbus-new-signals.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-signals.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py diff --git a/wpa_supplicant/examples/wpas-dbus-new-wps.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-wps.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-wps.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-wps.py diff --git a/wpa_supplicant/examples/wpas-dbus-new.py b/libeap/wpa_supplicant/examples/wpas-dbus-new.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new.py diff --git a/wpa_supplicant/examples/wpas-test.py b/libeap/wpa_supplicant/examples/wpas-test.py similarity index 100% rename from wpa_supplicant/examples/wpas-test.py rename to libeap/wpa_supplicant/examples/wpas-test.py diff --git a/wpa_supplicant/ibss_rsn.c b/libeap/wpa_supplicant/ibss_rsn.c similarity index 100% rename from wpa_supplicant/ibss_rsn.c rename to libeap/wpa_supplicant/ibss_rsn.c diff --git a/wpa_supplicant/ibss_rsn.h b/libeap/wpa_supplicant/ibss_rsn.h similarity index 100% rename from wpa_supplicant/ibss_rsn.h rename to libeap/wpa_supplicant/ibss_rsn.h diff --git a/wpa_supplicant/main.c b/libeap/wpa_supplicant/main.c similarity index 100% rename from wpa_supplicant/main.c rename to libeap/wpa_supplicant/main.c diff --git a/wpa_supplicant/main_none.c b/libeap/wpa_supplicant/main_none.c similarity index 100% rename from wpa_supplicant/main_none.c rename to libeap/wpa_supplicant/main_none.c diff --git a/wpa_supplicant/main_symbian.cpp b/libeap/wpa_supplicant/main_symbian.cpp similarity index 100% rename from wpa_supplicant/main_symbian.cpp rename to libeap/wpa_supplicant/main_symbian.cpp diff --git a/wpa_supplicant/main_winmain.c b/libeap/wpa_supplicant/main_winmain.c similarity index 100% rename from wpa_supplicant/main_winmain.c rename to libeap/wpa_supplicant/main_winmain.c diff --git a/wpa_supplicant/main_winsvc.c b/libeap/wpa_supplicant/main_winsvc.c similarity index 100% rename from wpa_supplicant/main_winsvc.c rename to libeap/wpa_supplicant/main_winsvc.c diff --git a/wpa_supplicant/mlme.c b/libeap/wpa_supplicant/mlme.c similarity index 100% rename from wpa_supplicant/mlme.c rename to libeap/wpa_supplicant/mlme.c diff --git a/wpa_supplicant/mlme.h b/libeap/wpa_supplicant/mlme.h similarity index 100% rename from wpa_supplicant/mlme.h rename to libeap/wpa_supplicant/mlme.h diff --git a/wpa_supplicant/nmake.mak b/libeap/wpa_supplicant/nmake.mak similarity index 100% rename from wpa_supplicant/nmake.mak rename to libeap/wpa_supplicant/nmake.mak diff --git a/wpa_supplicant/notify.c b/libeap/wpa_supplicant/notify.c similarity index 100% rename from wpa_supplicant/notify.c rename to libeap/wpa_supplicant/notify.c diff --git a/wpa_supplicant/notify.h b/libeap/wpa_supplicant/notify.h similarity index 100% rename from wpa_supplicant/notify.h rename to libeap/wpa_supplicant/notify.h diff --git a/wpa_supplicant/p2p_supplicant.c b/libeap/wpa_supplicant/p2p_supplicant.c similarity index 100% rename from wpa_supplicant/p2p_supplicant.c rename to libeap/wpa_supplicant/p2p_supplicant.c diff --git a/wpa_supplicant/p2p_supplicant.h b/libeap/wpa_supplicant/p2p_supplicant.h similarity index 100% rename from wpa_supplicant/p2p_supplicant.h rename to libeap/wpa_supplicant/p2p_supplicant.h diff --git a/wpa_supplicant/preauth_test.c b/libeap/wpa_supplicant/preauth_test.c similarity index 100% rename from wpa_supplicant/preauth_test.c rename to libeap/wpa_supplicant/preauth_test.c diff --git a/wpa_supplicant/scan.c b/libeap/wpa_supplicant/scan.c similarity index 100% rename from wpa_supplicant/scan.c rename to libeap/wpa_supplicant/scan.c diff --git a/wpa_supplicant/scan.h b/libeap/wpa_supplicant/scan.h similarity index 100% rename from wpa_supplicant/scan.h rename to libeap/wpa_supplicant/scan.h diff --git a/wpa_supplicant/sme.c b/libeap/wpa_supplicant/sme.c similarity index 100% rename from wpa_supplicant/sme.c rename to libeap/wpa_supplicant/sme.c diff --git a/wpa_supplicant/sme.h b/libeap/wpa_supplicant/sme.h similarity index 100% rename from wpa_supplicant/sme.h rename to libeap/wpa_supplicant/sme.h diff --git a/wpa_supplicant/symbian/README.symbian b/libeap/wpa_supplicant/symbian/README.symbian similarity index 100% rename from wpa_supplicant/symbian/README.symbian rename to libeap/wpa_supplicant/symbian/README.symbian diff --git a/wpa_supplicant/symbian/bld.inf b/libeap/wpa_supplicant/symbian/bld.inf similarity index 100% rename from wpa_supplicant/symbian/bld.inf rename to libeap/wpa_supplicant/symbian/bld.inf diff --git a/wpa_supplicant/symbian/wpa_supplicant.mmp b/libeap/wpa_supplicant/symbian/wpa_supplicant.mmp similarity index 100% rename from wpa_supplicant/symbian/wpa_supplicant.mmp rename to libeap/wpa_supplicant/symbian/wpa_supplicant.mmp diff --git a/wpa_supplicant/tests/link_test.c b/libeap/wpa_supplicant/tests/link_test.c similarity index 100% rename from wpa_supplicant/tests/link_test.c rename to libeap/wpa_supplicant/tests/link_test.c diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/libeap/wpa_supplicant/tests/test_eap_sim_common.c similarity index 100% rename from wpa_supplicant/tests/test_eap_sim_common.c rename to libeap/wpa_supplicant/tests/test_eap_sim_common.c diff --git a/wpa_supplicant/tests/test_wpa.c b/libeap/wpa_supplicant/tests/test_wpa.c similarity index 100% rename from wpa_supplicant/tests/test_wpa.c rename to libeap/wpa_supplicant/tests/test_wpa.c diff --git a/wpa_supplicant/todo.txt b/libeap/wpa_supplicant/todo.txt similarity index 100% rename from wpa_supplicant/todo.txt rename to libeap/wpa_supplicant/todo.txt diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj similarity index 100% rename from wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj rename to libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj diff --git a/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/libeap/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj similarity index 100% rename from wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj rename to libeap/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj diff --git a/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/libeap/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj diff --git a/wpa_supplicant/vs2005/wpa_supplicant.sln b/libeap/wpa_supplicant/vs2005/wpa_supplicant.sln similarity index 100% rename from wpa_supplicant/vs2005/wpa_supplicant.sln rename to libeap/wpa_supplicant/vs2005/wpa_supplicant.sln diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj diff --git a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj rename to libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj diff --git a/wpa_supplicant/win_example.reg b/libeap/wpa_supplicant/win_example.reg similarity index 100% rename from wpa_supplicant/win_example.reg rename to libeap/wpa_supplicant/win_example.reg diff --git a/wpa_supplicant/win_if_list.c b/libeap/wpa_supplicant/win_if_list.c similarity index 100% rename from wpa_supplicant/win_if_list.c rename to libeap/wpa_supplicant/win_if_list.c diff --git a/wpa_supplicant/wpa_cli.c b/libeap/wpa_supplicant/wpa_cli.c similarity index 100% rename from wpa_supplicant/wpa_cli.c rename to libeap/wpa_supplicant/wpa_cli.c diff --git a/wpa_supplicant/wpa_gui-qt4/.gitignore b/libeap/wpa_supplicant/wpa_gui-qt4/.gitignore similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/.gitignore rename to libeap/wpa_supplicant/wpa_gui-qt4/.gitignore diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/addinterface.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.h b/libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/addinterface.h rename to libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.h rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.ui diff --git a/wpa_supplicant/wpa_gui-qt4/icons.qrc b/libeap/wpa_supplicant/wpa_gui-qt4/icons.qrc similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons.qrc rename to libeap/wpa_supplicant/wpa_gui-qt4/icons.qrc diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/libeap/wpa_supplicant/wpa_gui-qt4/icons/Makefile similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/Makefile rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/Makefile diff --git a/wpa_supplicant/wpa_gui-qt4/icons/README b/libeap/wpa_supplicant/wpa_gui-qt4/icons/README similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/README rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/README diff --git a/wpa_supplicant/wpa_gui-qt4/icons/ap.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/ap.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/ap.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/ap.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/group.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/group.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/group.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/group.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/invitation.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/laptop.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons_png.qrc b/libeap/wpa_supplicant/wpa_gui-qt4/icons_png.qrc similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons_png.qrc rename to libeap/wpa_supplicant/wpa_gui-qt4/icons_png.qrc diff --git a/wpa_supplicant/wpa_gui-qt4/lang/.gitignore b/libeap/wpa_supplicant/wpa_gui-qt4/lang/.gitignore similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/lang/.gitignore rename to libeap/wpa_supplicant/wpa_gui-qt4/lang/.gitignore diff --git a/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts b/libeap/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts rename to libeap/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/main.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/main.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/main.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.h rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.ui diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/peers.h b/libeap/wpa_supplicant/wpa_gui-qt4/peers.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.h rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.h diff --git a/wpa_supplicant/wpa_gui-qt4/peers.ui b/libeap/wpa_supplicant/wpa_gui-qt4/peers.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.ui diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.h rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.ui diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/stringquery.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.h b/libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/stringquery.h rename to libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.h rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop b/libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop rename to libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpa_gui.pro rename to libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.h rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.ui diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpamsg.h rename to libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h diff --git a/wpa_supplicant/wpa_gui/.gitignore b/libeap/wpa_supplicant/wpa_gui/.gitignore similarity index 100% rename from wpa_supplicant/wpa_gui/.gitignore rename to libeap/wpa_supplicant/wpa_gui/.gitignore diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/libeap/wpa_supplicant/wpa_gui/eventhistory.ui similarity index 100% rename from wpa_supplicant/wpa_gui/eventhistory.ui rename to libeap/wpa_supplicant/wpa_gui/eventhistory.ui diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/libeap/wpa_supplicant/wpa_gui/eventhistory.ui.h similarity index 100% rename from wpa_supplicant/wpa_gui/eventhistory.ui.h rename to libeap/wpa_supplicant/wpa_gui/eventhistory.ui.h diff --git a/wpa_supplicant/wpa_gui/main.cpp b/libeap/wpa_supplicant/wpa_gui/main.cpp similarity index 100% rename from wpa_supplicant/wpa_gui/main.cpp rename to libeap/wpa_supplicant/wpa_gui/main.cpp diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/libeap/wpa_supplicant/wpa_gui/networkconfig.ui similarity index 100% rename from wpa_supplicant/wpa_gui/networkconfig.ui rename to libeap/wpa_supplicant/wpa_gui/networkconfig.ui diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/libeap/wpa_supplicant/wpa_gui/networkconfig.ui.h similarity index 100% rename from wpa_supplicant/wpa_gui/networkconfig.ui.h rename to libeap/wpa_supplicant/wpa_gui/networkconfig.ui.h diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/libeap/wpa_supplicant/wpa_gui/scanresults.ui similarity index 100% rename from wpa_supplicant/wpa_gui/scanresults.ui rename to libeap/wpa_supplicant/wpa_gui/scanresults.ui diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/libeap/wpa_supplicant/wpa_gui/scanresults.ui.h similarity index 100% rename from wpa_supplicant/wpa_gui/scanresults.ui.h rename to libeap/wpa_supplicant/wpa_gui/scanresults.ui.h diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/libeap/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling similarity index 100% rename from wpa_supplicant/wpa_gui/setup-mingw-cross-compiling rename to libeap/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/libeap/wpa_supplicant/wpa_gui/userdatarequest.ui similarity index 100% rename from wpa_supplicant/wpa_gui/userdatarequest.ui rename to libeap/wpa_supplicant/wpa_gui/userdatarequest.ui diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/libeap/wpa_supplicant/wpa_gui/userdatarequest.ui.h similarity index 100% rename from wpa_supplicant/wpa_gui/userdatarequest.ui.h rename to libeap/wpa_supplicant/wpa_gui/userdatarequest.ui.h diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/libeap/wpa_supplicant/wpa_gui/wpa_gui.pro similarity index 100% rename from wpa_supplicant/wpa_gui/wpa_gui.pro rename to libeap/wpa_supplicant/wpa_gui/wpa_gui.pro diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/libeap/wpa_supplicant/wpa_gui/wpagui.ui similarity index 100% rename from wpa_supplicant/wpa_gui/wpagui.ui rename to libeap/wpa_supplicant/wpa_gui/wpagui.ui diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/libeap/wpa_supplicant/wpa_gui/wpagui.ui.h similarity index 100% rename from wpa_supplicant/wpa_gui/wpagui.ui.h rename to libeap/wpa_supplicant/wpa_gui/wpagui.ui.h diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/libeap/wpa_supplicant/wpa_gui/wpamsg.h similarity index 100% rename from wpa_supplicant/wpa_gui/wpamsg.h rename to libeap/wpa_supplicant/wpa_gui/wpamsg.h diff --git a/wpa_supplicant/wpa_passphrase.c b/libeap/wpa_supplicant/wpa_passphrase.c similarity index 100% rename from wpa_supplicant/wpa_passphrase.c rename to libeap/wpa_supplicant/wpa_passphrase.c diff --git a/wpa_supplicant/wpa_priv.c b/libeap/wpa_supplicant/wpa_priv.c similarity index 100% rename from wpa_supplicant/wpa_priv.c rename to libeap/wpa_supplicant/wpa_priv.c diff --git a/wpa_supplicant/wpa_supplicant.c b/libeap/wpa_supplicant/wpa_supplicant.c similarity index 100% rename from wpa_supplicant/wpa_supplicant.c rename to libeap/wpa_supplicant/wpa_supplicant.c diff --git a/wpa_supplicant/wpa_supplicant.conf b/libeap/wpa_supplicant/wpa_supplicant.conf similarity index 100% rename from wpa_supplicant/wpa_supplicant.conf rename to libeap/wpa_supplicant/wpa_supplicant.conf diff --git a/wpa_supplicant/wpa_supplicant.nsi b/libeap/wpa_supplicant/wpa_supplicant.nsi similarity index 100% rename from wpa_supplicant/wpa_supplicant.nsi rename to libeap/wpa_supplicant/wpa_supplicant.nsi diff --git a/wpa_supplicant/wpa_supplicant_i.h b/libeap/wpa_supplicant/wpa_supplicant_i.h similarity index 100% rename from wpa_supplicant/wpa_supplicant_i.h rename to libeap/wpa_supplicant/wpa_supplicant_i.h diff --git a/wpa_supplicant/wpas_glue.c b/libeap/wpa_supplicant/wpas_glue.c similarity index 100% rename from wpa_supplicant/wpas_glue.c rename to libeap/wpa_supplicant/wpas_glue.c diff --git a/wpa_supplicant/wpas_glue.h b/libeap/wpa_supplicant/wpas_glue.h similarity index 100% rename from wpa_supplicant/wpas_glue.h rename to libeap/wpa_supplicant/wpas_glue.h diff --git a/wpa_supplicant/wps_supplicant.c b/libeap/wpa_supplicant/wps_supplicant.c similarity index 100% rename from wpa_supplicant/wps_supplicant.c rename to libeap/wpa_supplicant/wps_supplicant.c diff --git a/wpa_supplicant/wps_supplicant.h b/libeap/wpa_supplicant/wps_supplicant.h similarity index 100% rename from wpa_supplicant/wps_supplicant.h rename to libeap/wpa_supplicant/wps_supplicant.h diff --git a/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj b/libeap/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj similarity index 100% rename from wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj rename to libeap/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj diff --git a/www/Makefile b/libeap/www/Makefile similarity index 100% rename from www/Makefile rename to libeap/www/Makefile diff --git a/www/cvs.html b/libeap/www/cvs.html similarity index 100% rename from www/cvs.html rename to libeap/www/cvs.html diff --git a/www/hostapd/index.html b/libeap/www/hostapd/index.html similarity index 100% rename from www/hostapd/index.html rename to libeap/www/hostapd/index.html diff --git a/www/index.html b/libeap/www/index.html similarity index 100% rename from www/index.html rename to libeap/www/index.html diff --git a/www/links.html b/libeap/www/links.html similarity index 100% rename from www/links.html rename to libeap/www/links.html diff --git a/www/releases.html b/libeap/www/releases.html similarity index 100% rename from www/releases.html rename to libeap/www/releases.html diff --git a/www/versions.dot b/libeap/www/versions.dot similarity index 100% rename from www/versions.dot rename to libeap/www/versions.dot diff --git a/www/wpa_supplicant/conf/auth_modes.html b/libeap/www/wpa_supplicant/conf/auth_modes.html similarity index 100% rename from www/wpa_supplicant/conf/auth_modes.html rename to libeap/www/wpa_supplicant/conf/auth_modes.html diff --git a/www/wpa_supplicant/conf/configure.css b/libeap/www/wpa_supplicant/conf/configure.css similarity index 100% rename from www/wpa_supplicant/conf/configure.css rename to libeap/www/wpa_supplicant/conf/configure.css diff --git a/www/wpa_supplicant/conf/configure.html b/libeap/www/wpa_supplicant/conf/configure.html similarity index 100% rename from www/wpa_supplicant/conf/configure.html rename to libeap/www/wpa_supplicant/conf/configure.html diff --git a/www/wpa_supplicant/conf/configure.js b/libeap/www/wpa_supplicant/conf/configure.js similarity index 100% rename from www/wpa_supplicant/conf/configure.js rename to libeap/www/wpa_supplicant/conf/configure.js diff --git a/www/wpa_supplicant/conf/eap-peap.html b/libeap/www/wpa_supplicant/conf/eap-peap.html similarity index 100% rename from www/wpa_supplicant/conf/eap-peap.html rename to libeap/www/wpa_supplicant/conf/eap-peap.html diff --git a/www/wpa_supplicant/conf/eap-tls.html b/libeap/www/wpa_supplicant/conf/eap-tls.html similarity index 100% rename from www/wpa_supplicant/conf/eap-tls.html rename to libeap/www/wpa_supplicant/conf/eap-tls.html diff --git a/www/wpa_supplicant/conf/eap.html b/libeap/www/wpa_supplicant/conf/eap.html similarity index 100% rename from www/wpa_supplicant/conf/eap.html rename to libeap/www/wpa_supplicant/conf/eap.html diff --git a/www/wpa_supplicant/conf/index.html b/libeap/www/wpa_supplicant/conf/index.html similarity index 100% rename from www/wpa_supplicant/conf/index.html rename to libeap/www/wpa_supplicant/conf/index.html diff --git a/www/wpa_supplicant/events.png b/libeap/www/wpa_supplicant/events.png similarity index 100% rename from www/wpa_supplicant/events.png rename to libeap/www/wpa_supplicant/events.png diff --git a/www/wpa_supplicant/index.html b/libeap/www/wpa_supplicant/index.html similarity index 100% rename from www/wpa_supplicant/index.html rename to libeap/www/wpa_supplicant/index.html diff --git a/www/wpa_supplicant/main.png b/libeap/www/wpa_supplicant/main.png similarity index 100% rename from www/wpa_supplicant/main.png rename to libeap/www/wpa_supplicant/main.png diff --git a/www/wpa_supplicant/net_conf.png b/libeap/www/wpa_supplicant/net_conf.png similarity index 100% rename from www/wpa_supplicant/net_conf.png rename to libeap/www/wpa_supplicant/net_conf.png diff --git a/www/wpa_supplicant/scan.png b/libeap/www/wpa_supplicant/scan.png similarity index 100% rename from www/wpa_supplicant/scan.png rename to libeap/www/wpa_supplicant/scan.png diff --git a/www/wpa_supplicant/user_input.png b/libeap/www/wpa_supplicant/user_input.png similarity index 100% rename from www/wpa_supplicant/user_input.png rename to libeap/www/wpa_supplicant/user_input.png diff --git a/www/wpa_supplicant/wpa_gui.html b/libeap/www/wpa_supplicant/wpa_gui.html similarity index 100% rename from www/wpa_supplicant/wpa_gui.html rename to libeap/www/wpa_supplicant/wpa_gui.html 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/.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 +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..5f78a77 --- /dev/null +++ b/mech_eap/Makefile.am @@ -0,0 +1,178 @@ +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = gsseap_err.et radsec_err.et \ + mech_eap.exports mech_eap-noacceptor.exports + +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 \ + @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 \ + 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 \ + 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_moonshot.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 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 = ', and +appropriately ( 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 @ -pass host@ \ + "Testing GSS EAP" +% gss-server -port 5555 -export host@ + +Note: for SASL you will be prompted for a username and password. + +% client -C -p 5556 -s host -m EAP-AES128 +% server -c -p 5556 -s host -h + +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: + + + +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..567deed --- /dev/null +++ b/mech_eap/TODO @@ -0,0 +1,5 @@ +- integration with initiator-side EAP channel bindings +- 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..12f6862 --- /dev/null +++ b/mech_eap/accept_sec_context.c @@ -0,0 +1,1094 @@ +/* + * 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; + const char *configFile = RS_CONFIG_FILE; + const char *configStanza = "gss-eap"; + struct rs_alloc_scheme ralloc; + struct rs_error *err; + + GSSEAP_ASSERT(actx->radContext == NULL); + GSSEAP_ASSERT(actx->radConn == NULL); + + if (rs_context_create(&actx->radContext) != 0) { + *minor = GSSEAP_RADSEC_CONTEXT_FAILURE; + return GSS_S_FAILURE; + } + + if (cred->radiusConfigFile.value != NULL) + configFile = (const char *)cred->radiusConfigFile.value; + if (cred->radiusConfigStanza.value != NULL) + configStanza = (const char *)cred->radiusConfigStanza.value; + + ralloc.calloc = GSSEAP_CALLOC; + ralloc.malloc = GSSEAP_MALLOC; + ralloc.free = GSSEAP_FREE; + ralloc.realloc = GSSEAP_REALLOC; + + rs_context_set_alloc_scheme(actx->radContext, &ralloc); + + if (rs_context_read_config(actx->radContext, configFile) != 0) { + err = rs_err_ctx_pop(actx->radContext); + goto fail; + } + + if (rs_context_init_freeradius_dict(actx->radContext, NULL) != 0) { + err = rs_err_ctx_pop(actx->radContext); + goto fail; + } + + if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) { + err = rs_err_conn_pop(actx->radConn); + goto fail; + } + + if (actx->radServer != NULL) { + if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) { + err = rs_err_conn_pop(actx->radConn); + goto fail; + } + } + + *minor = 0; + return GSS_S_COMPLETE; + +fail: + return gssEapRadiusMapError(minor, err); +} + +/* + * 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; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + /* + * 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: + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + 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 + +/* + * 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/config.guess b/mech_eap/config.guess new file mode 100755 index 0000000..dc84c68 --- /dev/null +++ b/mech_eap/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file 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 of the License, 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. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mech_eap/config.sub b/mech_eap/config.sub new file mode 100755 index 0000000..2a55a50 --- /dev/null +++ b/mech_eap/config.sub @@ -0,0 +1,1705 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 of the License, 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. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: 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..1694566 --- /dev/null +++ b/mech_eap/dictionary.ukerna @@ -0,0 +1,19 @@ +# -*- 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 + +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..6eac550 --- /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/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..43208a9 --- /dev/null +++ b/mech_eap/gssapiP_eap.h @@ -0,0 +1,376 @@ +/* + * 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 +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef WIN32 +#ifndef MAXHOSTNAMELEN +# include +# define MAXHOSTNAMELEN NI_MAXHOST +#endif +#endif + +/* GSS headers */ +#include +#include +#ifdef HAVE_HEIMDAL_VERSION +typedef struct gss_any *gss_any_t; +#else +#include +#endif +#include "gssapi_eap.h" + +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH +typedef const gss_OID_desc *gss_const_OID; +#endif + +/* Kerberos headers */ +#include + +/* EAP headers */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef GSSEAP_ENABLE_ACCEPTOR +/* FreeRADIUS headers */ +#ifdef __cplusplus +extern "C" { +#ifndef WIN32 +#define operator fr_operator +#endif +#endif +#include +#include + +#undef pid_t + +/* libradsec headers */ +#include +#include +#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_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) + +/* 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); + +/* 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); + +/* 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 + +#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..f8ec5ef --- /dev/null +++ b/mech_eap/gsseap_err.et @@ -0,0 +1,161 @@ +# +# 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" + +# +# 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..56ee8d8 --- /dev/null +++ b/mech_eap/import_sec_context.c @@ -0,0 +1,363 @@ +/* + * 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 *key) +{ + unsigned char *p = *pBuf; + size_t remain = *pRemain; + OM_uint32 encryptionType; + OM_uint32 length; + gss_buffer_desc tmp; + + 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 (load_buffer(&p[12], length, &tmp) == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + KRB_KEY_TYPE(key) = encryptionType; + KRB_KEY_LENGTH(key) = tmp.length; + KRB_KEY_DATA(key) = (unsigned char *)tmp.value; + + *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..dc5c70f --- /dev/null +++ b/mech_eap/init_sec_context.c @@ -0,0 +1,1090 @@ +/* + * 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; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + 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; + } + + 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); + + 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; + + GSSEAP_ASSERT(ctx == GSS_C_NO_CONTEXT || ctx->mechanismUsed != GSS_C_NO_OID); + + 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..67b2ec8 --- /dev/null +++ b/mech_eap/inquire_sec_context_by_oid.c @@ -0,0 +1,141 @@ +/* + * 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 +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, tmpMinor; + unsigned char oidBuf[16]; + gss_buffer_desc buf; + gss_OID_desc oid; + + 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; + + oid.length = sizeof(oidBuf); + oid.elements = oidBuf; + + major = composeOid(minor, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04", + 10, + ctx->encryptionType, + &oid); + if (GSS_ERROR(major)) + goto cleanup; + + buf.length = oid.length; + buf.value = oid.elements; + + major = gss_add_buffer_set_member(minor, &buf, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major) && *dataSet != GSS_C_NO_BUFFER_SET) { + gss_buffer_set_t set = *dataSet; + + if (set->count != 0) + memset(set->elements[0].value, 0, set->elements[0].length); + gss_release_buffer_set(&tmpMinor, 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 + }, +}; + +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 (!CTX_IS_ESTABLISHED(ctx)) { + *minor = GSSEAP_CONTEXT_INCOMPLETE; + major = GSS_S_NO_CONTEXT; + goto cleanup; + } + + 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; + } + } + +cleanup: + 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..4ecbc52 --- /dev/null +++ b/mech_eap/mech_eap-noacceptor.exports @@ -0,0 +1,52 @@ +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_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_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..10c7f81 --- /dev/null +++ b/mech_eap/mech_eap.exports @@ -0,0 +1,60 @@ +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_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_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..b0ca1ea --- /dev/null +++ b/mech_eap/pseudo_random.c @@ -0,0 +1,185 @@ +/* + * 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); + + t.length = 0; + t.data = NULL; + + ns.length = 0; + ns.data = NULL; + + 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; + } + + t.length = prflen; + t.data = GSSEAP_MALLOC(t.length); + if (t.data == NULL) { + code = ENOMEM; + goto cleanup; + } + + 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); + krb5_free_data_contents(krbContext, &ns); + krb5_free_data_contents(krbContext, &t); + + *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/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..6291172 --- /dev/null +++ b/mech_eap/unwrap_iov.c @@ -0,0 +1,565 @@ +/* + * 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); + + code = gssEapVerify(krbContext, ctx->checksumType, 0, + 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..7fa3495 --- /dev/null +++ b/mech_eap/util.h @@ -0,0 +1,1007 @@ +/* + * 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 +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include + +#include + +#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 */ +#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) + +#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) + +#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 */ + +#define GSSEAP_CALLOC calloc +#define GSSEAP_MALLOC malloc +#define GSSEAP_FREE free +#define GSSEAP_REALLOC realloc + +#ifndef GSSAPI_CALLCONV +#define GSSAPI_CALLCONV KRB5_CALLCONV +#endif + +#ifndef GSSEAP_ASSERT +#include +#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 + +#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 + +#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 +#include +#include +#include +#include + +/* 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 +#include + +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..ba0dc87 --- /dev/null +++ b/mech_eap/util_context.c @@ -0,0 +1,383 @@ +/* + * 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.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 --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c new file mode 100644 index 0000000..fad8bad --- /dev/null +++ b/mech_eap/util_cred.c @@ -0,0 +1,739 @@ +/* + * 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 /* may need to use ShFolder.h instead */ +# include +#else +# include +#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); + } + + 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; + } + + 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 --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 +#include +#include +#include +#include + +#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 +#include + +#include + +#ifdef HAVE_SHIBRESOLVER +#include +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..ce3d0f6 --- /dev/null +++ b/mech_eap/util_krb.c @@ -0,0 +1,617 @@ +/* + * 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; + + tld = gssEapGetThreadLocalData(); + if (tld != NULL) { + *context = tld->krbContext; + if (*context == NULL) { + *minor = initKrbContext(context); + if (*minor == 0) + tld->krbContext = *context; + } + } + 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) + */ +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, prfOut; + 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_ASSERT(encryptionType != ENCTYPE_NULL); + + memset(pKey, 0, sizeof(*pKey)); + + GSSEAP_KRB_INIT(&krbContext); + + KRB_KEY_INIT(&kd); + KRB_KEY_TYPE(&kd) = encryptionType; + + t.data = NULL; + t.length = 0; + + prfOut.data = NULL; + prfOut.length = 0; + + code = krb5_c_keylengths(krbContext, encryptionType, + &randomLength, &keyLength); + if (code != 0) + goto cleanup; + + KRB_KEY_DATA(&kd) = GSSEAP_MALLOC(keyLength); + if (KRB_KEY_DATA(&kd) == NULL) { + code = ENOMEM; + goto cleanup; + } + KRB_KEY_LENGTH(&kd) = keyLength; + + /* Convert 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; + + code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd); +#endif + 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; + + t.length = prfLength; + t.data = GSSEAP_MALLOC(t.length); + if (t.data == NULL) { + code = ENOMEM; + goto cleanup; + } + + prfOut.length = randomLength; + prfOut.data = GSSEAP_MALLOC(prfOut.length); + if (prfOut.data == NULL) { + code = ENOMEM; + goto cleanup; + } + + for (i = 0, p = (unsigned char *)prfOut.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 + code = krb5_random_to_key(krbContext, encryptionType, + prfOut.data, prfOut.length, &kd); +#else + code = krb5_c_random_to_key(krbContext, encryptionType, &prfOut, &kd); +#endif + if (code != 0) + goto cleanup; + + *pKey = kd; + KRB_KEY_DATA(&kd) = NULL; + +cleanup: + if (KRB_KEY_DATA(&kd) != NULL) { + memset(KRB_KEY_DATA(&kd), 0, KRB_KEY_LENGTH(&kd)); + GSSEAP_FREE(KRB_KEY_DATA(&kd)); + } + if (t.data != NULL) { + memset(t.data, 0, t.length); + GSSEAP_FREE(t.data); + } + if (prfOut.data != NULL) { + memset(prfOut.data, 0, prfOut.length); + GSSEAP_FREE(prfOut.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 + data.length = 0; + data.data = NULL; + + 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..359058c --- /dev/null +++ b/mech_eap/util_lucid.c @@ -0,0 +1,180 @@ +/* + * 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); + 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.ctx_key + : &lctx->cfx_kd.acceptor_subkey; + + 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 + +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..a014bbe --- /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) = GSSEAP_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..a23d93d --- /dev/null +++ b/mech_eap/util_radius.cpp @@ -0,0 +1,873 @@ +/* + * 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(ctx); + + if (radius->m_vps != NULL) + m_vps = copyAvps(const_cast(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 &attrs, VALUE_PAIR *vp) +{ + for (std::vector::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 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); + +#ifdef GSSEAP_ENABLE_REAUTH + struct rs_context *radContext; + + /* + * This hack is necessary in order to force the loading of the global + * dictionary, otherwise accepting reauthentication tokens fails unless + * the acceptor has already accepted a normal authentication token. + */ + if (rs_context_create(&radContext) != 0) + return false; + + if (rs_context_read_config(radContext, RS_CONFIG_FILE) != 0) { + rs_context_destroy(radContext); + return false; + } + + if (rs_context_init_freeradius_dict(radContext, NULL)) { + rs_context_destroy(radContext); + return false; + } + + rs_context_destroy(radContext); +#endif + + 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; +} diff --git a/mech_eap/util_radius.h b/mech_eap/util_radius.h new file mode 100644 index 0000000..d209347 --- /dev/null +++ b/mech_eap/util_radius.h @@ -0,0 +1,178 @@ +/* + * 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); + +/* 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..1d8dbb1 --- /dev/null +++ b/mech_eap/util_reauth.c @@ -0,0 +1,1190 @@ +/* + * 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 + +/* + * 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; + + code = krb5_auth_con_setsendsubkey(krbContext, authContext, + &ctx->rfc3961Key); + 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; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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(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 + (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(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(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 + (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 &statements = + const_cast(assertion)->getAttributeStatements(); + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + + for (vector::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 * +decomposeAttributeName(const gss_buffer_t attr) +{ + BaseRefVectorOf *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 *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 *components = decomposeAttributeName(attr); + if (components == NULL) + return false; + + /* For each attribute statement, look for an attribute match */ + const vector &statements = + const_cast(assertion)->getAttributeStatements(); + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + ssize_t index = -1, i = 0; + + /* There's got to be an easier way to do this */ + for (vector::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 *components = decomposeAttributeName(attr); + if (components == NULL) + return false; + + /* For each attribute statement, look for an attribute match */ + const vector &statements = + const_cast(assertion)->getAttributeStatements(); + const saml2::Attribute *ret = NULL; + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + + for (vector::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(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 +#ifndef HAVE_OPENSAML +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +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()) + ; +} + +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(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 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 + (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 + (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::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); + ++a) + { + for (vector::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 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::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::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); + ++a) + { + for (vector::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(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(shibAttr); + const ScopedAttribute *scopedAttr = + dynamic_cast(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 v = duplicateAttributes(m_attributes); + + output = (gss_any_t)new vector (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 *v = ((vector *)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::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 +gss_eap_shib_attr_provider::duplicateAttributes(const vector src) +{ + vector dst; + + for (vector::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 + +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 getAttributes(void) const { + return m_attributes; + } + +private: + static shibsp::Attribute * + duplicateAttribute(const shibsp::Attribute *src); + static std::vector + duplicateAttributes(const std::vector 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 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..7010f99 --- /dev/null +++ b/mech_eap/util_sm.c @@ -0,0 +1,371 @@ +/* + * 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->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..a30f5f3 --- /dev/null +++ b/mech_eap/util_tld.c @@ -0,0 +1,156 @@ +/* + * 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; + +/* Access thread-local data */ +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData(void) +{ + return TlsGetValue(tlsIndex); +} + +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) + 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) + * possible multiple bytes, need to parse/generate + * 0x06 tag for OBJECT IDENTIFIER + * compile-time constant string (assume 1 byte) + * compile-time constant string + * 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..d72c57e --- /dev/null +++ b/mech_eap/verify_mic.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. + */ + +/* + * 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.length = 16; + iov[1].buffer.value = message_token->value; + + iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[2].buffer.length = message_token->length - 16; + iov[2].buffer.value = (unsigned char *)message_token->value + 16; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state, + iov, 3, 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; +}