update to libeap with -DCONFIG_TLS_INTERNAL_CLIENT
authorLuke Howard <lukeh@padl.com>
Tue, 3 May 2011 14:54:06 +0000 (16:54 +0200)
committerLuke Howard <lukeh@padl.com>
Tue, 3 May 2011 14:54:06 +0000 (16:54 +0200)
903 files changed:
.gitignore
Makefile.am
acinclude.m4 [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
libeap/.gitignore [new file with mode: 0644]
libeap/COPYING [moved from COPYING with 100% similarity]
libeap/FAQ [moved from FAQ with 100% similarity]
libeap/Makefile.am [new file with mode: 0644]
libeap/README [moved from README with 100% similarity]
libeap/build_nsis.sh [moved from build_nsis.sh with 100% similarity]
libeap/build_release [moved from build_release with 100% similarity]
libeap/doc/.gitignore [moved from doc/.gitignore with 100% similarity]
libeap/doc/Makefile [moved from doc/Makefile with 100% similarity]
libeap/doc/code_structure.doxygen [moved from doc/code_structure.doxygen with 100% similarity]
libeap/doc/ctrl_iface.doxygen [moved from doc/ctrl_iface.doxygen with 100% similarity]
libeap/doc/dbus.doxygen [moved from doc/dbus.doxygen with 100% similarity]
libeap/doc/directories.doxygen [moved from doc/directories.doxygen with 100% similarity]
libeap/doc/doxygen.conf [moved from doc/doxygen.conf with 100% similarity]
libeap/doc/driver_wrapper.doxygen [moved from doc/driver_wrapper.doxygen with 100% similarity]
libeap/doc/eap.doxygen [moved from doc/eap.doxygen with 100% similarity]
libeap/doc/eap_server.doxygen [moved from doc/eap_server.doxygen with 100% similarity]
libeap/doc/hostapd.fig [moved from doc/hostapd.fig with 100% similarity]
libeap/doc/hostapd_ctrl_iface.doxygen [moved from doc/hostapd_ctrl_iface.doxygen with 100% similarity]
libeap/doc/kerneldoc2doxygen.pl [moved from doc/kerneldoc2doxygen.pl with 100% similarity]
libeap/doc/mainpage.doxygen [moved from doc/mainpage.doxygen with 100% similarity]
libeap/doc/porting.doxygen [moved from doc/porting.doxygen with 100% similarity]
libeap/doc/testing_tools.doxygen [moved from doc/testing_tools.doxygen with 100% similarity]
libeap/doc/wpa_supplicant.fig [moved from doc/wpa_supplicant.fig with 100% similarity]
libeap/eap_example/.gitignore [moved from eap_example/.gitignore with 100% similarity]
libeap/eap_example/Makefile [moved from eap_example/Makefile with 100% similarity]
libeap/eap_example/README [moved from eap_example/README with 100% similarity]
libeap/eap_example/ca.pem [moved from eap_example/ca.pem with 100% similarity]
libeap/eap_example/eap_example.c [moved from eap_example/eap_example.c with 100% similarity]
libeap/eap_example/eap_example_peer.c [moved from eap_example/eap_example_peer.c with 100% similarity]
libeap/eap_example/eap_example_server.c [moved from eap_example/eap_example_server.c with 100% similarity]
libeap/eap_example/server-key.pem [moved from eap_example/server-key.pem with 100% similarity]
libeap/eap_example/server.key [moved from eap_example/server.key with 100% similarity]
libeap/eap_example/server.pem [moved from eap_example/server.pem with 100% similarity]
libeap/hostapd/ChangeLog [moved from hostapd/ChangeLog with 100% similarity]
libeap/hostapd/Makefile [moved from hostapd/Makefile with 100% similarity]
libeap/hostapd/README [moved from hostapd/README with 100% similarity]
libeap/hostapd/README-WPS [moved from hostapd/README-WPS with 100% similarity]
libeap/hostapd/config_file.c [moved from hostapd/config_file.c with 100% similarity]
libeap/hostapd/config_file.h [moved from hostapd/config_file.h with 100% similarity]
libeap/hostapd/ctrl_iface.c [moved from hostapd/ctrl_iface.c with 100% similarity]
libeap/hostapd/ctrl_iface.h [moved from hostapd/ctrl_iface.h with 100% similarity]
libeap/hostapd/defconfig [moved from hostapd/defconfig with 100% similarity]
libeap/hostapd/dump_state.c [moved from hostapd/dump_state.c with 100% similarity]
libeap/hostapd/dump_state.h [moved from hostapd/dump_state.h with 100% similarity]
libeap/hostapd/eap_register.c [moved from hostapd/eap_register.c with 100% similarity]
libeap/hostapd/eap_register.h [moved from hostapd/eap_register.h with 100% similarity]
libeap/hostapd/eap_testing.txt [moved from hostapd/eap_testing.txt with 100% similarity]
libeap/hostapd/hlr_auc_gw.c [moved from hostapd/hlr_auc_gw.c with 100% similarity]
libeap/hostapd/hlr_auc_gw.milenage_db [moved from hostapd/hlr_auc_gw.milenage_db with 100% similarity]
libeap/hostapd/hostapd.8 [moved from hostapd/hostapd.8 with 100% similarity]
libeap/hostapd/hostapd.accept [moved from hostapd/hostapd.accept with 100% similarity]
libeap/hostapd/hostapd.conf [moved from hostapd/hostapd.conf with 100% similarity]
libeap/hostapd/hostapd.deny [moved from hostapd/hostapd.deny with 100% similarity]
libeap/hostapd/hostapd.eap_user [moved from hostapd/hostapd.eap_user with 100% similarity]
libeap/hostapd/hostapd.radius_clients [moved from hostapd/hostapd.radius_clients with 100% similarity]
libeap/hostapd/hostapd.sim_db [moved from hostapd/hostapd.sim_db with 100% similarity]
libeap/hostapd/hostapd.vlan [moved from hostapd/hostapd.vlan with 100% similarity]
libeap/hostapd/hostapd.wpa_psk [moved from hostapd/hostapd.wpa_psk with 100% similarity]
libeap/hostapd/hostapd_cli.1 [moved from hostapd/hostapd_cli.1 with 100% similarity]
libeap/hostapd/hostapd_cli.c [moved from hostapd/hostapd_cli.c with 100% similarity]
libeap/hostapd/logwatch/README [moved from hostapd/logwatch/README with 100% similarity]
libeap/hostapd/logwatch/hostapd [moved from hostapd/logwatch/hostapd with 100% similarity]
libeap/hostapd/logwatch/hostapd.conf [moved from hostapd/logwatch/hostapd.conf with 100% similarity]
libeap/hostapd/main.c [moved from hostapd/main.c with 100% similarity]
libeap/hostapd/nt_password_hash.c [moved from hostapd/nt_password_hash.c with 100% similarity]
libeap/hostapd/wired.conf [moved from hostapd/wired.conf with 100% similarity]
libeap/mac80211_hwsim/README [moved from mac80211_hwsim/README with 100% similarity]
libeap/mac80211_hwsim/hostapd.conf [moved from mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf with 100% similarity]
libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf [moved from mac80211_hwsim/hostapd.conf with 100% similarity]
libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt [moved from mac80211_hwsim/tests/0001-wpa2-psk/test.txt with 100% similarity]
libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf [moved from mac80211_hwsim/wpa_supplicant.conf with 100% similarity]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept [moved from mac80211_hwsim/tests/0002-vlan/hostapd.accept with 100% similarity]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf [moved from mac80211_hwsim/tests/0002-vlan/hostapd.conf with 100% similarity]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan [moved from mac80211_hwsim/tests/0002-vlan/hostapd.vlan with 100% similarity]
libeap/mac80211_hwsim/tests/0002-vlan/test.txt [moved from mac80211_hwsim/tests/0002-vlan/test.txt with 100% similarity]
libeap/mac80211_hwsim/tools/Makefile [moved from mac80211_hwsim/tools/Makefile with 100% similarity]
libeap/mac80211_hwsim/tools/hwsim_test.c [moved from mac80211_hwsim/tools/hwsim_test.c with 100% similarity]
libeap/mac80211_hwsim/wpa_supplicant.conf [moved from mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf with 100% similarity]
libeap/patches/openssl-0.9.8-tls-extensions.patch [moved from patches/openssl-0.9.8-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.8d-tls-extensions.patch [moved from patches/openssl-0.9.8d-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.8e-tls-extensions.patch [moved from patches/openssl-0.9.8e-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.8g-tls-extensions.patch [moved from patches/openssl-0.9.8g-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.8h-tls-extensions.patch [moved from patches/openssl-0.9.8h-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.8i-tls-extensions.patch [moved from patches/openssl-0.9.8i-tls-extensions.patch with 100% similarity]
libeap/patches/openssl-0.9.9-session-ticket.patch [moved from patches/openssl-0.9.9-session-ticket.patch with 100% similarity]
libeap/radius_example/.gitignore [moved from radius_example/.gitignore with 100% similarity]
libeap/radius_example/Makefile [moved from radius_example/Makefile with 100% similarity]
libeap/radius_example/README [moved from radius_example/README with 100% similarity]
libeap/radius_example/radius_example.c [moved from radius_example/radius_example.c with 100% similarity]
libeap/src/Makefile [moved from src/Makefile with 100% similarity]
libeap/src/ap/Makefile [moved from src/wps/Makefile with 100% similarity]
libeap/src/ap/accounting.c [moved from src/ap/accounting.c with 100% similarity]
libeap/src/ap/accounting.h [moved from src/ap/accounting.h with 100% similarity]
libeap/src/ap/ap_config.c [moved from src/ap/ap_config.c with 100% similarity]
libeap/src/ap/ap_config.h [moved from src/ap/ap_config.h with 100% similarity]
libeap/src/ap/ap_drv_ops.c [moved from src/ap/ap_drv_ops.c with 100% similarity]
libeap/src/ap/ap_drv_ops.h [moved from src/ap/ap_drv_ops.h with 100% similarity]
libeap/src/ap/ap_list.c [moved from src/ap/ap_list.c with 100% similarity]
libeap/src/ap/ap_list.h [moved from src/ap/ap_list.h with 100% similarity]
libeap/src/ap/ap_mlme.c [moved from src/ap/ap_mlme.c with 100% similarity]
libeap/src/ap/ap_mlme.h [moved from src/ap/ap_mlme.h with 100% similarity]
libeap/src/ap/authsrv.c [moved from src/ap/authsrv.c with 100% similarity]
libeap/src/ap/authsrv.h [moved from src/ap/authsrv.h with 100% similarity]
libeap/src/ap/beacon.c [moved from src/ap/beacon.c with 100% similarity]
libeap/src/ap/beacon.h [moved from src/ap/beacon.h with 100% similarity]
libeap/src/ap/ctrl_iface_ap.c [moved from src/ap/ctrl_iface_ap.c with 100% similarity]
libeap/src/ap/ctrl_iface_ap.h [moved from src/ap/ctrl_iface_ap.h with 100% similarity]
libeap/src/ap/drv_callbacks.c [moved from src/ap/drv_callbacks.c with 100% similarity]
libeap/src/ap/hostapd.c [moved from src/ap/hostapd.c with 100% similarity]
libeap/src/ap/hostapd.h [moved from src/ap/hostapd.h with 100% similarity]
libeap/src/ap/hw_features.c [moved from src/ap/hw_features.c with 100% similarity]
libeap/src/ap/hw_features.h [moved from src/ap/hw_features.h with 100% similarity]
libeap/src/ap/iapp.c [moved from src/ap/iapp.c with 100% similarity]
libeap/src/ap/iapp.h [moved from src/ap/iapp.h with 100% similarity]
libeap/src/ap/ieee802_11.c [moved from src/ap/ieee802_11.c with 100% similarity]
libeap/src/ap/ieee802_11.h [moved from src/ap/ieee802_11.h with 100% similarity]
libeap/src/ap/ieee802_11_auth.c [moved from src/ap/ieee802_11_auth.c with 100% similarity]
libeap/src/ap/ieee802_11_auth.h [moved from src/ap/ieee802_11_auth.h with 100% similarity]
libeap/src/ap/ieee802_11_ht.c [moved from src/ap/ieee802_11_ht.c with 100% similarity]
libeap/src/ap/ieee802_1x.c [moved from src/ap/ieee802_1x.c with 100% similarity]
libeap/src/ap/ieee802_1x.h [moved from src/ap/ieee802_1x.h with 100% similarity]
libeap/src/ap/p2p_hostapd.c [moved from src/ap/p2p_hostapd.c with 100% similarity]
libeap/src/ap/p2p_hostapd.h [moved from src/ap/p2p_hostapd.h with 100% similarity]
libeap/src/ap/peerkey_auth.c [moved from src/ap/peerkey_auth.c with 100% similarity]
libeap/src/ap/pmksa_cache_auth.c [moved from src/ap/pmksa_cache_auth.c with 100% similarity]
libeap/src/ap/pmksa_cache_auth.h [moved from src/ap/pmksa_cache_auth.h with 100% similarity]
libeap/src/ap/preauth_auth.c [moved from src/ap/preauth_auth.c with 100% similarity]
libeap/src/ap/preauth_auth.h [moved from src/ap/preauth_auth.h with 100% similarity]
libeap/src/ap/sta_info.c [moved from src/ap/sta_info.c with 100% similarity]
libeap/src/ap/sta_info.h [moved from src/ap/sta_info.h with 100% similarity]
libeap/src/ap/tkip_countermeasures.c [moved from src/ap/tkip_countermeasures.c with 100% similarity]
libeap/src/ap/tkip_countermeasures.h [moved from src/ap/tkip_countermeasures.h with 100% similarity]
libeap/src/ap/utils.c [moved from src/ap/utils.c with 100% similarity]
libeap/src/ap/vlan_init.c [moved from src/ap/vlan_init.c with 100% similarity]
libeap/src/ap/vlan_init.h [moved from src/ap/vlan_init.h with 100% similarity]
libeap/src/ap/wmm.c [moved from src/ap/wmm.c with 100% similarity]
libeap/src/ap/wmm.h [moved from src/ap/wmm.h with 100% similarity]
libeap/src/ap/wpa_auth.c [moved from src/ap/wpa_auth.c with 100% similarity]
libeap/src/ap/wpa_auth.h [moved from src/ap/wpa_auth.h with 100% similarity]
libeap/src/ap/wpa_auth_ft.c [moved from src/ap/wpa_auth_ft.c with 100% similarity]
libeap/src/ap/wpa_auth_glue.c [moved from src/ap/wpa_auth_glue.c with 100% similarity]
libeap/src/ap/wpa_auth_glue.h [moved from src/ap/wpa_auth_glue.h with 100% similarity]
libeap/src/ap/wpa_auth_i.h [moved from src/ap/wpa_auth_i.h with 100% similarity]
libeap/src/ap/wpa_auth_ie.c [moved from src/ap/wpa_auth_ie.c with 100% similarity]
libeap/src/ap/wpa_auth_ie.h [moved from src/ap/wpa_auth_ie.h with 100% similarity]
libeap/src/ap/wps_hostapd.c [moved from src/ap/wps_hostapd.c with 100% similarity]
libeap/src/ap/wps_hostapd.h [moved from src/ap/wps_hostapd.h with 100% similarity]
libeap/src/common/Makefile [moved from src/rsn_supp/Makefile with 100% similarity]
libeap/src/common/defs.h [moved from src/common/defs.h with 100% similarity]
libeap/src/common/eapol_common.h [moved from src/common/eapol_common.h with 100% similarity]
libeap/src/common/ieee802_11_common.c [moved from src/common/ieee802_11_common.c with 100% similarity]
libeap/src/common/ieee802_11_common.h [moved from src/common/ieee802_11_common.h with 100% similarity]
libeap/src/common/ieee802_11_defs.h [moved from src/common/ieee802_11_defs.h with 100% similarity]
libeap/src/common/privsep_commands.h [moved from src/common/privsep_commands.h with 100% similarity]
libeap/src/common/version.h [moved from src/common/version.h with 100% similarity]
libeap/src/common/wpa_common.c [moved from src/common/wpa_common.c with 100% similarity]
libeap/src/common/wpa_common.h [moved from src/common/wpa_common.h with 100% similarity]
libeap/src/common/wpa_ctrl.c [moved from src/common/wpa_ctrl.c with 100% similarity]
libeap/src/common/wpa_ctrl.h [moved from src/common/wpa_ctrl.h with 100% similarity]
libeap/src/crypto/.gitignore [moved from src/crypto/.gitignore with 100% similarity]
libeap/src/crypto/Makefile [moved from src/crypto/Makefile with 100% similarity]
libeap/src/crypto/aes-cbc.c [moved from src/crypto/aes-cbc.c with 100% similarity]
libeap/src/crypto/aes-ctr.c [moved from src/crypto/aes-ctr.c with 100% similarity]
libeap/src/crypto/aes-eax.c [moved from src/crypto/aes-eax.c with 100% similarity]
libeap/src/crypto/aes-encblock.c [moved from src/crypto/aes-encblock.c with 100% similarity]
libeap/src/crypto/aes-internal-dec.c [moved from src/crypto/aes-internal-dec.c with 100% similarity]
libeap/src/crypto/aes-internal-enc.c [moved from src/crypto/aes-internal-enc.c with 100% similarity]
libeap/src/crypto/aes-internal.c [moved from src/crypto/aes-internal.c with 100% similarity]
libeap/src/crypto/aes-omac1.c [moved from src/crypto/aes-omac1.c with 100% similarity]
libeap/src/crypto/aes-unwrap.c [moved from src/crypto/aes-unwrap.c with 100% similarity]
libeap/src/crypto/aes-wrap.c [moved from src/crypto/aes-wrap.c with 100% similarity]
libeap/src/crypto/aes.h [moved from src/crypto/aes.h with 100% similarity]
libeap/src/crypto/aes_i.h [moved from src/crypto/aes_i.h with 100% similarity]
libeap/src/crypto/aes_wrap.h [moved from src/crypto/aes_wrap.h with 100% similarity]
libeap/src/crypto/crypto.h [moved from src/crypto/crypto.h with 100% similarity]
libeap/src/crypto/crypto_cryptoapi.c [moved from src/crypto/crypto_cryptoapi.c with 100% similarity]
libeap/src/crypto/crypto_gnutls.c [moved from src/crypto/crypto_gnutls.c with 100% similarity]
libeap/src/crypto/crypto_internal-cipher.c [moved from src/crypto/crypto_internal-cipher.c with 100% similarity]
libeap/src/crypto/crypto_internal-modexp.c [moved from src/crypto/crypto_internal-modexp.c with 100% similarity]
libeap/src/crypto/crypto_internal-rsa.c [moved from src/crypto/crypto_internal-rsa.c with 100% similarity]
libeap/src/crypto/crypto_internal.c [moved from src/crypto/crypto_internal.c with 100% similarity]
libeap/src/crypto/crypto_libtomcrypt.c [moved from src/crypto/crypto_libtomcrypt.c with 100% similarity]
libeap/src/crypto/crypto_none.c [moved from src/crypto/crypto_none.c with 100% similarity]
libeap/src/crypto/crypto_nss.c [moved from src/crypto/crypto_nss.c with 100% similarity]
libeap/src/crypto/crypto_openssl.c [moved from src/crypto/crypto_openssl.c with 100% similarity]
libeap/src/crypto/des-internal.c [moved from src/crypto/des-internal.c with 100% similarity]
libeap/src/crypto/des_i.h [moved from src/crypto/des_i.h with 100% similarity]
libeap/src/crypto/dh_group5.c [moved from src/crypto/dh_group5.c with 100% similarity]
libeap/src/crypto/dh_group5.h [moved from src/crypto/dh_group5.h with 100% similarity]
libeap/src/crypto/dh_groups.c [moved from src/crypto/dh_groups.c with 100% similarity]
libeap/src/crypto/dh_groups.h [moved from src/crypto/dh_groups.h with 100% similarity]
libeap/src/crypto/fips_prf_cryptoapi.c [moved from src/crypto/fips_prf_cryptoapi.c with 100% similarity]
libeap/src/crypto/fips_prf_gnutls.c [moved from src/crypto/fips_prf_gnutls.c with 100% similarity]
libeap/src/crypto/fips_prf_internal.c [moved from src/crypto/fips_prf_internal.c with 100% similarity]
libeap/src/crypto/fips_prf_nss.c [moved from src/crypto/fips_prf_nss.c with 100% similarity]
libeap/src/crypto/fips_prf_openssl.c [moved from src/crypto/fips_prf_openssl.c with 100% similarity]
libeap/src/crypto/md4-internal.c [moved from src/crypto/md4-internal.c with 100% similarity]
libeap/src/crypto/md5-internal.c [moved from src/crypto/md5-internal.c with 100% similarity]
libeap/src/crypto/md5-non-fips.c [moved from src/crypto/md5-non-fips.c with 100% similarity]
libeap/src/crypto/md5.c [moved from src/crypto/md5.c with 100% similarity]
libeap/src/crypto/md5.h [moved from src/crypto/md5.h with 100% similarity]
libeap/src/crypto/md5_i.h [moved from src/crypto/md5_i.h with 100% similarity]
libeap/src/crypto/milenage.c [moved from src/crypto/milenage.c with 100% similarity]
libeap/src/crypto/milenage.h [moved from src/crypto/milenage.h with 100% similarity]
libeap/src/crypto/ms_funcs.c [moved from src/crypto/ms_funcs.c with 100% similarity]
libeap/src/crypto/ms_funcs.h [moved from src/crypto/ms_funcs.h with 100% similarity]
libeap/src/crypto/rc4.c [moved from src/crypto/rc4.c with 100% similarity]
libeap/src/crypto/sha1-internal.c [moved from src/crypto/sha1-internal.c with 100% similarity]
libeap/src/crypto/sha1-pbkdf2.c [moved from src/crypto/sha1-pbkdf2.c with 100% similarity]
libeap/src/crypto/sha1-tlsprf.c [moved from src/crypto/sha1-tlsprf.c with 100% similarity]
libeap/src/crypto/sha1-tprf.c [moved from src/crypto/sha1-tprf.c with 100% similarity]
libeap/src/crypto/sha1.c [moved from src/crypto/sha1.c with 100% similarity]
libeap/src/crypto/sha1.h [moved from src/crypto/sha1.h with 100% similarity]
libeap/src/crypto/sha1_i.h [moved from src/crypto/sha1_i.h with 100% similarity]
libeap/src/crypto/sha256-internal.c [moved from src/crypto/sha256-internal.c with 100% similarity]
libeap/src/crypto/sha256.c [moved from src/crypto/sha256.c with 100% similarity]
libeap/src/crypto/sha256.h [moved from src/crypto/sha256.h with 100% similarity]
libeap/src/crypto/tls.h [moved from src/crypto/tls.h with 100% similarity]
libeap/src/crypto/tls_gnutls.c [moved from src/crypto/tls_gnutls.c with 100% similarity]
libeap/src/crypto/tls_internal.c [moved from src/crypto/tls_internal.c with 100% similarity]
libeap/src/crypto/tls_none.c [moved from src/crypto/tls_none.c with 100% similarity]
libeap/src/crypto/tls_nss.c [moved from src/crypto/tls_nss.c with 100% similarity]
libeap/src/crypto/tls_openssl.c [moved from src/crypto/tls_openssl.c with 100% similarity]
libeap/src/crypto/tls_schannel.c [moved from src/crypto/tls_schannel.c with 100% similarity]
libeap/src/drivers/.gitignore [moved from src/drivers/.gitignore with 100% similarity]
libeap/src/drivers/Apple80211.h [moved from src/drivers/Apple80211.h with 100% similarity]
libeap/src/drivers/Makefile [moved from src/drivers/Makefile with 100% similarity]
libeap/src/drivers/MobileApple80211.c [moved from src/drivers/MobileApple80211.c with 100% similarity]
libeap/src/drivers/MobileApple80211.h [moved from src/drivers/MobileApple80211.h with 100% similarity]
libeap/src/drivers/driver.h [moved from src/drivers/driver.h with 100% similarity]
libeap/src/drivers/driver_atheros.c [moved from src/drivers/driver_atheros.c with 100% similarity]
libeap/src/drivers/driver_atmel.c [moved from src/drivers/driver_atmel.c with 100% similarity]
libeap/src/drivers/driver_broadcom.c [moved from src/drivers/driver_broadcom.c with 100% similarity]
libeap/src/drivers/driver_bsd.c [moved from src/drivers/driver_bsd.c with 100% similarity]
libeap/src/drivers/driver_hostap.c [moved from src/drivers/driver_hostap.c with 100% similarity]
libeap/src/drivers/driver_hostap.h [moved from src/drivers/driver_hostap.h with 100% similarity]
libeap/src/drivers/driver_iphone.m [moved from src/drivers/driver_iphone.m with 100% similarity]
libeap/src/drivers/driver_ipw.c [moved from src/drivers/driver_ipw.c with 100% similarity]
libeap/src/drivers/driver_madwifi.c [moved from src/drivers/driver_madwifi.c with 100% similarity]
libeap/src/drivers/driver_ndis.c [moved from src/drivers/driver_ndis.c with 100% similarity]
libeap/src/drivers/driver_ndis.h [moved from src/drivers/driver_ndis.h with 100% similarity]
libeap/src/drivers/driver_ndis_.c [moved from src/drivers/driver_ndis_.c with 100% similarity]
libeap/src/drivers/driver_ndiswrapper.c [moved from src/drivers/driver_ndiswrapper.c with 100% similarity]
libeap/src/drivers/driver_nl80211.c [moved from src/drivers/driver_nl80211.c with 100% similarity]
libeap/src/drivers/driver_none.c [moved from src/drivers/driver_none.c with 100% similarity]
libeap/src/drivers/driver_osx.m [moved from src/drivers/driver_osx.m with 100% similarity]
libeap/src/drivers/driver_privsep.c [moved from src/drivers/driver_privsep.c with 100% similarity]
libeap/src/drivers/driver_ralink.c [moved from src/drivers/driver_ralink.c with 100% similarity]
libeap/src/drivers/driver_ralink.h [moved from src/drivers/driver_ralink.h with 100% similarity]
libeap/src/drivers/driver_roboswitch.c [moved from src/drivers/driver_roboswitch.c with 100% similarity]
libeap/src/drivers/driver_test.c [moved from src/drivers/driver_test.c with 100% similarity]
libeap/src/drivers/driver_wext.c [moved from src/drivers/driver_wext.c with 100% similarity]
libeap/src/drivers/driver_wext.h [moved from src/drivers/driver_wext.h with 100% similarity]
libeap/src/drivers/driver_wired.c [moved from src/drivers/driver_wired.c with 100% similarity]
libeap/src/drivers/drivers.c [moved from src/drivers/drivers.c with 100% similarity]
libeap/src/drivers/drivers.mak [moved from src/drivers/drivers.mak with 100% similarity]
libeap/src/drivers/linux_ioctl.c [moved from src/drivers/linux_ioctl.c with 100% similarity]
libeap/src/drivers/linux_ioctl.h [moved from src/drivers/linux_ioctl.h with 100% similarity]
libeap/src/drivers/ndis_events.c [moved from src/drivers/ndis_events.c with 100% similarity]
libeap/src/drivers/netlink.c [moved from src/drivers/netlink.c with 100% similarity]
libeap/src/drivers/netlink.h [moved from src/drivers/netlink.h with 100% similarity]
libeap/src/drivers/nl80211_copy.h [moved from src/drivers/nl80211_copy.h with 100% similarity]
libeap/src/drivers/priv_netlink.h [moved from src/drivers/priv_netlink.h with 100% similarity]
libeap/src/drivers/rfkill.c [moved from src/drivers/rfkill.c with 100% similarity]
libeap/src/drivers/rfkill.h [moved from src/drivers/rfkill.h with 100% similarity]
libeap/src/drivers/wireless_copy.h [moved from src/drivers/wireless_copy.h with 100% similarity]
libeap/src/eap_common/Makefile [moved from src/l2_packet/Makefile with 100% similarity]
libeap/src/eap_common/chap.c [moved from src/eap_common/chap.c with 100% similarity]
libeap/src/eap_common/chap.h [moved from src/eap_common/chap.h with 100% similarity]
libeap/src/eap_common/eap_common.c [moved from src/eap_common/eap_common.c with 100% similarity]
libeap/src/eap_common/eap_common.h [moved from src/eap_common/eap_common.h with 100% similarity]
libeap/src/eap_common/eap_defs.h [moved from src/eap_common/eap_defs.h with 100% similarity]
libeap/src/eap_common/eap_fast_common.c [moved from src/eap_common/eap_fast_common.c with 100% similarity]
libeap/src/eap_common/eap_fast_common.h [moved from src/eap_common/eap_fast_common.h with 100% similarity]
libeap/src/eap_common/eap_gpsk_common.c [moved from src/eap_common/eap_gpsk_common.c with 100% similarity]
libeap/src/eap_common/eap_gpsk_common.h [moved from src/eap_common/eap_gpsk_common.h with 100% similarity]
libeap/src/eap_common/eap_ikev2_common.c [moved from src/eap_common/eap_ikev2_common.c with 100% similarity]
libeap/src/eap_common/eap_ikev2_common.h [moved from src/eap_common/eap_ikev2_common.h with 100% similarity]
libeap/src/eap_common/eap_pax_common.c [moved from src/eap_common/eap_pax_common.c with 100% similarity]
libeap/src/eap_common/eap_pax_common.h [moved from src/eap_common/eap_pax_common.h with 100% similarity]
libeap/src/eap_common/eap_peap_common.c [moved from src/eap_common/eap_peap_common.c with 100% similarity]
libeap/src/eap_common/eap_peap_common.h [moved from src/eap_common/eap_peap_common.h with 100% similarity]
libeap/src/eap_common/eap_psk_common.c [moved from src/eap_common/eap_psk_common.c with 100% similarity]
libeap/src/eap_common/eap_psk_common.h [moved from src/eap_common/eap_psk_common.h with 100% similarity]
libeap/src/eap_common/eap_pwd_common.c [moved from src/eap_common/eap_pwd_common.c with 100% similarity]
libeap/src/eap_common/eap_pwd_common.h [moved from src/eap_common/eap_pwd_common.h with 100% similarity]
libeap/src/eap_common/eap_sake_common.c [moved from src/eap_common/eap_sake_common.c with 100% similarity]
libeap/src/eap_common/eap_sake_common.h [moved from src/eap_common/eap_sake_common.h with 100% similarity]
libeap/src/eap_common/eap_sim_common.c [moved from src/eap_common/eap_sim_common.c with 100% similarity]
libeap/src/eap_common/eap_sim_common.h [moved from src/eap_common/eap_sim_common.h with 100% similarity]
libeap/src/eap_common/eap_tlv_common.h [moved from src/eap_common/eap_tlv_common.h with 100% similarity]
libeap/src/eap_common/eap_ttls.h [moved from src/eap_common/eap_ttls.h with 100% similarity]
libeap/src/eap_common/eap_wsc_common.c [moved from src/eap_common/eap_wsc_common.c with 100% similarity]
libeap/src/eap_common/eap_wsc_common.h [moved from src/eap_common/eap_wsc_common.h with 100% similarity]
libeap/src/eap_common/ikev2_common.c [moved from src/eap_common/ikev2_common.c with 100% similarity]
libeap/src/eap_common/ikev2_common.h [moved from src/eap_common/ikev2_common.h with 100% similarity]
libeap/src/eap_peer/Makefile [moved from src/eap_peer/Makefile with 100% similarity]
libeap/src/eap_peer/eap.c [moved from src/eap_peer/eap.c with 100% similarity]
libeap/src/eap_peer/eap.h [moved from src/eap_peer/eap.h with 100% similarity]
libeap/src/eap_peer/eap_aka.c [moved from src/eap_peer/eap_aka.c with 100% similarity]
libeap/src/eap_peer/eap_config.h [moved from src/eap_peer/eap_config.h with 100% similarity]
libeap/src/eap_peer/eap_fast.c [moved from src/eap_peer/eap_fast.c with 100% similarity]
libeap/src/eap_peer/eap_fast_pac.c [moved from src/eap_peer/eap_fast_pac.c with 100% similarity]
libeap/src/eap_peer/eap_fast_pac.h [moved from src/eap_peer/eap_fast_pac.h with 100% similarity]
libeap/src/eap_peer/eap_gpsk.c [moved from src/eap_peer/eap_gpsk.c with 100% similarity]
libeap/src/eap_peer/eap_gtc.c [moved from src/eap_peer/eap_gtc.c with 100% similarity]
libeap/src/eap_peer/eap_i.h [moved from src/eap_peer/eap_i.h with 100% similarity]
libeap/src/eap_peer/eap_ikev2.c [moved from src/eap_peer/eap_ikev2.c with 100% similarity]
libeap/src/eap_peer/eap_leap.c [moved from src/eap_peer/eap_leap.c with 100% similarity]
libeap/src/eap_peer/eap_md5.c [moved from src/eap_peer/eap_md5.c with 100% similarity]
libeap/src/eap_peer/eap_methods.c [moved from src/eap_peer/eap_methods.c with 100% similarity]
libeap/src/eap_peer/eap_methods.h [moved from src/eap_peer/eap_methods.h with 100% similarity]
libeap/src/eap_peer/eap_mschapv2.c [moved from src/eap_peer/eap_mschapv2.c with 100% similarity]
libeap/src/eap_peer/eap_otp.c [moved from src/eap_peer/eap_otp.c with 100% similarity]
libeap/src/eap_peer/eap_pax.c [moved from src/eap_peer/eap_pax.c with 100% similarity]
libeap/src/eap_peer/eap_peap.c [moved from src/eap_peer/eap_peap.c with 100% similarity]
libeap/src/eap_peer/eap_psk.c [moved from src/eap_peer/eap_psk.c with 100% similarity]
libeap/src/eap_peer/eap_pwd.c [moved from src/eap_peer/eap_pwd.c with 100% similarity]
libeap/src/eap_peer/eap_sake.c [moved from src/eap_peer/eap_sake.c with 100% similarity]
libeap/src/eap_peer/eap_sim.c [moved from src/eap_peer/eap_sim.c with 100% similarity]
libeap/src/eap_peer/eap_tls.c [moved from src/eap_peer/eap_tls.c with 100% similarity]
libeap/src/eap_peer/eap_tls_common.c [moved from src/eap_peer/eap_tls_common.c with 100% similarity]
libeap/src/eap_peer/eap_tls_common.h [moved from src/eap_peer/eap_tls_common.h with 100% similarity]
libeap/src/eap_peer/eap_tnc.c [moved from src/eap_peer/eap_tnc.c with 100% similarity]
libeap/src/eap_peer/eap_ttls.c [moved from src/eap_peer/eap_ttls.c with 100% similarity]
libeap/src/eap_peer/eap_vendor_test.c [moved from src/eap_peer/eap_vendor_test.c with 100% similarity]
libeap/src/eap_peer/eap_wsc.c [moved from src/eap_peer/eap_wsc.c with 100% similarity]
libeap/src/eap_peer/ikev2.c [moved from src/eap_peer/ikev2.c with 100% similarity]
libeap/src/eap_peer/ikev2.h [moved from src/eap_peer/ikev2.h with 100% similarity]
libeap/src/eap_peer/mschapv2.c [moved from src/eap_peer/mschapv2.c with 100% similarity]
libeap/src/eap_peer/mschapv2.h [moved from src/eap_peer/mschapv2.h with 100% similarity]
libeap/src/eap_peer/tncc.c [moved from src/eap_peer/tncc.c with 100% similarity]
libeap/src/eap_peer/tncc.h [moved from src/eap_peer/tncc.h with 100% similarity]
libeap/src/eap_server/Makefile [moved from src/eapol_supp/Makefile with 100% similarity]
libeap/src/eap_server/eap.h [moved from src/eap_server/eap.h with 100% similarity]
libeap/src/eap_server/eap_i.h [moved from src/eap_server/eap_i.h with 100% similarity]
libeap/src/eap_server/eap_methods.h [moved from src/eap_server/eap_methods.h with 100% similarity]
libeap/src/eap_server/eap_server.c [moved from src/eap_server/eap_server.c with 100% similarity]
libeap/src/eap_server/eap_server_aka.c [moved from src/eap_server/eap_server_aka.c with 100% similarity]
libeap/src/eap_server/eap_server_fast.c [moved from src/eap_server/eap_server_fast.c with 100% similarity]
libeap/src/eap_server/eap_server_gpsk.c [moved from src/eap_server/eap_server_gpsk.c with 100% similarity]
libeap/src/eap_server/eap_server_gtc.c [moved from src/eap_server/eap_server_gtc.c with 100% similarity]
libeap/src/eap_server/eap_server_identity.c [moved from src/eap_server/eap_server_identity.c with 100% similarity]
libeap/src/eap_server/eap_server_ikev2.c [moved from src/eap_server/eap_server_ikev2.c with 100% similarity]
libeap/src/eap_server/eap_server_md5.c [moved from src/eap_server/eap_server_md5.c with 100% similarity]
libeap/src/eap_server/eap_server_methods.c [moved from src/eap_server/eap_server_methods.c with 100% similarity]
libeap/src/eap_server/eap_server_mschapv2.c [moved from src/eap_server/eap_server_mschapv2.c with 100% similarity]
libeap/src/eap_server/eap_server_pax.c [moved from src/eap_server/eap_server_pax.c with 100% similarity]
libeap/src/eap_server/eap_server_peap.c [moved from src/eap_server/eap_server_peap.c with 100% similarity]
libeap/src/eap_server/eap_server_psk.c [moved from src/eap_server/eap_server_psk.c with 100% similarity]
libeap/src/eap_server/eap_server_pwd.c [moved from src/eap_server/eap_server_pwd.c with 100% similarity]
libeap/src/eap_server/eap_server_sake.c [moved from src/eap_server/eap_server_sake.c with 100% similarity]
libeap/src/eap_server/eap_server_sim.c [moved from src/eap_server/eap_server_sim.c with 100% similarity]
libeap/src/eap_server/eap_server_tls.c [moved from src/eap_server/eap_server_tls.c with 100% similarity]
libeap/src/eap_server/eap_server_tls_common.c [moved from src/eap_server/eap_server_tls_common.c with 100% similarity]
libeap/src/eap_server/eap_server_tnc.c [moved from src/eap_server/eap_server_tnc.c with 100% similarity]
libeap/src/eap_server/eap_server_ttls.c [moved from src/eap_server/eap_server_ttls.c with 100% similarity]
libeap/src/eap_server/eap_server_vendor_test.c [moved from src/eap_server/eap_server_vendor_test.c with 100% similarity]
libeap/src/eap_server/eap_server_wsc.c [moved from src/eap_server/eap_server_wsc.c with 100% similarity]
libeap/src/eap_server/eap_sim_db.c [moved from src/eap_server/eap_sim_db.c with 100% similarity]
libeap/src/eap_server/eap_sim_db.h [moved from src/eap_server/eap_sim_db.h with 100% similarity]
libeap/src/eap_server/eap_tls_common.h [moved from src/eap_server/eap_tls_common.h with 100% similarity]
libeap/src/eap_server/ikev2.c [moved from src/eap_server/ikev2.c with 100% similarity]
libeap/src/eap_server/ikev2.h [moved from src/eap_server/ikev2.h with 100% similarity]
libeap/src/eap_server/tncs.c [moved from src/eap_server/tncs.c with 100% similarity]
libeap/src/eap_server/tncs.h [moved from src/eap_server/tncs.h with 100% similarity]
libeap/src/eapol_auth/Makefile [moved from src/eapol_auth/Makefile with 100% similarity]
libeap/src/eapol_auth/eapol_auth_dump.c [moved from src/eapol_auth/eapol_auth_dump.c with 100% similarity]
libeap/src/eapol_auth/eapol_auth_sm.c [moved from src/eapol_auth/eapol_auth_sm.c with 100% similarity]
libeap/src/eapol_auth/eapol_auth_sm.h [moved from src/eapol_auth/eapol_auth_sm.h with 100% similarity]
libeap/src/eapol_auth/eapol_auth_sm_i.h [moved from src/eapol_auth/eapol_auth_sm_i.h with 100% similarity]
libeap/src/eapol_supp/Makefile [moved from src/eap_server/Makefile with 100% similarity]
libeap/src/eapol_supp/eapol_supp_sm.c [moved from src/eapol_supp/eapol_supp_sm.c with 100% similarity]
libeap/src/eapol_supp/eapol_supp_sm.h [moved from src/eapol_supp/eapol_supp_sm.h with 100% similarity]
libeap/src/l2_packet/Makefile [moved from src/eap_common/Makefile with 100% similarity]
libeap/src/l2_packet/l2_packet.h [moved from src/l2_packet/l2_packet.h with 100% similarity]
libeap/src/l2_packet/l2_packet_freebsd.c [moved from src/l2_packet/l2_packet_freebsd.c with 100% similarity]
libeap/src/l2_packet/l2_packet_linux.c [moved from src/l2_packet/l2_packet_linux.c with 100% similarity]
libeap/src/l2_packet/l2_packet_ndis.c [moved from src/l2_packet/l2_packet_ndis.c with 100% similarity]
libeap/src/l2_packet/l2_packet_none.c [moved from src/l2_packet/l2_packet_none.c with 100% similarity]
libeap/src/l2_packet/l2_packet_pcap.c [moved from src/l2_packet/l2_packet_pcap.c with 100% similarity]
libeap/src/l2_packet/l2_packet_privsep.c [moved from src/l2_packet/l2_packet_privsep.c with 100% similarity]
libeap/src/l2_packet/l2_packet_winpcap.c [moved from src/l2_packet/l2_packet_winpcap.c with 100% similarity]
libeap/src/lib.rules [moved from src/lib.rules with 100% similarity]
libeap/src/p2p/Makefile [moved from src/p2p/Makefile with 100% similarity]
libeap/src/p2p/p2p.c [moved from src/p2p/p2p.c with 100% similarity]
libeap/src/p2p/p2p.h [moved from src/p2p/p2p.h with 100% similarity]
libeap/src/p2p/p2p_build.c [moved from src/p2p/p2p_build.c with 100% similarity]
libeap/src/p2p/p2p_dev_disc.c [moved from src/p2p/p2p_dev_disc.c with 100% similarity]
libeap/src/p2p/p2p_go_neg.c [moved from src/p2p/p2p_go_neg.c with 100% similarity]
libeap/src/p2p/p2p_group.c [moved from src/p2p/p2p_group.c with 100% similarity]
libeap/src/p2p/p2p_i.h [moved from src/p2p/p2p_i.h with 100% similarity]
libeap/src/p2p/p2p_invitation.c [moved from src/p2p/p2p_invitation.c with 100% similarity]
libeap/src/p2p/p2p_parse.c [moved from src/p2p/p2p_parse.c with 100% similarity]
libeap/src/p2p/p2p_pd.c [moved from src/p2p/p2p_pd.c with 100% similarity]
libeap/src/p2p/p2p_sd.c [moved from src/p2p/p2p_sd.c with 100% similarity]
libeap/src/p2p/p2p_utils.c [moved from src/p2p/p2p_utils.c with 100% similarity]
libeap/src/radius/.gitignore [moved from src/radius/.gitignore with 100% similarity]
libeap/src/radius/Makefile [moved from src/radius/Makefile with 100% similarity]
libeap/src/radius/radius.c [moved from src/radius/radius.c with 100% similarity]
libeap/src/radius/radius.h [moved from src/radius/radius.h with 100% similarity]
libeap/src/radius/radius_client.c [moved from src/radius/radius_client.c with 100% similarity]
libeap/src/radius/radius_client.h [moved from src/radius/radius_client.h with 100% similarity]
libeap/src/radius/radius_server.c [moved from src/radius/radius_server.c with 100% similarity]
libeap/src/radius/radius_server.h [moved from src/radius/radius_server.h with 100% similarity]
libeap/src/rsn_supp/Makefile [moved from src/common/Makefile with 100% similarity]
libeap/src/rsn_supp/peerkey.c [moved from src/rsn_supp/peerkey.c with 100% similarity]
libeap/src/rsn_supp/peerkey.h [moved from src/rsn_supp/peerkey.h with 100% similarity]
libeap/src/rsn_supp/pmksa_cache.c [moved from src/rsn_supp/pmksa_cache.c with 100% similarity]
libeap/src/rsn_supp/pmksa_cache.h [moved from src/rsn_supp/pmksa_cache.h with 100% similarity]
libeap/src/rsn_supp/preauth.c [moved from src/rsn_supp/preauth.c with 100% similarity]
libeap/src/rsn_supp/preauth.h [moved from src/rsn_supp/preauth.h with 100% similarity]
libeap/src/rsn_supp/wpa.c [moved from src/rsn_supp/wpa.c with 100% similarity]
libeap/src/rsn_supp/wpa.h [moved from src/rsn_supp/wpa.h with 100% similarity]
libeap/src/rsn_supp/wpa_ft.c [moved from src/rsn_supp/wpa_ft.c with 100% similarity]
libeap/src/rsn_supp/wpa_i.h [moved from src/rsn_supp/wpa_i.h with 100% similarity]
libeap/src/rsn_supp/wpa_ie.c [moved from src/rsn_supp/wpa_ie.c with 100% similarity]
libeap/src/rsn_supp/wpa_ie.h [moved from src/rsn_supp/wpa_ie.h with 100% similarity]
libeap/src/tls/.gitignore [moved from src/tls/.gitignore with 100% similarity]
libeap/src/tls/Makefile [moved from src/tls/Makefile with 100% similarity]
libeap/src/tls/asn1.c [moved from src/tls/asn1.c with 100% similarity]
libeap/src/tls/asn1.h [moved from src/tls/asn1.h with 100% similarity]
libeap/src/tls/bignum.c [moved from src/tls/bignum.c with 100% similarity]
libeap/src/tls/bignum.h [moved from src/tls/bignum.h with 100% similarity]
libeap/src/tls/libtommath.c [moved from src/tls/libtommath.c with 100% similarity]
libeap/src/tls/pkcs1.c [moved from src/tls/pkcs1.c with 100% similarity]
libeap/src/tls/pkcs1.h [moved from src/tls/pkcs1.h with 100% similarity]
libeap/src/tls/pkcs5.c [moved from src/tls/pkcs5.c with 100% similarity]
libeap/src/tls/pkcs5.h [moved from src/tls/pkcs5.h with 100% similarity]
libeap/src/tls/pkcs8.c [moved from src/tls/pkcs8.c with 100% similarity]
libeap/src/tls/pkcs8.h [moved from src/tls/pkcs8.h with 100% similarity]
libeap/src/tls/rsa.c [moved from src/tls/rsa.c with 100% similarity]
libeap/src/tls/rsa.h [moved from src/tls/rsa.h with 100% similarity]
libeap/src/tls/tlsv1_client.c [moved from src/tls/tlsv1_client.c with 100% similarity]
libeap/src/tls/tlsv1_client.h [moved from src/tls/tlsv1_client.h with 100% similarity]
libeap/src/tls/tlsv1_client_i.h [moved from src/tls/tlsv1_client_i.h with 100% similarity]
libeap/src/tls/tlsv1_client_read.c [moved from src/tls/tlsv1_client_read.c with 100% similarity]
libeap/src/tls/tlsv1_client_write.c [moved from src/tls/tlsv1_client_write.c with 100% similarity]
libeap/src/tls/tlsv1_common.c [moved from src/tls/tlsv1_common.c with 100% similarity]
libeap/src/tls/tlsv1_common.h [moved from src/tls/tlsv1_common.h with 100% similarity]
libeap/src/tls/tlsv1_cred.c [moved from src/tls/tlsv1_cred.c with 100% similarity]
libeap/src/tls/tlsv1_cred.h [moved from src/tls/tlsv1_cred.h with 100% similarity]
libeap/src/tls/tlsv1_record.c [moved from src/tls/tlsv1_record.c with 100% similarity]
libeap/src/tls/tlsv1_record.h [moved from src/tls/tlsv1_record.h with 100% similarity]
libeap/src/tls/tlsv1_server.c [moved from src/tls/tlsv1_server.c with 100% similarity]
libeap/src/tls/tlsv1_server.h [moved from src/tls/tlsv1_server.h with 100% similarity]
libeap/src/tls/tlsv1_server_i.h [moved from src/tls/tlsv1_server_i.h with 100% similarity]
libeap/src/tls/tlsv1_server_read.c [moved from src/tls/tlsv1_server_read.c with 100% similarity]
libeap/src/tls/tlsv1_server_write.c [moved from src/tls/tlsv1_server_write.c with 100% similarity]
libeap/src/tls/x509v3.c [moved from src/tls/x509v3.c with 100% similarity]
libeap/src/tls/x509v3.h [moved from src/tls/x509v3.h with 100% similarity]
libeap/src/utils/.gitignore [moved from src/utils/.gitignore with 100% similarity]
libeap/src/utils/Makefile [moved from src/utils/Makefile with 100% similarity]
libeap/src/utils/base64.c [moved from src/utils/base64.c with 100% similarity]
libeap/src/utils/base64.h [moved from src/utils/base64.h with 100% similarity]
libeap/src/utils/build_config.h [moved from src/utils/build_config.h with 100% similarity]
libeap/src/utils/common.c [moved from src/utils/common.c with 100% similarity]
libeap/src/utils/common.h [moved from src/utils/common.h with 100% similarity]
libeap/src/utils/eloop.c [moved from src/utils/eloop.c with 100% similarity]
libeap/src/utils/eloop.h [moved from src/utils/eloop.h with 100% similarity]
libeap/src/utils/eloop_none.c [moved from src/utils/eloop_none.c with 100% similarity]
libeap/src/utils/eloop_win.c [moved from src/utils/eloop_win.c with 100% similarity]
libeap/src/utils/includes.h [moved from src/utils/includes.h with 100% similarity]
libeap/src/utils/ip_addr.c [moved from src/utils/ip_addr.c with 100% similarity]
libeap/src/utils/ip_addr.h [moved from src/utils/ip_addr.h with 100% similarity]
libeap/src/utils/list.h [moved from src/utils/list.h with 100% similarity]
libeap/src/utils/os.h [moved from src/utils/os.h with 100% similarity]
libeap/src/utils/os_internal.c [moved from src/utils/os_internal.c with 100% similarity]
libeap/src/utils/os_none.c [moved from src/utils/os_none.c with 100% similarity]
libeap/src/utils/os_unix.c [moved from src/utils/os_unix.c with 100% similarity]
libeap/src/utils/os_win32.c [moved from src/utils/os_win32.c with 100% similarity]
libeap/src/utils/pcsc_funcs.c [moved from src/utils/pcsc_funcs.c with 100% similarity]
libeap/src/utils/pcsc_funcs.h [moved from src/utils/pcsc_funcs.h with 100% similarity]
libeap/src/utils/radiotap.c [moved from src/utils/radiotap.c with 100% similarity]
libeap/src/utils/radiotap.h [moved from src/utils/radiotap.h with 100% similarity]
libeap/src/utils/radiotap_iter.h [moved from src/utils/radiotap_iter.h with 100% similarity]
libeap/src/utils/state_machine.h [moved from src/utils/state_machine.h with 100% similarity]
libeap/src/utils/trace.c [moved from src/utils/trace.c with 100% similarity]
libeap/src/utils/trace.h [moved from src/utils/trace.h with 100% similarity]
libeap/src/utils/uuid.c [moved from src/utils/uuid.c with 100% similarity]
libeap/src/utils/uuid.h [moved from src/utils/uuid.h with 100% similarity]
libeap/src/utils/wpa_debug.c [moved from src/utils/wpa_debug.c with 100% similarity]
libeap/src/utils/wpa_debug.h [moved from src/utils/wpa_debug.h with 100% similarity]
libeap/src/utils/wpabuf.c [moved from src/utils/wpabuf.c with 100% similarity]
libeap/src/utils/wpabuf.h [moved from src/utils/wpabuf.h with 100% similarity]
libeap/src/wps/Makefile [moved from src/ap/Makefile with 100% similarity]
libeap/src/wps/http.h [moved from src/wps/http.h with 100% similarity]
libeap/src/wps/http_client.c [moved from src/wps/http_client.c with 100% similarity]
libeap/src/wps/http_client.h [moved from src/wps/http_client.h with 100% similarity]
libeap/src/wps/http_server.c [moved from src/wps/http_server.c with 100% similarity]
libeap/src/wps/http_server.h [moved from src/wps/http_server.h with 100% similarity]
libeap/src/wps/httpread.c [moved from src/wps/httpread.c with 100% similarity]
libeap/src/wps/httpread.h [moved from src/wps/httpread.h with 100% similarity]
libeap/src/wps/ndef.c [moved from src/wps/ndef.c with 100% similarity]
libeap/src/wps/upnp_xml.c [moved from src/wps/upnp_xml.c with 100% similarity]
libeap/src/wps/upnp_xml.h [moved from src/wps/upnp_xml.h with 100% similarity]
libeap/src/wps/wps.c [moved from src/wps/wps.c with 100% similarity]
libeap/src/wps/wps.h [moved from src/wps/wps.h with 100% similarity]
libeap/src/wps/wps_attr_build.c [moved from src/wps/wps_attr_build.c with 100% similarity]
libeap/src/wps/wps_attr_parse.c [moved from src/wps/wps_attr_parse.c with 100% similarity]
libeap/src/wps/wps_attr_process.c [moved from src/wps/wps_attr_process.c with 100% similarity]
libeap/src/wps/wps_common.c [moved from src/wps/wps_common.c with 100% similarity]
libeap/src/wps/wps_defs.h [moved from src/wps/wps_defs.h with 100% similarity]
libeap/src/wps/wps_dev_attr.c [moved from src/wps/wps_dev_attr.c with 100% similarity]
libeap/src/wps/wps_dev_attr.h [moved from src/wps/wps_dev_attr.h with 100% similarity]
libeap/src/wps/wps_enrollee.c [moved from src/wps/wps_enrollee.c with 100% similarity]
libeap/src/wps/wps_er.c [moved from src/wps/wps_er.c with 100% similarity]
libeap/src/wps/wps_er.h [moved from src/wps/wps_er.h with 100% similarity]
libeap/src/wps/wps_er_ssdp.c [moved from src/wps/wps_er_ssdp.c with 100% similarity]
libeap/src/wps/wps_i.h [moved from src/wps/wps_i.h with 100% similarity]
libeap/src/wps/wps_nfc.c [moved from src/wps/wps_nfc.c with 100% similarity]
libeap/src/wps/wps_nfc_pn531.c [moved from src/wps/wps_nfc_pn531.c with 100% similarity]
libeap/src/wps/wps_registrar.c [moved from src/wps/wps_registrar.c with 100% similarity]
libeap/src/wps/wps_ufd.c [moved from src/wps/wps_ufd.c with 100% similarity]
libeap/src/wps/wps_upnp.c [moved from src/wps/wps_upnp.c with 100% similarity]
libeap/src/wps/wps_upnp.h [moved from src/wps/wps_upnp.h with 100% similarity]
libeap/src/wps/wps_upnp_ap.c [moved from src/wps/wps_upnp_ap.c with 100% similarity]
libeap/src/wps/wps_upnp_event.c [moved from src/wps/wps_upnp_event.c with 100% similarity]
libeap/src/wps/wps_upnp_i.h [moved from src/wps/wps_upnp_i.h with 100% similarity]
libeap/src/wps/wps_upnp_ssdp.c [moved from src/wps/wps_upnp_ssdp.c with 100% similarity]
libeap/src/wps/wps_upnp_web.c [moved from src/wps/wps_upnp_web.c with 100% similarity]
libeap/src/wps/wps_validate.c [moved from src/wps/wps_validate.c with 100% similarity]
libeap/testing/compile_wireless_versions [moved from testing/compile_wireless_versions with 100% similarity]
libeap/testing/hostapd-config/arm [moved from testing/hostapd-config/arm with 100% similarity]
libeap/testing/hostapd-config/arm-0.4 [moved from testing/hostapd-config/arm-0.4 with 100% similarity]
libeap/testing/hostapd-config/freebsd [moved from testing/hostapd-config/freebsd with 100% similarity]
libeap/testing/hostapd-config/full [moved from testing/hostapd-config/full with 100% similarity]
libeap/testing/hostapd-config/full-0.4 [moved from testing/hostapd-config/full-0.4 with 100% similarity]
libeap/testing/hostapd-config/gcc-cvs [moved from testing/hostapd-config/gcc-cvs with 100% similarity]
libeap/testing/hostapd-config/minimal [moved from testing/hostapd-config/minimal with 100% similarity]
libeap/testing/hostapd-config/minimal-0.4 [moved from testing/hostapd-config/minimal-0.4 with 100% similarity]
libeap/testing/hostapd-config/noeap [moved from testing/hostapd-config/noeap with 100% similarity]
libeap/testing/hostapd-config/noeap-0.4 [moved from testing/hostapd-config/noeap-0.4 with 100% similarity]
libeap/testing/hostapd-config/x86_64 [moved from testing/hostapd-config/x86_64 with 100% similarity]
libeap/testing/run-hostapd [moved from testing/run-hostapd with 100% similarity]
libeap/testing/run-hostapd-0.3 [moved from testing/run-hostapd-0.3 with 100% similarity]
libeap/testing/run-hostapd-0.4 [moved from testing/run-hostapd-0.4 with 100% similarity]
libeap/testing/run-wpa_supplicant [moved from testing/run-wpa_supplicant with 100% similarity]
libeap/testing/run-wpa_supplicant-0.3 [moved from testing/run-wpa_supplicant-0.3 with 100% similarity]
libeap/testing/run-wpa_supplicant-0.4 [moved from testing/run-wpa_supplicant-0.4 with 100% similarity]
libeap/testing/wireless/iw_handler-2.h [moved from testing/wireless/iw_handler-2.h with 100% similarity]
libeap/testing/wireless/iw_handler-3.h [moved from testing/wireless/iw_handler-3.h with 100% similarity]
libeap/testing/wireless/iw_handler-4.h [moved from testing/wireless/iw_handler-4.h with 100% similarity]
libeap/testing/wireless/iw_handler-5.h [moved from testing/wireless/iw_handler-5.h with 100% similarity]
libeap/testing/wireless/iw_handler-6.h [moved from testing/wireless/iw_handler-6.h with 100% similarity]
libeap/testing/wireless/iw_handler-7.h [moved from testing/wireless/iw_handler-7.h with 100% similarity]
libeap/testing/wireless/wireless-10.h [moved from testing/wireless/wireless-10.h with 100% similarity]
libeap/testing/wireless/wireless-11.h [moved from testing/wireless/wireless-11.h with 100% similarity]
libeap/testing/wireless/wireless-12.h [moved from testing/wireless/wireless-12.h with 100% similarity]
libeap/testing/wireless/wireless-13.h [moved from testing/wireless/wireless-13.h with 100% similarity]
libeap/testing/wireless/wireless-14.h [moved from testing/wireless/wireless-14.h with 100% similarity]
libeap/testing/wireless/wireless-15.h [moved from testing/wireless/wireless-15.h with 100% similarity]
libeap/testing/wireless/wireless-16.h [moved from testing/wireless/wireless-16.h with 100% similarity]
libeap/testing/wireless/wireless-17.h [moved from testing/wireless/wireless-17.h with 100% similarity]
libeap/testing/wireless/wireless-18.h [moved from testing/wireless/wireless-18.h with 100% similarity]
libeap/testing/wireless/wireless-19.h [moved from testing/wireless/wireless-19.h with 100% similarity]
libeap/testing/wireless/wireless-6.h [moved from testing/wireless/wireless-6.h with 100% similarity]
libeap/testing/wireless/wireless-8.h [moved from testing/wireless/wireless-8.h with 100% similarity]
libeap/testing/wireless/wireless-9.h [moved from testing/wireless/wireless-9.h with 100% similarity]
libeap/testing/wpa_supplicant-config/arm [moved from testing/wpa_supplicant-config/arm with 100% similarity]
libeap/testing/wpa_supplicant-config/default [moved from testing/wpa_supplicant-config/default with 100% similarity]
libeap/testing/wpa_supplicant-config/default-0.3 [moved from testing/wpa_supplicant-config/default-0.3 with 100% similarity]
libeap/testing/wpa_supplicant-config/dyneap [moved from testing/wpa_supplicant-config/dyneap with 100% similarity]
libeap/testing/wpa_supplicant-config/freebsd [moved from testing/wpa_supplicant-config/freebsd with 100% similarity]
libeap/testing/wpa_supplicant-config/gcc-cvs [moved from testing/wpa_supplicant-config/gcc-cvs with 100% similarity]
libeap/testing/wpa_supplicant-config/minimal [moved from testing/wpa_supplicant-config/minimal with 100% similarity]
libeap/testing/wpa_supplicant-config/minimal-wpa [moved from testing/wpa_supplicant-config/minimal-wpa with 100% similarity]
libeap/testing/wpa_supplicant-config/windows [moved from testing/wpa_supplicant-config/windows with 100% similarity]
libeap/testing/wpa_supplicant-config/windows-0.3 [moved from testing/wpa_supplicant-config/windows-0.3 with 100% similarity]
libeap/testing/wpa_supplicant-config/windows-0.4 [moved from testing/wpa_supplicant-config/windows-0.4 with 100% similarity]
libeap/testing/wpa_supplicant-config/windows2 [moved from testing/wpa_supplicant-config/windows2 with 100% similarity]
libeap/testing/wpa_supplicant-config/windows2-0.3 [moved from testing/wpa_supplicant-config/windows2-0.3 with 100% similarity]
libeap/testing/wpa_supplicant-config/windows2-0.4 [moved from testing/wpa_supplicant-config/windows2-0.4 with 100% similarity]
libeap/testing/wpa_supplicant-config/x86_64 [moved from testing/wpa_supplicant-config/x86_64 with 100% similarity]
libeap/tests/.gitignore [moved from tests/.gitignore with 100% similarity]
libeap/tests/Makefile [moved from tests/Makefile with 100% similarity]
libeap/tests/test-aes.c [moved from tests/test-aes.c with 100% similarity]
libeap/tests/test-asn1.c [moved from tests/test-asn1.c with 100% similarity]
libeap/tests/test-base64.c [moved from tests/test-base64.c with 100% similarity]
libeap/tests/test-list.c [moved from tests/test-list.c with 100% similarity]
libeap/tests/test-md4.c [moved from tests/test-md4.c with 100% similarity]
libeap/tests/test-md5.c [moved from tests/test-md5.c with 100% similarity]
libeap/tests/test-milenage.c [moved from tests/test-milenage.c with 100% similarity]
libeap/tests/test-ms_funcs.c [moved from tests/test-ms_funcs.c with 100% similarity]
libeap/tests/test-sha1.c [moved from tests/test-sha1.c with 100% similarity]
libeap/tests/test-sha256.c [moved from tests/test-sha256.c with 100% similarity]
libeap/tests/test-x509.c [moved from tests/test-x509.c with 100% similarity]
libeap/tests/test-x509v3.c [moved from tests/test-x509v3.c with 100% similarity]
libeap/tests/test_x509v3_nist.sh [moved from tests/test_x509v3_nist.sh with 100% similarity]
libeap/tests/test_x509v3_nist2.sh [moved from tests/test_x509v3_nist2.sh with 100% similarity]
libeap/wpa_supplicant/.gitignore [moved from wpa_supplicant/.gitignore with 100% similarity]
libeap/wpa_supplicant/ChangeLog [moved from wpa_supplicant/ChangeLog with 100% similarity]
libeap/wpa_supplicant/Makefile [moved from wpa_supplicant/Makefile with 100% similarity]
libeap/wpa_supplicant/README [moved from wpa_supplicant/README with 100% similarity]
libeap/wpa_supplicant/README-WPS [moved from wpa_supplicant/README-WPS with 100% similarity]
libeap/wpa_supplicant/README-Windows.txt [moved from wpa_supplicant/README-Windows.txt with 100% similarity]
libeap/wpa_supplicant/ap.c [moved from wpa_supplicant/ap.c with 100% similarity]
libeap/wpa_supplicant/ap.h [moved from wpa_supplicant/ap.h with 100% similarity]
libeap/wpa_supplicant/bgscan.c [moved from wpa_supplicant/bgscan.c with 100% similarity]
libeap/wpa_supplicant/bgscan.h [moved from wpa_supplicant/bgscan.h with 100% similarity]
libeap/wpa_supplicant/bgscan_learn.c [moved from wpa_supplicant/bgscan_learn.c with 100% similarity]
libeap/wpa_supplicant/bgscan_simple.c [moved from wpa_supplicant/bgscan_simple.c with 100% similarity]
libeap/wpa_supplicant/blacklist.c [moved from wpa_supplicant/blacklist.c with 100% similarity]
libeap/wpa_supplicant/blacklist.h [moved from wpa_supplicant/blacklist.h with 100% similarity]
libeap/wpa_supplicant/bss.c [moved from wpa_supplicant/bss.c with 100% similarity]
libeap/wpa_supplicant/bss.h [moved from wpa_supplicant/bss.h with 100% similarity]
libeap/wpa_supplicant/config.c [moved from wpa_supplicant/config.c with 100% similarity]
libeap/wpa_supplicant/config.h [moved from wpa_supplicant/config.h with 100% similarity]
libeap/wpa_supplicant/config_file.c [moved from wpa_supplicant/config_file.c with 100% similarity]
libeap/wpa_supplicant/config_none.c [moved from wpa_supplicant/config_none.c with 100% similarity]
libeap/wpa_supplicant/config_ssid.h [moved from wpa_supplicant/config_ssid.h with 100% similarity]
libeap/wpa_supplicant/config_winreg.c [moved from wpa_supplicant/config_winreg.c with 100% similarity]
libeap/wpa_supplicant/ctrl_iface.c [moved from wpa_supplicant/ctrl_iface.c with 100% similarity]
libeap/wpa_supplicant/ctrl_iface.h [moved from wpa_supplicant/ctrl_iface.h with 100% similarity]
libeap/wpa_supplicant/ctrl_iface_named_pipe.c [moved from wpa_supplicant/ctrl_iface_named_pipe.c with 100% similarity]
libeap/wpa_supplicant/ctrl_iface_udp.c [moved from wpa_supplicant/ctrl_iface_udp.c with 100% similarity]
libeap/wpa_supplicant/ctrl_iface_unix.c [moved from wpa_supplicant/ctrl_iface_unix.c with 100% similarity]
libeap/wpa_supplicant/dbus/.gitignore [moved from wpa_supplicant/dbus/.gitignore with 100% similarity]
libeap/wpa_supplicant/dbus/Makefile [moved from wpa_supplicant/dbus/Makefile with 100% similarity]
libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf [moved from wpa_supplicant/dbus/dbus-wpa_supplicant.conf with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_common.c [moved from wpa_supplicant/dbus/dbus_common.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_common.h [moved from wpa_supplicant/dbus/dbus_common.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_common_i.h [moved from wpa_supplicant/dbus/dbus_common_i.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_dict_helpers.c [moved from wpa_supplicant/dbus/dbus_dict_helpers.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_dict_helpers.h [moved from wpa_supplicant/dbus/dbus_dict_helpers.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new.c [moved from wpa_supplicant/dbus/dbus_new.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new.h [moved from wpa_supplicant/dbus/dbus_new.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_handlers.c [moved from wpa_supplicant/dbus/dbus_new_handlers.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_handlers.h [moved from wpa_supplicant/dbus/dbus_new_handlers.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c [moved from wpa_supplicant/dbus/dbus_new_handlers_wps.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_helpers.c [moved from wpa_supplicant/dbus/dbus_new_helpers.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_helpers.h [moved from wpa_supplicant/dbus/dbus_new_helpers.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_new_introspect.c [moved from wpa_supplicant/dbus/dbus_new_introspect.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_old.c [moved from wpa_supplicant/dbus/dbus_old.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_old.h [moved from wpa_supplicant/dbus/dbus_old.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_old_handlers.c [moved from wpa_supplicant/dbus/dbus_old_handlers.c with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_old_handlers.h [moved from wpa_supplicant/dbus/dbus_old_handlers.h with 100% similarity]
libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c [moved from wpa_supplicant/dbus/dbus_old_handlers_wps.c with 100% similarity]
libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service [moved from wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service with 100% similarity]
libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service [moved from wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service with 100% similarity]
libeap/wpa_supplicant/defconfig [moved from wpa_supplicant/defconfig with 100% similarity]
libeap/wpa_supplicant/doc/docbook/.gitignore [moved from wpa_supplicant/doc/docbook/.gitignore with 100% similarity]
libeap/wpa_supplicant/doc/docbook/Makefile [moved from wpa_supplicant/doc/docbook/Makefile with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_background.sgml [moved from wpa_supplicant/doc/docbook/wpa_background.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml [moved from wpa_supplicant/doc/docbook/wpa_cli.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml [moved from wpa_supplicant/doc/docbook/wpa_gui.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml [moved from wpa_supplicant/doc/docbook/wpa_passphrase.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml [moved from wpa_supplicant/doc/docbook/wpa_priv.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml [moved from wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml with 100% similarity]
libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml [moved from wpa_supplicant/doc/docbook/wpa_supplicant.sgml with 100% similarity]
libeap/wpa_supplicant/driver_i.h [moved from wpa_supplicant/driver_i.h with 100% similarity]
libeap/wpa_supplicant/eap_register.c [moved from wpa_supplicant/eap_register.c with 100% similarity]
libeap/wpa_supplicant/eap_testing.txt [moved from wpa_supplicant/eap_testing.txt with 100% similarity]
libeap/wpa_supplicant/eapol_test.c [moved from wpa_supplicant/eapol_test.c with 100% similarity]
libeap/wpa_supplicant/events.c [moved from wpa_supplicant/events.c with 100% similarity]
libeap/wpa_supplicant/examples/60_wpa_supplicant [moved from wpa_supplicant/examples/60_wpa_supplicant with 100% similarity]
libeap/wpa_supplicant/examples/ieee8021x.conf [moved from wpa_supplicant/examples/ieee8021x.conf with 100% similarity]
libeap/wpa_supplicant/examples/openCryptoki.conf [moved from wpa_supplicant/examples/openCryptoki.conf with 100% similarity]
libeap/wpa_supplicant/examples/p2p-action-udhcp.sh [moved from wpa_supplicant/examples/p2p-action-udhcp.sh with 100% similarity]
libeap/wpa_supplicant/examples/p2p-action.sh [moved from wpa_supplicant/examples/p2p-action.sh with 100% similarity]
libeap/wpa_supplicant/examples/plaintext.conf [moved from wpa_supplicant/examples/plaintext.conf with 100% similarity]
libeap/wpa_supplicant/examples/udhcpd-p2p.conf [moved from wpa_supplicant/examples/udhcpd-p2p.conf with 100% similarity]
libeap/wpa_supplicant/examples/wep.conf [moved from wpa_supplicant/examples/wep.conf with 100% similarity]
libeap/wpa_supplicant/examples/wpa-psk-tkip.conf [moved from wpa_supplicant/examples/wpa-psk-tkip.conf with 100% similarity]
libeap/wpa_supplicant/examples/wpa2-eap-ccmp.conf [moved from wpa_supplicant/examples/wpa2-eap-ccmp.conf with 100% similarity]
libeap/wpa_supplicant/examples/wpas-dbus-new-getall.py [moved from wpa_supplicant/examples/wpas-dbus-new-getall.py with 100% similarity]
libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py [moved from wpa_supplicant/examples/wpas-dbus-new-signals.py with 100% similarity]
libeap/wpa_supplicant/examples/wpas-dbus-new-wps.py [moved from wpa_supplicant/examples/wpas-dbus-new-wps.py with 100% similarity]
libeap/wpa_supplicant/examples/wpas-dbus-new.py [moved from wpa_supplicant/examples/wpas-dbus-new.py with 100% similarity]
libeap/wpa_supplicant/examples/wpas-test.py [moved from wpa_supplicant/examples/wpas-test.py with 100% similarity]
libeap/wpa_supplicant/ibss_rsn.c [moved from wpa_supplicant/ibss_rsn.c with 100% similarity]
libeap/wpa_supplicant/ibss_rsn.h [moved from wpa_supplicant/ibss_rsn.h with 100% similarity]
libeap/wpa_supplicant/main.c [moved from wpa_supplicant/main.c with 100% similarity]
libeap/wpa_supplicant/main_none.c [moved from wpa_supplicant/main_none.c with 100% similarity]
libeap/wpa_supplicant/main_symbian.cpp [moved from wpa_supplicant/main_symbian.cpp with 100% similarity]
libeap/wpa_supplicant/main_winmain.c [moved from wpa_supplicant/main_winmain.c with 100% similarity]
libeap/wpa_supplicant/main_winsvc.c [moved from wpa_supplicant/main_winsvc.c with 100% similarity]
libeap/wpa_supplicant/mlme.c [moved from wpa_supplicant/mlme.c with 100% similarity]
libeap/wpa_supplicant/mlme.h [moved from wpa_supplicant/mlme.h with 100% similarity]
libeap/wpa_supplicant/nmake.mak [moved from wpa_supplicant/nmake.mak with 100% similarity]
libeap/wpa_supplicant/notify.c [moved from wpa_supplicant/notify.c with 100% similarity]
libeap/wpa_supplicant/notify.h [moved from wpa_supplicant/notify.h with 100% similarity]
libeap/wpa_supplicant/p2p_supplicant.c [moved from wpa_supplicant/p2p_supplicant.c with 100% similarity]
libeap/wpa_supplicant/p2p_supplicant.h [moved from wpa_supplicant/p2p_supplicant.h with 100% similarity]
libeap/wpa_supplicant/preauth_test.c [moved from wpa_supplicant/preauth_test.c with 100% similarity]
libeap/wpa_supplicant/scan.c [moved from wpa_supplicant/scan.c with 100% similarity]
libeap/wpa_supplicant/scan.h [moved from wpa_supplicant/scan.h with 100% similarity]
libeap/wpa_supplicant/sme.c [moved from wpa_supplicant/sme.c with 100% similarity]
libeap/wpa_supplicant/sme.h [moved from wpa_supplicant/sme.h with 100% similarity]
libeap/wpa_supplicant/symbian/README.symbian [moved from wpa_supplicant/symbian/README.symbian with 100% similarity]
libeap/wpa_supplicant/symbian/bld.inf [moved from wpa_supplicant/symbian/bld.inf with 100% similarity]
libeap/wpa_supplicant/symbian/wpa_supplicant.mmp [moved from wpa_supplicant/symbian/wpa_supplicant.mmp with 100% similarity]
libeap/wpa_supplicant/tests/link_test.c [moved from wpa_supplicant/tests/link_test.c with 100% similarity]
libeap/wpa_supplicant/tests/test_eap_sim_common.c [moved from wpa_supplicant/tests/test_eap_sim_common.c with 100% similarity]
libeap/wpa_supplicant/tests/test_wpa.c [moved from wpa_supplicant/tests/test_wpa.c with 100% similarity]
libeap/wpa_supplicant/todo.txt [moved from wpa_supplicant/todo.txt with 100% similarity]
libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj [moved from wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj with 100% similarity]
libeap/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj [moved from wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj with 100% similarity]
libeap/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj [moved from wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj with 100% similarity]
libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj [moved from wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj with 100% similarity]
libeap/wpa_supplicant/vs2005/wpa_supplicant.sln [moved from wpa_supplicant/vs2005/wpa_supplicant.sln with 100% similarity]
libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj [moved from wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj with 100% similarity]
libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj [moved from wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj with 100% similarity]
libeap/wpa_supplicant/win_example.reg [moved from wpa_supplicant/win_example.reg with 100% similarity]
libeap/wpa_supplicant/win_if_list.c [moved from wpa_supplicant/win_if_list.c with 100% similarity]
libeap/wpa_supplicant/wpa_cli.c [moved from wpa_supplicant/wpa_cli.c with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/.gitignore [moved from wpa_supplicant/wpa_gui-qt4/.gitignore with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp [moved from wpa_supplicant/wpa_gui-qt4/addinterface.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h [moved from wpa_supplicant/wpa_gui-qt4/addinterface.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp [moved from wpa_supplicant/wpa_gui-qt4/eventhistory.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h [moved from wpa_supplicant/wpa_gui-qt4/eventhistory.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.ui [moved from wpa_supplicant/wpa_gui-qt4/eventhistory.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons.qrc [moved from wpa_supplicant/wpa_gui-qt4/icons.qrc with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/Makefile [moved from wpa_supplicant/wpa_gui-qt4/icons/Makefile with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/README [moved from wpa_supplicant/wpa_gui-qt4/icons/README with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/ap.svg [moved from wpa_supplicant/wpa_gui-qt4/icons/ap.svg with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/group.svg [moved from wpa_supplicant/wpa_gui-qt4/icons/group.svg with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg [moved from wpa_supplicant/wpa_gui-qt4/icons/invitation.svg with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg [moved from wpa_supplicant/wpa_gui-qt4/icons/laptop.svg with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg [moved from wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/icons_png.qrc [moved from wpa_supplicant/wpa_gui-qt4/icons_png.qrc with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/lang/.gitignore [moved from wpa_supplicant/wpa_gui-qt4/lang/.gitignore with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts [moved from wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/main.cpp [moved from wpa_supplicant/wpa_gui-qt4/main.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp [moved from wpa_supplicant/wpa_gui-qt4/networkconfig.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h [moved from wpa_supplicant/wpa_gui-qt4/networkconfig.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.ui [moved from wpa_supplicant/wpa_gui-qt4/networkconfig.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp [moved from wpa_supplicant/wpa_gui-qt4/peers.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/peers.h [moved from wpa_supplicant/wpa_gui-qt4/peers.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/peers.ui [moved from wpa_supplicant/wpa_gui-qt4/peers.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp [moved from wpa_supplicant/wpa_gui-qt4/scanresults.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h [moved from wpa_supplicant/wpa_gui-qt4/scanresults.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/scanresults.ui [moved from wpa_supplicant/wpa_gui-qt4/scanresults.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp [moved from wpa_supplicant/wpa_gui-qt4/stringquery.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h [moved from wpa_supplicant/wpa_gui-qt4/stringquery.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp [moved from wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h [moved from wpa_supplicant/wpa_gui-qt4/userdatarequest.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui [moved from wpa_supplicant/wpa_gui-qt4/userdatarequest.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop [moved from wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro [moved from wpa_supplicant/wpa_gui-qt4/wpa_gui.pro with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp [moved from wpa_supplicant/wpa_gui-qt4/wpagui.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h [moved from wpa_supplicant/wpa_gui-qt4/wpagui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpagui.ui [moved from wpa_supplicant/wpa_gui-qt4/wpagui.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h [moved from wpa_supplicant/wpa_gui-qt4/wpamsg.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/.gitignore [moved from wpa_supplicant/wpa_gui/.gitignore with 100% similarity]
libeap/wpa_supplicant/wpa_gui/eventhistory.ui [moved from wpa_supplicant/wpa_gui/eventhistory.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui/eventhistory.ui.h [moved from wpa_supplicant/wpa_gui/eventhistory.ui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/main.cpp [moved from wpa_supplicant/wpa_gui/main.cpp with 100% similarity]
libeap/wpa_supplicant/wpa_gui/networkconfig.ui [moved from wpa_supplicant/wpa_gui/networkconfig.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui/networkconfig.ui.h [moved from wpa_supplicant/wpa_gui/networkconfig.ui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/scanresults.ui [moved from wpa_supplicant/wpa_gui/scanresults.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui/scanresults.ui.h [moved from wpa_supplicant/wpa_gui/scanresults.ui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling [moved from wpa_supplicant/wpa_gui/setup-mingw-cross-compiling with 100% similarity]
libeap/wpa_supplicant/wpa_gui/userdatarequest.ui [moved from wpa_supplicant/wpa_gui/userdatarequest.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui/userdatarequest.ui.h [moved from wpa_supplicant/wpa_gui/userdatarequest.ui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/wpa_gui.pro [moved from wpa_supplicant/wpa_gui/wpa_gui.pro with 100% similarity]
libeap/wpa_supplicant/wpa_gui/wpagui.ui [moved from wpa_supplicant/wpa_gui/wpagui.ui with 100% similarity]
libeap/wpa_supplicant/wpa_gui/wpagui.ui.h [moved from wpa_supplicant/wpa_gui/wpagui.ui.h with 100% similarity]
libeap/wpa_supplicant/wpa_gui/wpamsg.h [moved from wpa_supplicant/wpa_gui/wpamsg.h with 100% similarity]
libeap/wpa_supplicant/wpa_passphrase.c [moved from wpa_supplicant/wpa_passphrase.c with 100% similarity]
libeap/wpa_supplicant/wpa_priv.c [moved from wpa_supplicant/wpa_priv.c with 100% similarity]
libeap/wpa_supplicant/wpa_supplicant.c [moved from wpa_supplicant/wpa_supplicant.c with 100% similarity]
libeap/wpa_supplicant/wpa_supplicant.conf [moved from wpa_supplicant/wpa_supplicant.conf with 100% similarity]
libeap/wpa_supplicant/wpa_supplicant.nsi [moved from wpa_supplicant/wpa_supplicant.nsi with 100% similarity]
libeap/wpa_supplicant/wpa_supplicant_i.h [moved from wpa_supplicant/wpa_supplicant_i.h with 100% similarity]
libeap/wpa_supplicant/wpas_glue.c [moved from wpa_supplicant/wpas_glue.c with 100% similarity]
libeap/wpa_supplicant/wpas_glue.h [moved from wpa_supplicant/wpas_glue.h with 100% similarity]
libeap/wpa_supplicant/wps_supplicant.c [moved from wpa_supplicant/wps_supplicant.c with 100% similarity]
libeap/wpa_supplicant/wps_supplicant.h [moved from wpa_supplicant/wps_supplicant.h with 100% similarity]
libeap/wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj [moved from wpa_supplicant/xcode/wpa_supplicant.xcodeproj/project.pbxproj with 100% similarity]
libeap/www/Makefile [moved from www/Makefile with 100% similarity]
libeap/www/cvs.html [moved from www/cvs.html with 100% similarity]
libeap/www/hostapd/index.html [moved from www/hostapd/index.html with 100% similarity]
libeap/www/index.html [moved from www/index.html with 100% similarity]
libeap/www/links.html [moved from www/links.html with 100% similarity]
libeap/www/releases.html [moved from www/releases.html with 100% similarity]
libeap/www/versions.dot [moved from www/versions.dot with 100% similarity]
libeap/www/wpa_supplicant/conf/auth_modes.html [moved from www/wpa_supplicant/conf/auth_modes.html with 100% similarity]
libeap/www/wpa_supplicant/conf/configure.css [moved from www/wpa_supplicant/conf/configure.css with 100% similarity]
libeap/www/wpa_supplicant/conf/configure.html [moved from www/wpa_supplicant/conf/configure.html with 100% similarity]
libeap/www/wpa_supplicant/conf/configure.js [moved from www/wpa_supplicant/conf/configure.js with 100% similarity]
libeap/www/wpa_supplicant/conf/eap-peap.html [moved from www/wpa_supplicant/conf/eap-peap.html with 100% similarity]
libeap/www/wpa_supplicant/conf/eap-tls.html [moved from www/wpa_supplicant/conf/eap-tls.html with 100% similarity]
libeap/www/wpa_supplicant/conf/eap.html [moved from www/wpa_supplicant/conf/eap.html with 100% similarity]
libeap/www/wpa_supplicant/conf/index.html [moved from www/wpa_supplicant/conf/index.html with 100% similarity]
libeap/www/wpa_supplicant/events.png [moved from www/wpa_supplicant/events.png with 100% similarity]
libeap/www/wpa_supplicant/index.html [moved from www/wpa_supplicant/index.html with 100% similarity]
libeap/www/wpa_supplicant/main.png [moved from www/wpa_supplicant/main.png with 100% similarity]
libeap/www/wpa_supplicant/net_conf.png [moved from www/wpa_supplicant/net_conf.png with 100% similarity]
libeap/www/wpa_supplicant/scan.png [moved from www/wpa_supplicant/scan.png with 100% similarity]
libeap/www/wpa_supplicant/user_input.png [moved from www/wpa_supplicant/user_input.png with 100% similarity]
libeap/www/wpa_supplicant/wpa_gui.html [moved from www/wpa_supplicant/wpa_gui.html with 100% similarity]
mech_eap/.gitignore [new file with mode: 0644]
mech_eap/AUTHORS [new file with mode: 0644]
mech_eap/COPYING [new file with mode: 0644]
mech_eap/LICENSE [new file with mode: 0644]
mech_eap/Makefile.am [new file with mode: 0644]
mech_eap/NEWS [new file with mode: 0644]
mech_eap/NOTES [new file with mode: 0644]
mech_eap/README [new file with mode: 0644]
mech_eap/TODO [new file with mode: 0644]
mech_eap/accept_sec_context.c [new file with mode: 0644]
mech_eap/acquire_cred.c [new file with mode: 0644]
mech_eap/acquire_cred_with_password.c [new file with mode: 0644]
mech_eap/add_cred.c [new file with mode: 0644]
mech_eap/add_cred_with_password.c [new file with mode: 0644]
mech_eap/authdata_plugin.h [new file with mode: 0644]
mech_eap/authorize_localname.c [new file with mode: 0644]
mech_eap/canonicalize_name.c [new file with mode: 0644]
mech_eap/compare_name.c [new file with mode: 0644]
mech_eap/config.guess [new file with mode: 0755]
mech_eap/config.sub [new file with mode: 0755]
mech_eap/context_time.c [new file with mode: 0644]
mech_eap/delete_name_attribute.c [new file with mode: 0644]
mech_eap/delete_sec_context.c [new file with mode: 0644]
mech_eap/dictionary.ukerna [new file with mode: 0644]
mech_eap/display_name.c [new file with mode: 0644]
mech_eap/display_name_ext.c [new file with mode: 0644]
mech_eap/display_status.c [new file with mode: 0644]
mech_eap/duplicate_name.c [new file with mode: 0644]
mech_eap/eap_mech.c [new file with mode: 0644]
mech_eap/export_name.c [new file with mode: 0644]
mech_eap/export_name_composite.c [new file with mode: 0644]
mech_eap/export_sec_context.c [new file with mode: 0644]
mech_eap/get_mic.c [new file with mode: 0644]
mech_eap/get_name_attribute.c [new file with mode: 0644]
mech_eap/gssapiP_eap.h [new file with mode: 0644]
mech_eap/gssapi_eap.h [new file with mode: 0644]
mech_eap/gsseap_err.et [new file with mode: 0644]
mech_eap/import_name.c [new file with mode: 0644]
mech_eap/import_sec_context.c [new file with mode: 0644]
mech_eap/indicate_mechs.c [new file with mode: 0644]
mech_eap/init_sec_context.c [new file with mode: 0644]
mech_eap/inquire_attrs_for_mech.c [new file with mode: 0644]
mech_eap/inquire_context.c [new file with mode: 0644]
mech_eap/inquire_cred.c [new file with mode: 0644]
mech_eap/inquire_cred_by_oid.c [new file with mode: 0644]
mech_eap/inquire_mech_for_saslname.c [new file with mode: 0644]
mech_eap/inquire_mechs_for_name.c [new file with mode: 0644]
mech_eap/inquire_name.c [new file with mode: 0644]
mech_eap/inquire_names_for_mech.c [new file with mode: 0644]
mech_eap/inquire_saslname_for_mech.c [new file with mode: 0644]
mech_eap/inquire_sec_context_by_oid.c [new file with mode: 0644]
mech_eap/install-sh [new file with mode: 0755]
mech_eap/map_name_to_any.c [new file with mode: 0644]
mech_eap/mech [new file with mode: 0644]
mech_eap/mech_eap.exports [new file with mode: 0644]
mech_eap/mech_invoke.c [new file with mode: 0644]
mech_eap/process_context_token.c [new file with mode: 0644]
mech_eap/pseudo_random.c [new file with mode: 0644]
mech_eap/radius_ad.exports [new file with mode: 0644]
mech_eap/radsec.conf [new file with mode: 0644]
mech_eap/radsec_err.et [new file with mode: 0644]
mech_eap/release_any_name_mapping.c [new file with mode: 0644]
mech_eap/release_cred.c [new file with mode: 0644]
mech_eap/release_name.c [new file with mode: 0644]
mech_eap/release_oid.c [new file with mode: 0644]
mech_eap/set_cred_option.c [new file with mode: 0644]
mech_eap/set_name_attribute.c [new file with mode: 0644]
mech_eap/set_sec_context_option.c [new file with mode: 0644]
mech_eap/store_cred.c [new file with mode: 0644]
mech_eap/unwrap.c [new file with mode: 0644]
mech_eap/unwrap_iov.c [new file with mode: 0644]
mech_eap/util.h [new file with mode: 0644]
mech_eap/util_adshim.c [new file with mode: 0644]
mech_eap/util_attr.cpp [new file with mode: 0644]
mech_eap/util_attr.h [new file with mode: 0644]
mech_eap/util_base64.c [new file with mode: 0644]
mech_eap/util_base64.h [new file with mode: 0644]
mech_eap/util_buffer.c [new file with mode: 0644]
mech_eap/util_cksum.c [new file with mode: 0644]
mech_eap/util_context.c [new file with mode: 0644]
mech_eap/util_cred.c [new file with mode: 0644]
mech_eap/util_crypt.c [new file with mode: 0644]
mech_eap/util_json.cpp [new file with mode: 0644]
mech_eap/util_json.h [new file with mode: 0644]
mech_eap/util_krb.c [new file with mode: 0644]
mech_eap/util_lucid.c [new file with mode: 0644]
mech_eap/util_mech.c [new file with mode: 0644]
mech_eap/util_name.c [new file with mode: 0644]
mech_eap/util_oid.c [new file with mode: 0644]
mech_eap/util_ordering.c [new file with mode: 0644]
mech_eap/util_radius.cpp [new file with mode: 0644]
mech_eap/util_radius.h [new file with mode: 0644]
mech_eap/util_reauth.c [new file with mode: 0644]
mech_eap/util_reauth.h [new file with mode: 0644]
mech_eap/util_saml.cpp [new file with mode: 0644]
mech_eap/util_saml.h [new file with mode: 0644]
mech_eap/util_shib.cpp [new file with mode: 0644]
mech_eap/util_shib.h [new file with mode: 0644]
mech_eap/util_sm.c [new file with mode: 0644]
mech_eap/util_token.c [new file with mode: 0644]
mech_eap/verify_mic.c [new file with mode: 0644]
mech_eap/wrap.c [new file with mode: 0644]
mech_eap/wrap_iov.c [new file with mode: 0644]
mech_eap/wrap_iov_length.c [new file with mode: 0644]
mech_eap/wrap_size_limit.c [new file with mode: 0644]

index 4a1ad86..6ada720 100644 (file)
@@ -1,17 +1,8 @@
-*.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
index b735ec8..2fa303c 100644 (file)
@@ -1,126 +1,3 @@
 AUTOMAKE_OPTIONS = foreign
 
-AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils 
-
-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
-
-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
-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
-
-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
-
-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
-
-libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) $(TLS_SRCS)
-
-noinst_LTLIBRARIES = libeap.la
+SUBDIRS = libeap mech_eap
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644 (file)
index 0000000..eab00b4
--- /dev/null
@@ -0,0 +1,260 @@
+dnl Based on the one from the Boinc project by Reinhard
+
+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";
+     KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
+     KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`;
+     COMPILE_ET="$dir/bin/compile_et";
+     break;
+   fi
+done
+AC_MSG_RESULT($found_krb5)
+if test x_$found_krb5 != x_yes; then
+   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(gssapi_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(gssapi_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(gssapi_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/OpenSAML 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)
+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=])
+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
+AC_MSG_RESULT($found_shibresolver)
+if test x_$found_shibresolver != x_yes; then
+   AC_MSG_ERROR([
+----------------------------------------------------------------------
+  Cannot find Shibboleth resolver libraries.
+
+  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)
+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
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..13432d0
--- /dev/null
@@ -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/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..5ab930c
--- /dev/null
@@ -0,0 +1,57 @@
+AC_PREREQ([2.61])
+AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
+dnl AC_CONFIG_MACRO_DIR([m4])
+dnl AM_INIT_AUTOMAKE([silent-rules])
+AM_INIT_AUTOMAKE
+LT_PREREQ([2.2])
+LT_INIT([dlopen disable-static])
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_CONFIG_HEADERS([config.h])
+AC_GNU_SOURCE
+
+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")
+
+AC_SUBST(TARGET_CFLAGS)
+AC_SUBST(TARGET_LDFLAGS)
+AX_CHECK_KRB5
+dnl AX_CHECK_EAP
+AX_CHECK_SHIBSP
+AX_CHECK_SHIBRESOLVER
+AX_CHECK_RADSEC
+AX_CHECK_JANSSON
+AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile])
+AC_OUTPUT
diff --git a/libeap/.gitignore b/libeap/.gitignore
new file mode 100644 (file)
index 0000000..4a1ad86
--- /dev/null
@@ -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
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 (file)
index 0000000..b735ec8
--- /dev/null
@@ -0,0 +1,126 @@
+AUTOMAKE_OPTIONS = foreign
+
+AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils 
+
+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
+
+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
+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
+
+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
+
+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
+
+libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) $(TLS_SRCS)
+
+noinst_LTLIBRARIES = libeap.la
similarity index 100%
rename from README
rename to libeap/README
similarity index 100%
rename from build_nsis.sh
rename to libeap/build_nsis.sh
similarity index 100%
rename from build_release
rename to libeap/build_release
similarity index 100%
rename from doc/.gitignore
rename to libeap/doc/.gitignore
similarity index 100%
rename from doc/Makefile
rename to libeap/doc/Makefile
similarity index 100%
rename from doc/dbus.doxygen
rename to libeap/doc/dbus.doxygen
similarity index 100%
rename from doc/doxygen.conf
rename to libeap/doc/doxygen.conf
similarity index 100%
rename from doc/eap.doxygen
rename to libeap/doc/eap.doxygen
similarity index 100%
rename from doc/hostapd.fig
rename to libeap/doc/hostapd.fig
similarity index 100%
rename from eap_example/README
rename to libeap/eap_example/README
similarity index 100%
rename from eap_example/ca.pem
rename to libeap/eap_example/ca.pem
similarity index 100%
rename from hostapd/ChangeLog
rename to libeap/hostapd/ChangeLog
similarity index 100%
rename from hostapd/Makefile
rename to libeap/hostapd/Makefile
similarity index 100%
rename from hostapd/README
rename to libeap/hostapd/README
similarity index 100%
rename from hostapd/README-WPS
rename to libeap/hostapd/README-WPS
similarity index 100%
rename from hostapd/defconfig
rename to libeap/hostapd/defconfig
similarity index 100%
rename from hostapd/hostapd.8
rename to libeap/hostapd/hostapd.8
similarity index 100%
rename from hostapd/main.c
rename to libeap/hostapd/main.c
similarity index 100%
rename from hostapd/wired.conf
rename to libeap/hostapd/wired.conf
similarity index 100%
rename from src/Makefile
rename to libeap/src/Makefile
similarity index 100%
rename from src/wps/Makefile
rename to libeap/src/ap/Makefile
similarity index 100%
rename from src/ap/ap_config.c
rename to libeap/src/ap/ap_config.c
similarity index 100%
rename from src/ap/ap_config.h
rename to libeap/src/ap/ap_config.h
similarity index 100%
rename from src/ap/ap_list.c
rename to libeap/src/ap/ap_list.c
similarity index 100%
rename from src/ap/ap_list.h
rename to libeap/src/ap/ap_list.h
similarity index 100%
rename from src/ap/ap_mlme.c
rename to libeap/src/ap/ap_mlme.c
similarity index 100%
rename from src/ap/ap_mlme.h
rename to libeap/src/ap/ap_mlme.h
similarity index 100%
rename from src/ap/authsrv.c
rename to libeap/src/ap/authsrv.c
similarity index 100%
rename from src/ap/authsrv.h
rename to libeap/src/ap/authsrv.h
similarity index 100%
rename from src/ap/beacon.c
rename to libeap/src/ap/beacon.c
similarity index 100%
rename from src/ap/beacon.h
rename to libeap/src/ap/beacon.h
similarity index 100%
rename from src/ap/hostapd.c
rename to libeap/src/ap/hostapd.c
similarity index 100%
rename from src/ap/hostapd.h
rename to libeap/src/ap/hostapd.h
similarity index 100%
rename from src/ap/iapp.c
rename to libeap/src/ap/iapp.c
similarity index 100%
rename from src/ap/iapp.h
rename to libeap/src/ap/iapp.h
similarity index 100%
rename from src/ap/sta_info.c
rename to libeap/src/ap/sta_info.c
similarity index 100%
rename from src/ap/sta_info.h
rename to libeap/src/ap/sta_info.h
similarity index 100%
rename from src/ap/utils.c
rename to libeap/src/ap/utils.c
similarity index 100%
rename from src/ap/vlan_init.c
rename to libeap/src/ap/vlan_init.c
similarity index 100%
rename from src/ap/vlan_init.h
rename to libeap/src/ap/vlan_init.h
similarity index 100%
rename from src/ap/wmm.c
rename to libeap/src/ap/wmm.c
similarity index 100%
rename from src/ap/wmm.h
rename to libeap/src/ap/wmm.h
similarity index 100%
rename from src/ap/wpa_auth.c
rename to libeap/src/ap/wpa_auth.c
similarity index 100%
rename from src/ap/wpa_auth.h
rename to libeap/src/ap/wpa_auth.h
similarity index 100%
rename from src/common/defs.h
rename to libeap/src/common/defs.h
similarity index 100%
rename from src/crypto/aes.h
rename to libeap/src/crypto/aes.h
similarity index 100%
rename from src/crypto/aes_i.h
rename to libeap/src/crypto/aes_i.h
similarity index 100%
rename from src/crypto/des_i.h
rename to libeap/src/crypto/des_i.h
similarity index 100%
rename from src/crypto/md5.c
rename to libeap/src/crypto/md5.c
similarity index 100%
rename from src/crypto/md5.h
rename to libeap/src/crypto/md5.h
similarity index 100%
rename from src/crypto/md5_i.h
rename to libeap/src/crypto/md5_i.h
similarity index 100%
rename from src/crypto/rc4.c
rename to libeap/src/crypto/rc4.c
similarity index 100%
rename from src/crypto/sha1.c
rename to libeap/src/crypto/sha1.c
similarity index 100%
rename from src/crypto/sha1.h
rename to libeap/src/crypto/sha1.h
similarity index 100%
rename from src/crypto/tls.h
rename to libeap/src/crypto/tls.h
similarity index 100%
rename from src/eap_peer/eap.c
rename to libeap/src/eap_peer/eap.c
similarity index 100%
rename from src/eap_peer/eap.h
rename to libeap/src/eap_peer/eap.h
similarity index 100%
rename from src/lib.rules
rename to libeap/src/lib.rules
similarity index 100%
rename from src/p2p/Makefile
rename to libeap/src/p2p/Makefile
similarity index 100%
rename from src/p2p/p2p.c
rename to libeap/src/p2p/p2p.c
similarity index 100%
rename from src/p2p/p2p.h
rename to libeap/src/p2p/p2p.h
similarity index 100%
rename from src/p2p/p2p_i.h
rename to libeap/src/p2p/p2p_i.h
similarity index 100%
rename from src/p2p/p2p_pd.c
rename to libeap/src/p2p/p2p_pd.c
similarity index 100%
rename from src/p2p/p2p_sd.c
rename to libeap/src/p2p/p2p_sd.c
similarity index 100%
rename from src/rsn_supp/wpa.c
rename to libeap/src/rsn_supp/wpa.c
similarity index 100%
rename from src/rsn_supp/wpa.h
rename to libeap/src/rsn_supp/wpa.h
similarity index 100%
rename from src/tls/.gitignore
rename to libeap/src/tls/.gitignore
similarity index 100%
rename from src/tls/Makefile
rename to libeap/src/tls/Makefile
similarity index 100%
rename from src/tls/asn1.c
rename to libeap/src/tls/asn1.c
similarity index 100%
rename from src/tls/asn1.h
rename to libeap/src/tls/asn1.h
similarity index 100%
rename from src/tls/bignum.c
rename to libeap/src/tls/bignum.c
similarity index 100%
rename from src/tls/bignum.h
rename to libeap/src/tls/bignum.h
similarity index 100%
rename from src/tls/pkcs1.c
rename to libeap/src/tls/pkcs1.c
similarity index 100%
rename from src/tls/pkcs1.h
rename to libeap/src/tls/pkcs1.h
similarity index 100%
rename from src/tls/pkcs5.c
rename to libeap/src/tls/pkcs5.c
similarity index 100%
rename from src/tls/pkcs5.h
rename to libeap/src/tls/pkcs5.h
similarity index 100%
rename from src/tls/pkcs8.c
rename to libeap/src/tls/pkcs8.c
similarity index 100%
rename from src/tls/pkcs8.h
rename to libeap/src/tls/pkcs8.h
similarity index 100%
rename from src/tls/rsa.c
rename to libeap/src/tls/rsa.c
similarity index 100%
rename from src/tls/rsa.h
rename to libeap/src/tls/rsa.h
similarity index 100%
rename from src/tls/x509v3.c
rename to libeap/src/tls/x509v3.c
similarity index 100%
rename from src/tls/x509v3.h
rename to libeap/src/tls/x509v3.h
similarity index 100%
rename from src/utils/Makefile
rename to libeap/src/utils/Makefile
similarity index 100%
rename from src/utils/base64.c
rename to libeap/src/utils/base64.c
similarity index 100%
rename from src/utils/base64.h
rename to libeap/src/utils/base64.h
similarity index 100%
rename from src/utils/common.c
rename to libeap/src/utils/common.c
similarity index 100%
rename from src/utils/common.h
rename to libeap/src/utils/common.h
similarity index 100%
rename from src/utils/eloop.c
rename to libeap/src/utils/eloop.c
similarity index 100%
rename from src/utils/eloop.h
rename to libeap/src/utils/eloop.h
similarity index 100%
rename from src/utils/list.h
rename to libeap/src/utils/list.h
similarity index 100%
rename from src/utils/os.h
rename to libeap/src/utils/os.h
similarity index 100%
rename from src/utils/trace.c
rename to libeap/src/utils/trace.c
similarity index 100%
rename from src/utils/trace.h
rename to libeap/src/utils/trace.h
similarity index 100%
rename from src/utils/uuid.c
rename to libeap/src/utils/uuid.c
similarity index 100%
rename from src/utils/uuid.h
rename to libeap/src/utils/uuid.h
similarity index 100%
rename from src/utils/wpabuf.c
rename to libeap/src/utils/wpabuf.c
similarity index 100%
rename from src/utils/wpabuf.h
rename to libeap/src/utils/wpabuf.h
similarity index 100%
rename from src/ap/Makefile
rename to libeap/src/wps/Makefile
similarity index 100%
rename from src/wps/http.h
rename to libeap/src/wps/http.h
similarity index 100%
rename from src/wps/httpread.c
rename to libeap/src/wps/httpread.c
similarity index 100%
rename from src/wps/httpread.h
rename to libeap/src/wps/httpread.h
similarity index 100%
rename from src/wps/ndef.c
rename to libeap/src/wps/ndef.c
similarity index 100%
rename from src/wps/upnp_xml.c
rename to libeap/src/wps/upnp_xml.c
similarity index 100%
rename from src/wps/upnp_xml.h
rename to libeap/src/wps/upnp_xml.h
similarity index 100%
rename from src/wps/wps.c
rename to libeap/src/wps/wps.c
similarity index 100%
rename from src/wps/wps.h
rename to libeap/src/wps/wps.h
similarity index 100%
rename from src/wps/wps_defs.h
rename to libeap/src/wps/wps_defs.h
similarity index 100%
rename from src/wps/wps_er.c
rename to libeap/src/wps/wps_er.c
similarity index 100%
rename from src/wps/wps_er.h
rename to libeap/src/wps/wps_er.h
similarity index 100%
rename from src/wps/wps_i.h
rename to libeap/src/wps/wps_i.h
similarity index 100%
rename from src/wps/wps_nfc.c
rename to libeap/src/wps/wps_nfc.c
similarity index 100%
rename from src/wps/wps_ufd.c
rename to libeap/src/wps/wps_ufd.c
similarity index 100%
rename from src/wps/wps_upnp.c
rename to libeap/src/wps/wps_upnp.c
similarity index 100%
rename from src/wps/wps_upnp.h
rename to libeap/src/wps/wps_upnp.h
similarity index 100%
rename from tests/.gitignore
rename to libeap/tests/.gitignore
similarity index 100%
rename from tests/Makefile
rename to libeap/tests/Makefile
similarity index 100%
rename from tests/test-aes.c
rename to libeap/tests/test-aes.c
similarity index 100%
rename from tests/test-asn1.c
rename to libeap/tests/test-asn1.c
similarity index 100%
rename from tests/test-list.c
rename to libeap/tests/test-list.c
similarity index 100%
rename from tests/test-md4.c
rename to libeap/tests/test-md4.c
similarity index 100%
rename from tests/test-md5.c
rename to libeap/tests/test-md5.c
similarity index 100%
rename from tests/test-sha1.c
rename to libeap/tests/test-sha1.c
similarity index 100%
rename from tests/test-x509.c
rename to libeap/tests/test-x509.c
similarity index 100%
rename from www/Makefile
rename to libeap/www/Makefile
similarity index 100%
rename from www/cvs.html
rename to libeap/www/cvs.html
similarity index 100%
rename from www/index.html
rename to libeap/www/index.html
similarity index 100%
rename from www/links.html
rename to libeap/www/links.html
similarity index 100%
rename from www/releases.html
rename to libeap/www/releases.html
similarity index 100%
rename from www/versions.dot
rename to libeap/www/versions.dot
diff --git a/mech_eap/.gitignore b/mech_eap/.gitignore
new file mode 100644 (file)
index 0000000..06a3924
--- /dev/null
@@ -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 (file)
index 0000000..3007a4b
--- /dev/null
@@ -0,0 +1,6 @@
+The initial implementation of mech_eap was written by PADL Software
+under contract to JANET(UK).
+
+--
+Luke Howard <lukeh@padl.com>
+January, 2011
diff --git a/mech_eap/COPYING b/mech_eap/COPYING
new file mode 100644 (file)
index 0000000..7554e77
--- /dev/null
@@ -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 (file)
index 0000000..1b03a95
--- /dev/null
@@ -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 (file)
index 0000000..c8fba95
--- /dev/null
@@ -0,0 +1,131 @@
+AUTOMAKE_OPTIONS = foreign
+
+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 \
+       -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
+
+gssdir = $(libdir)/gss
+gss_LTLIBRARIES = mech_eap.la
+
+mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\"
+mech_eap_la_CFLAGS   = -Werror -Wall -Wunused-parameter \
+                       @KRB5_CFLAGS@  @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
+mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter \
+                       @KRB5_CFLAGS@  @RADSEC_CFLAGS@ \
+                       @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
+mech_eap_la_LDFLAGS  = -avoid-version -module \
+                       -export-symbols mech_eap.exports -no-undefined \
+                       @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
+mech_eap_la_LIBADD   = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \
+                      @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@
+
+mech_eap_la_SOURCES =                          \
+       accept_sec_context.c                    \
+       acquire_cred.c                          \
+       acquire_cred_with_password.c            \
+       add_cred.c                              \
+       add_cred_with_password.c                \
+       authorize_localname.c                   \
+       canonicalize_name.c                     \
+       compare_name.c                          \
+       context_time.c                          \
+       delete_name_attribute.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_name_composite.c                 \
+       export_sec_context.c                    \
+       get_mic.c                               \
+       get_name_attribute.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_oid.c                   \
+       inquire_mech_for_saslname.c             \
+       inquire_mechs_for_name.c                \
+       inquire_name.c                          \
+       inquire_names_for_mech.c                \
+       inquire_saslname_for_mech.c             \
+       inquire_sec_context_by_oid.c            \
+       map_name_to_any.c                       \
+       process_context_token.c                 \
+       pseudo_random.c                         \
+       radsec_err.c                            \
+       release_any_name_mapping.c              \
+       release_cred.c                          \
+       release_name.c                          \
+       release_oid.c                           \
+       set_name_attribute.c                    \
+       set_cred_option.c                       \
+       set_sec_context_option.c                \
+       store_cred.c                            \
+       unwrap.c                                \
+       unwrap_iov.c                            \
+       util_attr.cpp                           \
+       util_base64.c                           \
+       util_buffer.c                           \
+       util_context.c                          \
+       util_cksum.c                            \
+       util_cred.c                             \
+       util_crypt.c                            \
+       util_json.cpp                           \
+       util_krb.c                              \
+       util_lucid.c                            \
+       util_mech.c                             \
+       util_name.c                             \
+       util_oid.c                              \
+       util_ordering.c                         \
+       util_radius.cpp                         \
+       util_saml.cpp                           \
+       util_shib.cpp                           \
+       util_sm.c                               \
+       util_token.c                            \
+       verify_mic.c                            \
+       wrap.c                                  \
+       wrap_iov.c                              \
+       wrap_iov_length.c                       \
+       wrap_size_limit.c
+
+BUILT_SOURCES = gsseap_err.c radsec_err.c
+
+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
+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 (file)
index 0000000..e69de29
diff --git a/mech_eap/NOTES b/mech_eap/NOTES
new file mode 100644 (file)
index 0000000..849ce4e
--- /dev/null
@@ -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 (file)
index 0000000..3cb2d50
--- /dev/null
@@ -0,0 +1,147 @@
+Overview
+========
+
+This is an implementation of the GSS EAP mechanism, as described in
+draft-ietf-abfab-gss-eap-01.txt.
+
+Building
+========
+
+In order to build this, a recent Kerberos implementation (MIT or
+Heimdal), Shibboleth, and EAP libraries are required, along with
+all of their dependencies.
+
+Note: not all SPIs are supported by the Heimdal mechanism glue,
+so not all features will be available.
+
+Installing
+==========
+
+GSS mechglue
+------------
+
+When installing, be sure to edit $prefix/etc/gss/mech to register
+the EAP mechanisms. A sample configuration file is in this directory.
+You may need to specify an absolute path.
+
+RADIUS client library
+---------------------
+
+Make sure your RADIUS library is configured to talk to the server of
+your choice: see the example radsec.conf in this directory. If you
+want to use TCP or TLS, you'll need to run radsecproxy in front of
+your RADIUS server.
+
+RADIUS server
+-------------
+
+These instructions apply to FreeRADIUS only, which is downloadable
+from http://freeradius.org/. After configure, make, install, do the
+following:
+
+On the RADIUS server side, you need to install dictionary.ukerna to
+$prefix/etc/raddb and include it from the main dictionary file, by
+adding:
+
+    $INCLUDE dictionary.ukerna
+
+to $prefix/etc/raddb/dictionary. Make sure these files are world-
+readable; they weren't in my installation.
+
+Edit $prefix/etc/raddb/users to add your test user and password:
+
+    bob@PROJECT-MOONSHOT.ORG Cleartext-Password := secret
+
+Add an entry for your acceptor to $prefix/etc/raddb/clients.conf:
+
+    client somehost {
+        ipaddr = 127.0.0.1
+        secret = testing123
+        require_message_authenticator = yes
+    }
+
+Edit $prefix/etc/raddb/eap.conf and set:
+
+    eap {
+...
+        default_eap_type = ttls
+...
+        tls {
+            certdir = ...
+            cadir = ...
+            private_key_file = ...
+            certificate_file = ...
+        }
+        ttls {
+            default_eap_type = mschapv2
+            copy_request_to_tunnel = no
+            use_tunneled_reply = no
+            virtual_server = "inner-tunnel"
+        }
+...
+    }
+
+to enable EAP-TTLS.
+
+If you want the acceptor be able to identify the user, the RADIUS
+server needs to echo back the EAP username from the inner tunnel;
+for privacy, mech_eap only sends the realm in the EAP Identity
+response. To configure this with FreeRADIUS, add:
+
+    update outer.reply {
+        User-Name = "%{request:User-Name}"
+    }
+
+If you want to add a SAML assertion, do this with "update reply"
+in $prefix/etc/raddb/sites-available/default:
+
+    update reply {
+        SAML-AAA-Assertion = '<saml:Assertion ...'
+        SAML-AAA-Assertion += '...'
+    }
+
+You'll need to split it into multiple lines because of the RADIUS
+attribute size limit.
+
+Testing
+=======
+
+You can then test the MIT or Cyrus GSS and SASL example programs.
+Sample usage is given below. Substitute <user>, <pass> and <host>
+appropriately (<host> is the name of the host running the server,
+not the RADIUS server).
+
+% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" \
+  -user <user>@<realm> -pass <pass> <host> host@<host> \
+  "Testing GSS EAP"
+% gss-server -port 5555 -export host@<host>
+
+Note: for SASL you will be prompted for a username and password.
+
+% client -C -p 5556 -s host -m EAP-AES128 <host>
+% server -c -p 5556 -s host -h <host>
+
+To test fast reauthentication support, add the following to
+/etc/krb5.conf:
+
+[appdefaults]
+        eap_gss = {
+                reauth_use_ccache = TRUE
+        }
+
+This will store a Kerberos ticket for a GSS-EAP authenticated user
+in a credentials cache, which can then be used for re-authentication
+to the same acceptor. You must have a valid keytab configured.
+
+In this testing phase of Moonshot, it's also possible to store a
+default identity and credential in a file. The format consists of
+the string representation of the initiator identity and the password,
+separated by newlines. The default location of this file is
+.gss_eap_id in the user's home directory, however the GSSEAP_IDENTITY
+environment variable can be used to set an alternate location.
+
+You can also set a default realm in [appdefaults]; the Kerberos
+default realm is never used by mech_eap (or at least, that is the
+intention), so if unspecified you must always qualify names. It should
+generally not be necessary to specify this.
+
diff --git a/mech_eap/TODO b/mech_eap/TODO
new file mode 100644 (file)
index 0000000..d622364
--- /dev/null
@@ -0,0 +1,7 @@
+- integration with initiator-side EAP channel bindings
+- integration with final supplicant architecture
+- test Heimdal port
+
+- fix ABNF: no slash in the case where there is no host
+- specify anonymous behaviour: use empty name
+
diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c
new file mode 100644 (file)
index 0000000..cc8702d
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * 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;
+
+    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;
+    assert(krbPrinc != NULL);
+    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;
+
+    assert(actx->radContext == NULL);
+    assert(actx->radConn == NULL);
+
+    if (rs_context_create(&actx->radContext) != 0) {
+        *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
+        return GSS_S_FAILURE;
+    }
+
+    if (cred->radiusConfigFile != NULL)
+        configFile = cred->radiusConfigFile;
+    if (cred->radiusConfigStanza != NULL)
+        configStanza = cred->radiusConfigStanza;
+
+    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;
+    }
+
+    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) {
+        assert(major == GSS_S_CONTINUE_NEEDED);
+
+        rs_conn_destroy(ctx->acceptorCtx.radConn);
+        ctx->acceptorCtx.radConn = NULL;
+    }
+
+    return major;
+}
+
+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, tmpMinor;
+    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;
+    iov[1].buffer = *inputToken;
+
+    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+                                    iov, 2, TOK_TYPE_WRAP);
+    if (GSS_ERROR(major))
+        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;
+    }
+
+    gss_release_buffer(&tmpMinor, &iov[0].buffer);
+
+    return major;
+}
+
+#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
+eapGssSmAcceptCompleteInitiatorExts(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 GSSEAP_UNUSED)
+{
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
+
+    *minor = 0;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmAcceptCompleteAcceptorExts(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)
+{
+    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
+
+    *minor = 0;
+    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
+
+    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_CHANNEL_BINDINGS,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        SM_ITOK_FLAG_REQUIRED,
+        eapGssSmAcceptGssChannelBindings,
+    },
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        0,
+        eapGssSmAcceptCompleteInitiatorExts,
+    },
+#ifdef GSSEAP_ENABLE_REAUTH
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_REAUTH_CREDS,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
+        0,
+        eapGssSmAcceptReauthCreds,
+    },
+#endif
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
+        0,
+        eapGssSmAcceptCompleteAcceptorExts
+    },
+};
+
+OM_uint32
+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);
+
+    if (cred == GSS_C_NO_CREDENTIAL) {
+        if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
+            major = gssEapAcquireCred(minor,
+                                      GSS_C_NO_NAME,
+                                      GSS_C_NO_BUFFER,
+                                      GSS_C_INDEFINITE,
+                                      GSS_C_NO_OID_SET,
+                                      GSS_C_ACCEPT,
+                                      &ctx->defaultCred,
+                                      NULL,
+                                      NULL);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        }
+
+        cred = ctx->defaultCred;
+    }
+
+    GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+    if (cred->name != GSS_C_NO_NAME) {
+        major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+        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;
+        }
+    }
+
+    assert(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
+
+cleanup:
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+    if (GSS_ERROR(major))
+        gssEapReleaseContext(&tmpMinor, context_handle);
+
+    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 */
diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c
new file mode 100644 (file)
index 0000000..2326eaa
--- /dev/null
@@ -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
+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, GSS_C_NO_BUFFER,
+                             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 (file)
index 0000000..c0f4159
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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
+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)
+{
+    return gssEapAcquireCred(minor, desired_name, password,
+                             time_req, desired_mechs, cred_usage,
+                             output_cred_handle, actual_mechs, time_rec);
+}
diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c
new file mode 100644 (file)
index 0000000..37d0add
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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
+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,
+                              GSS_C_NO_BUFFER,
+                              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 (file)
index 0000000..7907138
--- /dev/null
@@ -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.
+ */
+
+/*
+ * Wrapper for acquiring a credential handle using a password.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+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;
+    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,
+                              password,
+                              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/authdata_plugin.h b/mech_eap/authdata_plugin.h
new file mode 100644 (file)
index 0000000..32bff2f
--- /dev/null
@@ -0,0 +1,331 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * krb5/authdata_plugin.h
+ *
+ * Copyright (C) 2007 Apple Inc.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * AuthorizationData plugin definitions for Kerberos 5.
+ */
+
+/*
+ * This is considered an INTERNAL interface at this time.
+ *
+ * Some work is needed before exporting it:
+ *
+ * + Documentation.
+ * + Sample code.
+ * + Test cases (preferably automated testing under "make check").
+ * + Hook into TGS exchange too; will change API.
+ * + Examine memory management issues, especially for Windows; may
+ *   change API.
+ *
+ * Other changes that would be nice to have, but not necessarily
+ * before making this interface public:
+ *
+ * + Library support for AD-IF-RELEVANT and similar wrappers.  (We can
+ *   make the plugin construct them if it wants them.)
+ * + KDC could combine/optimize wrapped AD elements provided by
+ *   multiple plugins, e.g., two IF-RELEVANT sequences could be
+ *   merged.  (The preauth plugin API also has this bug, we're going
+ *   to need a general fix.)
+ */
+
+#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#include <krb5/krb5.h>
+
+/*
+ * While arguments of these types are passed-in, for the most part a
+ * authorization data module can treat them as opaque.  If we need
+ * keying data, we can ask for it directly.
+ */
+struct _krb5_db_entry_new;
+
+/*
+ * The function table / structure which an authdata server module must export as
+ * "authdata_server_0".  NOTE: replace "0" with "1" for the type and
+ * variable names if this gets picked up by upstream.  If the interfaces work
+ * correctly, future versions of the table will add either more callbacks or
+ * more arguments to callbacks, and in both cases we'll be able to wrap the v0
+ * functions.
+ */
+/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
+typedef struct krb5plugin_authdata_server_ftable_v0 {
+    /* Not-usually-visible name. */
+    char *name;
+
+    /*
+     * Per-plugin initialization/cleanup.  The init function is called
+     * by the KDC when the plugin is loaded, and the fini function is
+     * called before the plugin is unloaded.  Both are optional.
+     */
+    krb5_error_code (*init_proc)(krb5_context, void **);
+    void (*fini_proc)(krb5_context, void *);
+    /*
+     * Actual authorization data handling function.  If this field
+     * holds a null pointer, this mechanism will be skipped, and the
+     * init/fini functions will not be run.
+     *
+     * This function should only modify the field
+     * enc_tkt_reply->authorization_data.  All other values should be
+     * considered inputs only.  And, it should *modify* the field, not
+     * overwrite it and assume that there are no other authdata
+     * plugins in use.
+     *
+     * Memory management: authorization_data is a malloc-allocated,
+     * null-terminated sequence of malloc-allocated pointers to
+     * authorization data structures.  This plugin code currently
+     * assumes the libraries, KDC, and plugin all use the same malloc
+     * pool, which may be a problem if/when we get the KDC code
+     * running on Windows.
+     *
+     * If this function returns a non-zero error code, a message
+     * is logged, but no other action is taken.  Other authdata
+     * plugins will be called, and a response will be sent to the
+     * client (barring other problems).
+     */
+    krb5_error_code (*authdata_proc)(krb5_context,
+                                     struct _krb5_db_entry_new *client,
+                                     krb5_data *req_pkt,
+                                     krb5_kdc_req *request,
+                                     krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_server_authdata_ftable_v0;
+
+typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0;
+
+typedef struct krb5plugin_authdata_server_ftable_v2 {
+    /* Not-usually-visible name. */
+    char *name;
+
+    /*
+     * Per-plugin initialization/cleanup.  The init function is called
+     * by the KDC when the plugin is loaded, and the fini function is
+     * called before the plugin is unloaded.  Both are optional.
+     */
+    krb5_error_code (*init_proc)(krb5_context, void **);
+    void (*fini_proc)(krb5_context, void *);
+    /*
+     * Actual authorization data handling function.  If this field
+     * holds a null pointer, this mechanism will be skipped, and the
+     * init/fini functions will not be run.
+     *
+     * This function should only modify the field
+     * enc_tkt_reply->authorization_data.  All other values should be
+     * considered inputs only.  And, it should *modify* the field, not
+     * overwrite it and assume that there are no other authdata
+     * plugins in use.
+     *
+     * Memory management: authorization_data is a malloc-allocated,
+     * null-terminated sequence of malloc-allocated pointers to
+     * authorization data structures.  This plugin code currently
+     * assumes the libraries, KDC, and plugin all use the same malloc
+     * pool, which may be a problem if/when we get the KDC code
+     * running on Windows.
+     *
+     * If this function returns a non-zero error code, a message
+     * is logged, but no other action is taken.  Other authdata
+     * plugins will be called, and a response will be sent to the
+     * client (barring other problems).
+     */
+    krb5_error_code (*authdata_proc)(krb5_context,
+                                     unsigned int flags,
+                                     struct _krb5_db_entry_new *client,
+                                     struct _krb5_db_entry_new *server,
+                                     struct _krb5_db_entry_new *tgs,
+                                     krb5_keyblock *client_key,
+                                     krb5_keyblock *server_key,
+                                     krb5_keyblock *tgs_key,
+                                     krb5_data *req_pkt,
+                                     krb5_kdc_req *request,
+                                     krb5_const_principal for_user_princ,
+                                     krb5_enc_tkt_part *enc_tkt_request,
+                                     krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_authdata_server_ftable_v2;
+
+typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2;
+
+typedef krb5_error_code
+(*authdata_client_plugin_init_proc)(krb5_context context,
+                                    void **plugin_context);
+
+#define AD_USAGE_AS_REQ         0x01
+#define AD_USAGE_TGS_REQ        0x02
+#define AD_USAGE_AP_REQ         0x04
+#define AD_USAGE_KDC_ISSUED     0x08
+#define AD_USAGE_MASK           0x0F
+#define AD_INFORMATIONAL        0x10
+
+struct _krb5_authdata_context;
+
+typedef void
+(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
+                                     void *plugin_context,
+                                     krb5_authdatatype ad_type,
+                                     krb5_flags *flags);
+
+typedef void
+(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
+                                    void *plugin_context);
+
+typedef krb5_error_code
+(*authdata_client_request_init_proc)(krb5_context kcontext,
+                                     struct _krb5_authdata_context *context,
+                                     void *plugin_context,
+                                     void **request_context);
+
+typedef void
+(*authdata_client_request_fini_proc)(krb5_context kcontext,
+                                     struct _krb5_authdata_context *context,
+                                     void *plugin_context,
+                                     void *request_context);
+
+typedef krb5_error_code
+(*authdata_client_import_authdata_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_authdata **authdata,
+                                        krb5_boolean kdc_issued_flag,
+                                        krb5_const_principal issuer);
+
+typedef krb5_error_code
+(*authdata_client_export_authdata_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_flags usage,
+                                        krb5_authdata ***authdata);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
+                                            struct _krb5_authdata_context *context,
+                                            void *plugin_context,
+                                            void *request_context,
+                                            krb5_data **attrs);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      const krb5_data *attribute,
+                                      krb5_boolean *authenticated,
+                                      krb5_boolean *complete,
+                                      krb5_data *value,
+                                      krb5_data *display_value,
+                                      int *more);
+
+typedef krb5_error_code
+(*authdata_client_set_attribute_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      krb5_boolean complete,
+                                      const krb5_data *attribute,
+                                      const krb5_data *value);
+
+typedef krb5_error_code
+(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
+                                         struct _krb5_authdata_context *context,
+                                         void *plugin_context,
+                                         void *request_context,
+                                         const krb5_data *attribute);
+
+typedef krb5_error_code
+(*authdata_client_export_internal_proc)(krb5_context kcontext,
+                                        struct _krb5_authdata_context *context,
+                                        void *plugin_context,
+                                        void *request_context,
+                                        krb5_boolean restrict_authenticated,
+                                        void **ptr);
+
+typedef void
+(*authdata_client_free_internal_proc)(krb5_context kcontext,
+                                      struct _krb5_authdata_context *context,
+                                      void *plugin_context,
+                                      void *request_context,
+                                      void *ptr);
+
+typedef krb5_error_code
+(*authdata_client_verify_proc)(krb5_context kcontext,
+                               struct _krb5_authdata_context *context,
+                               void *plugin_context,
+                               void *request_context,
+                               const krb5_auth_context *auth_context,
+                               const krb5_keyblock *key,
+                               const krb5_ap_req *req);
+
+typedef krb5_error_code
+(*authdata_client_size_proc)(krb5_context kcontext,
+                             struct _krb5_authdata_context *context,
+                             void *plugin_context,
+                             void *request_context,
+                             size_t *sizep);
+
+typedef krb5_error_code
+(*authdata_client_externalize_proc)(krb5_context kcontext,
+                                    struct _krb5_authdata_context *context,
+                                    void *plugin_context,
+                                    void *request_context,
+                                    krb5_octet **buffer,
+                                    size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_internalize_proc)(krb5_context kcontext,
+                                    struct _krb5_authdata_context *context,
+                                    void *plugin_context,
+                                    void *request_context,
+                                    krb5_octet **buffer,
+                                    size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_copy_proc)(krb5_context kcontext,
+                             struct _krb5_authdata_context *context,
+                             void *plugin_context,
+                             void *request_context,
+                             void *dst_plugin_context,
+                             void *dst_request_context);
+
+typedef struct krb5plugin_authdata_client_ftable_v0 {
+    char *name;
+    krb5_authdatatype *ad_type_list;
+    authdata_client_plugin_init_proc init;
+    authdata_client_plugin_fini_proc fini;
+    authdata_client_plugin_flags_proc flags;
+    authdata_client_request_init_proc request_init;
+    authdata_client_request_fini_proc request_fini;
+    authdata_client_get_attribute_types_proc get_attribute_types;
+    authdata_client_get_attribute_proc get_attribute;
+    authdata_client_set_attribute_proc set_attribute;
+    authdata_client_delete_attribute_proc delete_attribute;
+    authdata_client_export_authdata_proc export_authdata;
+    authdata_client_import_authdata_proc import_authdata;
+    authdata_client_export_internal_proc export_internal;
+    authdata_client_free_internal_proc free_internal;
+    authdata_client_verify_proc verify;
+    authdata_client_size_proc size;
+    authdata_client_externalize_proc externalize;
+    authdata_client_internalize_proc internalize;
+    authdata_client_copy_proc copy; /* optional */
+} krb5plugin_authdata_client_ftable_v0;
+
+#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
diff --git a/mech_eap/authorize_localname.c b/mech_eap/authorize_localname.c
new file mode 100644 (file)
index 0000000..ef5788e
--- /dev/null
@@ -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
+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 (file)
index 0000000..82d96b6
--- /dev/null
@@ -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
+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 (file)
index 0000000..1da4d98
--- /dev/null
@@ -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
+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 (executable)
index 0000000..dc84c68
--- /dev/null
@@ -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 <config-patches@gnu.org> 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 <config-patches@gnu.org>."
+
+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 <stdio.h>  /* 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 <sys/systemcfg.h>
+
+               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 <stdlib.h>
+              #include <unistd.h>
+
+              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 <unistd.h>
+       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' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # 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 <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#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 <sys/param.h>
+  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 <sys/param.h>
+#  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 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> 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 (executable)
index 0000000..2a55a50
--- /dev/null
@@ -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 <config-patches@gnu.org>.  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 <config-patches@gnu.org>."
+
+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 (file)
index 0000000..1486065
--- /dev/null
@@ -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
+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 (file)
index 0000000..88cade3
--- /dev/null
@@ -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
+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 (file)
index 0000000..7bd9cfb
--- /dev/null
@@ -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
+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, FALSE,
+                                   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 (file)
index 0000000..d62d829
--- /dev/null
@@ -0,0 +1,18 @@
+# -*- 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
+
+END-VENDOR UKERNA
diff --git a/mech_eap/display_name.c b/mech_eap/display_name.c
new file mode 100644 (file)
index 0000000..427dcf2
--- /dev/null
@@ -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
+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 (file)
index 0000000..dff525f
--- /dev/null
@@ -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
+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 (file)
index 0000000..b3cf2f9
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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"
+
+static GSSEAP_THREAD_ONCE gssEapStatusInfoKeyOnce = GSSEAP_ONCE_INITIALIZER;
+static GSSEAP_THREAD_KEY gssEapStatusInfoKey;
+
+struct gss_eap_status_info {
+    OM_uint32 code;
+    char *message;
+    struct gss_eap_status_info *next;
+};
+
+static void
+destroyStatusInfo(void *arg)
+{
+    struct gss_eap_status_info *p = arg, *next;
+
+    for (p = arg; p != NULL; p = next) {
+        next = p->next;
+        GSSEAP_FREE(p->message);
+        GSSEAP_FREE(p);
+    }
+}
+
+static void
+createStatusInfoKey(void)
+{
+    GSSEAP_KEY_CREATE(&gssEapStatusInfoKey, destroyStatusInfo);
+}
+
+/*
+ * 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;
+
+    GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
+
+    p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
+    for (; 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
+        GSSEAP_SETSPECIFIC(gssEapStatusInfoKey, p);
+}
+
+static const char *
+getStatusInfo(OM_uint32 minor)
+{
+    struct gss_eap_status_info *p;
+
+    GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
+
+    for (p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
+         p != NULL;
+         p = p->next) {
+        if (p->code == minor)
+            return p->message;
+    }
+
+    return NULL;
+}
+
+void
+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
+{
+    char *s = NULL;
+    int n;
+    va_list ap;
+
+    if (format != NULL) {
+        va_start(ap, format);
+        n = vasprintf(&s, format, ap);
+        va_end(ap);
+    }
+
+    saveStatusInfoNoCopy(minor, s);
+}
+
+OM_uint32
+gss_display_status(OM_uint32 *minor,
+                   OM_uint32 status_value,
+                   int status_type,
+                   gss_OID mech_type,
+                   OM_uint32 *message_context,
+                   gss_buffer_t status_string)
+{
+    OM_uint32 major;
+    krb5_context krbContext = NULL;
+    const char *errMsg;
+
+    status_string->length = 0;
+    status_string->value = NULL;
+
+    if (!gssEapIsMechanismOid(mech_type)) {
+        *minor = GSSEAP_WRONG_MECH;
+        return GSS_S_BAD_MECH;
+    }
+
+    if (status_type != GSS_C_MECH_CODE ||
+        *message_context != 0) {
+        /* we rely on the mechglue for GSS_C_GSS_CODE */
+        *minor = 0;
+        return GSS_S_BAD_STATUS;
+    }
+
+    errMsg = getStatusInfo(status_value);
+    if (errMsg == NULL) {
+        GSSEAP_KRB_INIT(&krbContext);
+
+        /* 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;
+}
diff --git a/mech_eap/duplicate_name.c b/mech_eap/duplicate_name.c
new file mode 100644 (file)
index 0000000..b618b3d
--- /dev/null
@@ -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
+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 (file)
index 0000000..fb827dd
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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;
+}
+
+static void gssEapInitiatorInit(void) __attribute__((constructor));
+static void gssEapFinalize(void) __attribute__((destructor));
+
+static void
+gssEapInitiatorInit(void)
+{
+    OM_uint32 major, minor;
+
+    initialize_eapg_error_table();
+    initialize_rse_error_table();
+
+    major = gssEapInitLibEap(&minor);
+    assert(major == GSS_S_COMPLETE);
+
+    major = gssEapInitLibRadsec(&minor);
+    assert(major == GSS_S_COMPLETE);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+    major = gssEapReauthInitialize(&minor);
+    assert(major == GSS_S_COMPLETE);
+#endif
+}
+
+static void
+gssEapFinalize(void)
+{
+    OM_uint32 minor;
+
+    gssEapAttrProvidersFinalize(&minor);
+    eap_peer_unregister_methods();
+}
diff --git a/mech_eap/export_name.c b/mech_eap/export_name.c
new file mode 100644 (file)
index 0000000..7a37e30
--- /dev/null
@@ -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
+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 (file)
index 0000000..7fb9840
--- /dev/null
@@ -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
+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 (file)
index 0000000..43f3f28
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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"
+
+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;
+    }
+
+    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;
+}
+
+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;
+    }
+
+    /*
+     * 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;
+    }
+
+    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);
+
+    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
+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 (file)
index 0000000..c19e68f
--- /dev/null
@@ -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
+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 (file)
index 0000000..8273368
--- /dev/null
@@ -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
+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 (file)
index 0000000..d1d6bce
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GSSAPIP_EAP_H_
+#define _GSSAPIP_EAP_H_ 1
+
+#include "config.h"
+
+#ifdef HAVE_HEIMDAL_VERSION
+#define KRB5_DEPRECATED         /* so we can use krb5_free_unparsed_name() */
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/param.h>
+
+/* GSS headers */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#ifdef HAVE_HEIMDAL_VERSION
+typedef struct gss_any *gss_any_t;
+#else
+#include <gssapi/gssapi_ext.h>
+#endif
+#include "gssapi_eap.h"
+
+/* Kerberos headers */
+#include <krb5.h>
+
+/* EAP headers */
+#include <common.h>
+#include <eap_peer/eap.h>
+#include <eap_peer/eap_config.h>
+#include <eap_peer/eap_methods.h>
+#include <eap_common/eap_common.h>
+#include <wpabuf.h>
+
+/* FreeRADIUS headers */
+#ifdef __cplusplus
+extern "C" {
+#define operator fr_operator
+#endif
+#include <freeradius/libradius.h>
+#include <freeradius/radius.h>
+#include <radsec/radsec.h>
+#include <radsec/request.h>
+#ifdef __cplusplus
+#undef operator
+}
+#endif
+
+#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 */
+    struct gss_eap_attr_ctx *attrCtx;
+};
+
+#define CRED_FLAG_INITIATE                  0x00010000
+#define CRED_FLAG_ACCEPT                    0x00020000
+#define CRED_FLAG_DEFAULT_IDENTITY          0x00040000
+#define CRED_FLAG_PASSWORD                  0x00080000
+#define CRED_FLAG_DEFAULT_CCACHE            0x00100000
+#define CRED_FLAG_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_buffer_desc password;
+    gss_OID_set mechanisms;
+    time_t expiryTime;
+    char *radiusConfigFile;
+    char *radiusConfigStanza;
+#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;
+};
+
+struct gss_eap_acceptor_ctx {
+    struct rs_context *radContext;
+    struct rs_connection *radConn;
+    char *radServer;
+    gss_buffer_desc state;
+    VALUE_PAIR *vps;
+};
+
+#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 defaultCred;
+    union {
+        struct gss_eap_initiator_ctx initiator;
+        #define initiatorCtx         ctxU.initiator
+        struct gss_eap_acceptor_ctx  acceptor;
+        #define acceptorCtx          ctxU.acceptor
+#ifdef GSSEAP_ENABLE_REAUTH
+        gss_ctx_id_t                 reauth;
+        #define reauthCtx            ctxU.reauth
+#endif
+    } ctxU;
+};
+
+#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
+
+/* 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, ...);
+
+#define IS_WIRE_ERROR(err)              ((err) > GSSEAP_RESERVED && \
+                                         (err) <= GSSEAP_RADIUS_PROT_FAILURE)
+
+/* export_sec_context.c */
+OM_uint32
+gssEapExportSecContext(OM_uint32 *minor,
+                       gss_ctx_id_t ctx,
+                       gss_buffer_t token);
+
+
+#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 (file)
index 0000000..9f713ec
--- /dev/null
@@ -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.
+ */
+
+#ifndef _GSSAPI_EAP_H_
+#define _GSSAPI_EAP_H_ 1
+
+#include <gssapi/gssapi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * GSS EAP mechanism OIDs.
+ */
+extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM;
+extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
+
+/*
+ * Mechanism name OID.
+ */
+extern gss_OID GSS_EAP_NT_EAP_NAME;
+
+/*
+ * The libradsec configuration file; defaults to radsec.conf
+ * in the system configuration directory if unspecified.
+ */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
+
+/*
+ * The stanza in the libradsec configuration file; defaults
+ * to "gss-eap" if unspecified.
+ */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA;
+
+/*
+ * Flags as a 32-bit integer in network byte order,
+ * followed by a boolean octet indicating whether to
+ * clear the specified flags (if absent, defaults to
+ * FALSE, ie. set flags).
+ */
+extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG;
+
+/*
+ * 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 (file)
index 0000000..6bcfff0
--- /dev/null
@@ -0,0 +1,149 @@
+#
+# 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"
+#
+# 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 (file)
index 0000000..87f0830
--- /dev/null
@@ -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
+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 (file)
index 0000000..d571bca
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * 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)
+
+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
+    assert(remain == 0);
+#endif
+
+    *pBuf = p;
+    *pRemain -= 4 + ctxLength;
+
+    return GSS_S_COMPLETE;
+}
+
+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;
+}
+
+static 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;
+
+    /*
+     * 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
+    assert(remain == 0);
+#endif
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+    return major;
+}
+
+OM_uint32
+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 (file)
index 0000000..ff88b4d
--- /dev/null
@@ -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
+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 (file)
index 0000000..930eb32
--- /dev/null
@@ -0,0 +1,1016 @@
+/*
+ * 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;
+
+    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;
+
+    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_cred_id_t cred,
+               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;
+
+    eapPeerConfig->identity = NULL;
+    eapPeerConfig->identity_len = 0;
+    eapPeerConfig->anonymous_identity = NULL;
+    eapPeerConfig->anonymous_identity_len = 0;
+    eapPeerConfig->password = NULL;
+    eapPeerConfig->password_len = 0;
+
+    assert(cred != GSS_C_NO_CREDENTIAL);
+
+    GSSEAP_KRB_INIT(&krbContext);
+
+    eapPeerConfig->fragment_size = 1024;
+#ifdef GSSEAP_DEBUG
+    wpa_debug_level = 0;
+#endif
+
+    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;
+
+    *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_cred_id_t cred,
+          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;
+
+    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;
+    }
+
+    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;
+
+    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) {
+        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;
+
+    assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
+    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,
+                         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;
+    int code;
+    struct wpabuf *resp = NULL;
+
+    *minor = 0;
+
+    assert(inputToken != GSS_C_NO_BUFFER);
+
+    major = peerConfigInit(minor, cred, ctx);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    assert(ctx->initiatorCtx.eap != NULL);
+    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;
+
+    code = 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;
+
+        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
+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;
+
+    assert(outputToken->value != NULL);
+
+    *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
+eapGssSmInitCompleteInitiatorExts(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)
+{
+    GSSEAP_SM_TRANSITION_NEXT(ctx);
+
+    *minor = 0;
+    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmInitCompleteAcceptorExts(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 GSSEAP_UNUSED)
+{
+    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_CHANNEL_BINDINGS,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        SM_ITOK_FLAG_REQUIRED,
+        eapGssSmInitGssChannelBindings
+    },
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        0,
+        eapGssSmInitCompleteInitiatorExts
+    },
+#ifdef GSSEAP_ENABLE_REAUTH
+    {
+        ITOK_TYPE_REAUTH_CREDS,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
+        0,
+        eapGssSmInitReauthCreds
+    },
+#endif
+    /* other extensions go here */
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
+        0,
+        eapGssSmInitCompleteAcceptorExts
+    }
+};
+
+OM_uint32
+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;
+    int initialContextToken = 0;
+
+    *minor = 0;
+
+    output_token->length = 0;
+    output_token->value = NULL;
+
+    if (ctx == GSS_C_NO_CONTEXT) {
+        if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+            *minor = GSSEAP_WRONG_SIZE;
+            return GSS_S_DEFECTIVE_TOKEN;
+        }
+
+        major = gssEapAllocContext(minor, &ctx);
+        if (GSS_ERROR(major))
+            return major;
+
+        ctx->flags |= CTX_FLAG_INITIATOR;
+        initialContextToken = 1;
+
+        *context_handle = ctx;
+    }
+
+    GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+    if (cred == GSS_C_NO_CREDENTIAL) {
+        if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
+            major = gssEapAcquireCred(minor,
+                                      GSS_C_NO_NAME,
+                                      GSS_C_NO_BUFFER,
+                                      time_req,
+                                      GSS_C_NO_OID_SET,
+                                      GSS_C_INITIATE,
+                                      &ctx->defaultCred,
+                                      NULL,
+                                      NULL);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        }
+
+        cred = ctx->defaultCred;
+    }
+
+    GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+    if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
+        major = GSS_S_NO_CRED;
+        *minor = GSSEAP_CRED_USAGE_MISMATCH;
+        goto cleanup;
+    }
+
+    if (initialContextToken) {
+        major = initBegin(minor, cred, 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);
+
+    assert(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
+
+cleanup:
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+    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 (file)
index 0000000..8c1bf12
--- /dev/null
@@ -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.
+ */
+
+/*
+ * 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)
+
+#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+typedef const gss_OID_desc *gss_const_OID;
+#endif
+
+OM_uint32
+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 (file)
index 0000000..0e7b586
--- /dev/null
@@ -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
+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 (file)
index 0000000..2e684b7
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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
+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;
+    time_t now, lifetime;
+
+    if (cred == NULL) {
+        *minor = EINVAL;
+        return GSS_S_NO_CRED;
+    }
+
+    GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+    if (name != NULL) {
+        major = gssEapDuplicateName(minor, cred->name, name);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    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:
+    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 (file)
index 0000000..b4a95f8
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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"
+
+static struct {
+    gss_OID_desc oid;
+    OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t,
+                         const gss_OID, gss_buffer_set_t *);
+} inquireCredOps[] = {
+};
+
+OM_uint32
+gss_inquire_cred_by_oid(OM_uint32 *minor,
+                        const gss_cred_id_t cred_handle,
+                        const gss_OID desired_object,
+                        gss_buffer_set_t *data_set)
+{
+    OM_uint32 major;
+    int i;
+
+    *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;
+
+    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;
+        }
+    }
+
+    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 (file)
index 0000000..c2f7914
--- /dev/null
@@ -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
+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 (file)
index 0000000..ca5d365
--- /dev/null
@@ -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
+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 (file)
index 0000000..2a4e0e3
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 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 (file)
index 0000000..e01740a
--- /dev/null
@@ -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
+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 (file)
index 0000000..aec2a85
--- /dev/null
@@ -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
+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 (file)
index 0000000..a69b9e9
--- /dev/null
@@ -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
+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 (executable)
index 0000000..6781b98
--- /dev/null
@@ -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 (file)
index 0000000..6f952e3
--- /dev/null
@@ -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
+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 (file)
index 0000000..258a43a
--- /dev/null
@@ -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.exports b/mech_eap/mech_eap.exports
new file mode 100644 (file)
index 0000000..1613713
--- /dev/null
@@ -0,0 +1,54 @@
+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_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_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
+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 (file)
index 0000000..2b7fb7e
--- /dev/null
@@ -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
+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 (file)
index 0000000..5bad3c0
--- /dev/null
@@ -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
+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 (file)
index 0000000..4bbf542
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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
+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)
+{
+    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;
+
+    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)) {
+        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+        *minor = GSSEAP_CONTEXT_INCOMPLETE;
+        return GSS_S_NO_CONTEXT;
+    }
+
+    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(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:
+    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+    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;
+}
diff --git a/mech_eap/radius_ad.exports b/mech_eap/radius_ad.exports
new file mode 100644 (file)
index 0000000..8d5d5c4
--- /dev/null
@@ -0,0 +1 @@
+authdata_client_0
diff --git a/mech_eap/radsec.conf b/mech_eap/radsec.conf
new file mode 100644 (file)
index 0000000..27f895a
--- /dev/null
@@ -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 (file)
index 0000000..3b7fae2
--- /dev/null
@@ -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 (file)
index 0000000..54d3162
--- /dev/null
@@ -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
+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 (file)
index 0000000..57ba829
--- /dev/null
@@ -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
+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 (file)
index 0000000..fb267a5
--- /dev/null
@@ -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
+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 (file)
index 0000000..4e0d4f0
--- /dev/null
@@ -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
+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 (file)
index 0000000..bfffa1f
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * 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;
+    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;
+    }
+
+    if (cred->radiusConfigFile != NULL)
+        GSSEAP_FREE(cred->radiusConfigFile);
+
+    cred->radiusConfigFile = (char *)configFileBuffer.value;
+
+    *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;
+    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;
+    }
+
+    if (cred->radiusConfigStanza != NULL)
+        GSSEAP_FREE(cred->radiusConfigStanza);
+
+    cred->radiusConfigStanza = (char *)configStanzaBuffer.value;
+
+    *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 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,
+    },
+};
+
+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;
+
+OM_uint32
+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 (file)
index 0000000..6dd9434
--- /dev/null
@@ -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
+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 (file)
index 0000000..1f373c2
--- /dev/null
@@ -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.
+ */
+
+/*
+ * Set an extended property on a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+static struct {
+    gss_OID_desc oid;
+    OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx,
+                           const gss_OID, const gss_buffer_t);
+} setCtxOps[] = {
+};
+
+OM_uint32
+gss_set_sec_context_option(OM_uint32 *minor,
+                           gss_ctx_id_t *pCtx,
+                           const gss_OID desired_object,
+                           const gss_buffer_t value)
+{
+    OM_uint32 major;
+    gss_ctx_id_t ctx = *pCtx;
+    int i;
+
+    major = GSS_S_UNAVAILABLE;
+    *minor = GSSEAP_BAD_CONTEXT_OPTION;
+
+    if (ctx != GSS_C_NO_CONTEXT)
+        GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+    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;
+        }
+    }
+
+    if (*pCtx == NULL)
+        *pCtx = ctx;
+    else
+        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 (file)
index 0000000..2847f42
--- /dev/null
@@ -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
+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 (file)
index 0000000..ae35bf9
--- /dev/null
@@ -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
+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 (file)
index 0000000..19bafc6
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * 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);
+    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, toktype2;
+    int i = 0, j;
+    gss_iov_buffer_desc *tiov = NULL;
+    gss_iov_buffer_t stream, data = NULL;
+    gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto = NULL;
+#endif
+
+    GSSEAP_KRB_INIT(&krbContext);
+
+    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);
+    assert(stream != NULL);
+
+    if (stream->buffer.length < 16) {
+        major = GSS_S_DEFECTIVE_TOKEN;
+        goto cleanup;
+    }
+
+    ptr = (unsigned char *)stream->buffer.value;
+    toktype2 = load_uint16_be(ptr);
+    ptr += 2;
+
+    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;
+
+    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;
+    }
+
+    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
+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 (file)
index 0000000..b3399be
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * 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
+
+#include <sys/param.h>
+#include <string.h>
+#include <errno.h>
+
+#include <krb5.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN
+#define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
+#endif
+
+#if !(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);
+
+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);
+
+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_FLAG_CRITICAL              0x80000000  /* critical, wire flag */
+#define ITOK_FLAG_VERIFIED              0x40000000  /* verified, API flag */
+
+#define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
+
+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);
+
+/* 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);
+
+OM_uint32
+gssEapAcquireCred(OM_uint32 *minor,
+                  const gss_name_t desiredName,
+                  const gss_buffer_t password,
+                  OM_uint32 timeReq,
+                  const gss_OID_set desiredMechs,
+                  int cred_usage,
+                  gss_cred_id_t *pCred,
+                  gss_OID_set *pActualMechs,
+                  OM_uint32 *timeRec);
+
+int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
+
+/* 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_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 */
+OM_uint32
+gssEapEncodeInnerTokens(OM_uint32 *minor,
+                        gss_buffer_set_t extensions,
+                        OM_uint32 *types,
+                        gss_buffer_t buffer);
+OM_uint32
+gssEapDecodeInnerTokens(OM_uint32 *minor,
+                        const gss_buffer_t buffer,
+                        gss_buffer_set_t *pExtensions,
+                        OM_uint32 **pTypes);
+
+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
+
+#define GSSEAP_NOT_IMPLEMENTED          do {            \
+        assert(0 && "not implemented");                 \
+        *minor = ENOSYS;                                \
+        return GSS_S_FAILURE;                           \
+    } while (0)
+
+#include <pthread.h>
+
+#define GSSEAP_MUTEX                    pthread_mutex_t
+#define GSSEAP_MUTEX_INITIALIZER        PTHREAD_MUTEX_INITIALIZER
+
+#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(o, i)               pthread_once((o), (i))
+#define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
+
+/* 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;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "util_json.h"
+#include "util_attr.h"
+#include "util_base64.h"
+#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 (file)
index 0000000..b74a29a
--- /dev/null
@@ -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;
+
+    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 (file)
index 0000000..01c3135
--- /dev/null
@@ -0,0 +1,1184 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Attribute provider mechanism.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <typeinfo>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <new>
+
+/* lazy initialisation */
+static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
+static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+
+static void
+gssEapAttrProvidersInitInternal(void)
+{
+    OM_uint32 major, minor;
+
+    assert(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
+
+    major = gssEapRadiusAttrProviderInit(&minor);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssEapSamlAttrProvidersInit(&minor);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    /* Allow Shibboleth initialization failure to be non-fatal */
+    gssEapLocalAttrProviderInit(&minor);
+
+cleanup:
+#ifdef GSSEAP_DEBUG
+    assert(major == GSS_S_COMPLETE);
+#endif
+
+    gssEapAttrProvidersInitStatus = major;
+}
+
+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)
+{
+    OM_uint32 major = GSS_S_COMPLETE;
+
+    if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
+        major = gssEapLocalAttrProviderFinalize(minor);
+        if (major == GSS_S_COMPLETE)
+            major = gssEapSamlAttrProvidersFinalize(minor);
+        if (major == GSS_S_COMPLETE)
+            major = gssEapRadiusAttrProviderFinalize(minor);
+
+        gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+    }
+
+    return major;
+}
+
+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)
+{
+    assert(type <= ATTR_TYPE_MAX);
+
+    assert(gssEapAttrFactories[type] == NULL);
+
+    gssEapAttrFactories[type] = factory;
+}
+
+/*
+ * Unregister a provider
+ */
+void
+gss_eap_attr_ctx::unregisterProvider(unsigned int type)
+{
+    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
+{
+    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:
+    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;
+
+    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);
+    }
+
+    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;
+
+    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);
+    }
+
+    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;
+
+    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 (file)
index 0000000..e3f3567
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Attribute provider interface.
+ */
+
+#ifndef _UTIL_ATTR_H_
+#define _UTIL_ATTR_H_ 1
+
+#ifdef __cplusplus
+#include <string>
+#include <new>
+
+using namespace gss_eap_util;
+
+struct gss_eap_attr_provider;
+struct gss_eap_attr_ctx;
+
+typedef bool
+(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_ctx *ctx,
+                               const gss_eap_attr_provider *source,
+                               const gss_buffer_t attribute,
+                               void *data);
+
+#define ATTR_TYPE_RADIUS            0U                  /* RADIUS AVPs */
+#define ATTR_TYPE_SAML_ASSERTION    1U                  /* SAML assertion */
+#define ATTR_TYPE_SAML              2U                  /* SAML attributes */
+#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 (file)
index 0000000..5d5241d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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;
+    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+       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;
+    }
+    return q - (unsigned char *) data;
+}
+
+int
+base64Valid(const char *str)
+{
+    const char *p;
+    int valid = 1;
+
+    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+       unsigned int val = token_decode(p);
+       if (val == DECODE_ERROR) {
+            valid = 0;
+           break;
+        }
+    }
+    return valid;
+}
diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h
new file mode 100644 (file)
index 0000000..d015efe
--- /dev/null
@@ -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 (file)
index 0000000..e135db9
--- /dev/null
@@ -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 (file)
index 0000000..ba76fd2
--- /dev/null
@@ -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);
+    assert(header != NULL);
+
+    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+    assert(rrc != 0 || trailer != NULL);
+
+    if (trailer == NULL) {
+        if (rrc != k5_checksumlen)
+            return KRB5_BAD_MSIZE;
+        if (header->buffer.length != 16 + k5_checksumlen)
+            return KRB5_BAD_MSIZE;
+    } else if (trailer->buffer.length != k5_checksumlen)
+        return KRB5_BAD_MSIZE;
+
+    kiov_count = 2 + iov_count;
+    kiov = (krb5_crypto_iov *)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 (file)
index 0000000..e9a9308
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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;
+
+    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 = errno;
+        gssEapReleaseContext(&tmpMinor, &ctx);
+        return GSS_S_FAILURE;
+    }
+
+    ctx->state = GSSEAP_STATE_INITIAL;
+
+    /*
+     * 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);
+}
+
+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);
+}
+
+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
+    if (CTX_IS_INITIATOR(ctx)) {
+        releaseInitiatorContext(&ctx->initiatorCtx);
+    } else {
+        releaseAcceptorContext(&ctx->acceptorCtx);
+    }
+
+    krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
+    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
+    gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
+    gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
+    sequenceFree(&tmpMinor, &ctx->seqState);
+    gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
+
+    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;
+
+    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;
+}
diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c
new file mode 100644 (file)
index 0000000..1d49e56
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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"
+
+#include <pwd.h>
+
+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 = errno;
+        gssEapReleaseCred(&tmpMinor, &cred);
+        return GSS_S_FAILURE;
+    }
+
+    *pCred = cred;
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+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);
+
+    if (cred->password.value != NULL) {
+        memset(cred->password.value, 0, cred->password.length);
+        GSSEAP_FREE(cred->password.value);
+    }
+
+    if (cred->radiusConfigFile != NULL)
+        GSSEAP_FREE(cred->radiusConfigFile);
+    if (cred->radiusConfigStanza != NULL)
+        GSSEAP_FREE(cred->radiusConfigStanza);
+
+#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
+readDefaultIdentityAndCreds(OM_uint32 *minor,
+                            gss_buffer_t defaultIdentity,
+                            gss_buffer_t defaultCreds)
+{
+    OM_uint32 major, tmpMinor;
+    FILE *fp = NULL;
+    char pwbuf[BUFSIZ], buf[BUFSIZ];
+    char *ccacheName;
+    struct passwd *pw = NULL, pwd;
+
+    defaultIdentity->length = 0;
+    defaultIdentity->value = NULL;
+
+    defaultCreds->length = 0;
+    defaultCreds->value = NULL;
+
+    ccacheName = getenv("GSSEAP_IDENTITY");
+    if (ccacheName == NULL) {
+        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
+            pw == NULL || pw->pw_dir == NULL) {
+            major = GSS_S_CRED_UNAVAIL;
+            *minor = errno;
+            goto cleanup;
+        }
+
+        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
+        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 (defaultIdentity->value == NULL)
+            dst = defaultIdentity;
+        else if (defaultCreds->value == NULL)
+            dst = defaultCreds;
+        else
+            break;
+
+        major = duplicateBuffer(minor, &src, dst);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    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);
+        gss_release_buffer(&tmpMinor, defaultCreds);
+    }
+
+    return major;
+}
+
+OM_uint32
+gssEapAcquireCred(OM_uint32 *minor,
+                  const gss_name_t desiredName,
+                  const gss_buffer_t password,
+                  OM_uint32 timeReq GSSEAP_UNUSED,
+                  const gss_OID_set desiredMechs,
+                  int credUsage,
+                  gss_cred_id_t *pCred,
+                  gss_OID_set *pActualMechs,
+                  OM_uint32 *timeRec)
+{
+    OM_uint32 major, tmpMinor;
+    gss_cred_id_t cred;
+    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
+    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
+    gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
+    gss_OID nameMech = GSS_C_NO_OID;
+
+    /* XXX TODO validate with changed set_cred_option API */
+    *pCred = GSS_C_NO_CREDENTIAL;
+
+    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 (cred->mechanisms != GSS_C_NO_OID_SET &&
+        cred->mechanisms->count == 1)
+        nameMech = &cred->mechanisms->elements[0];
+
+    if (cred->flags & CRED_FLAG_INITIATE) {
+        major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
+        if (major == GSS_S_COMPLETE) {
+            major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
+                                     nameMech, &defaultIdentityName);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        } else if (major != GSS_S_CRED_UNAVAIL)
+            goto cleanup;
+    }
+
+    if (desiredName != GSS_C_NO_NAME) {
+        GSSEAP_MUTEX_LOCK(&desiredName->mutex);
+
+        major = gssEapDuplicateName(minor, desiredName, &cred->name);
+        if (GSS_ERROR(major)) {
+            GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
+            goto cleanup;
+        }
+
+        GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
+
+        if (defaultIdentityName != GSS_C_NO_NAME) {
+            int nameEqual;
+
+            major = gssEapCompareName(minor, desiredName,
+                                      defaultIdentityName, &nameEqual);
+            if (GSS_ERROR(major))
+                goto cleanup;
+            else if (nameEqual)
+                cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
+        }
+    } else {
+        if (cred->flags & CRED_FLAG_ACCEPT) {
+            gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+            char serviceName[5 + MAXHOSTNAMELEN];
+
+            /* default host-based service is host@localhost */
+            memcpy(serviceName, "host@", 5);
+            if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
+                major = GSS_S_FAILURE;
+                *minor = GSSEAP_NO_HOSTNAME;
+                goto cleanup;
+            }
+
+            nameBuf.value = serviceName;
+            nameBuf.length = strlen((char *)nameBuf.value);
+
+            major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
+                                     nameMech, &cred->name);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        } else if (cred->flags & CRED_FLAG_INITIATE) {
+            if (defaultIdentityName == GSS_C_NO_NAME) {
+                major = GSS_S_CRED_UNAVAIL;
+                *minor = GSSEAP_NO_DEFAULT_IDENTITY;
+                goto cleanup;
+            }
+
+            cred->name = defaultIdentityName;
+            defaultIdentityName = GSS_C_NO_NAME;
+        }
+        cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
+    }
+
+    assert(cred->name != GSS_C_NO_NAME);
+
+    if (password != GSS_C_NO_BUFFER) {
+        major = duplicateBuffer(minor, password, &cred->password);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        cred->flags |= CRED_FLAG_PASSWORD;
+    } else if (defaultCreds.value != NULL &&
+        (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
+        cred->password = defaultCreds;
+
+        defaultCreds.length = 0;
+        defaultCreds.value = NULL;
+
+        cred->flags |= CRED_FLAG_PASSWORD;
+    } else if (cred->flags & CRED_FLAG_INITIATE) {
+        /*
+         * OK, here we need to ask the supplicant if we have creds or it
+         * will acquire them, so GS2 can know whether to prompt for a
+         * password or not.
+         */
+#if 0
+        && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
+#endif
+        major = GSS_S_CRED_UNAVAIL;
+        *minor = GSSEAP_NO_DEFAULT_CRED;
+        goto cleanup;
+    }
+
+    if (pActualMechs != NULL) {
+        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);
+    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
+    gss_release_buffer(&tmpMinor, &defaultIdentity);
+    if (defaultCreds.value != NULL) {
+        memset(defaultCreds.value, 0, defaultCreds.length);
+        gss_release_buffer(&tmpMinor, &defaultCreds);
+    }
+
+    return major;
+}
+
+/*
+ * 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;
+
+    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;
+}
diff --git a/mech_eap/util_crypt.c b/mech_eap/util_crypt.c
new file mode 100644 (file)
index 0000000..f230da2
--- /dev/null
@@ -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);
+    assert(header != NULL);
+
+    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+    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 = 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;
+
+    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;
+
+    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;
+
+    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)
+{
+    assert(iov != GSS_C_NO_IOV_BUFFER);
+    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 (file)
index 0000000..0133772
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * JSONObject utilities.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <typeinfo>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <new>
+
+#define JSON_INIT(obj) do {                                     \
+        if ((obj) == NULL)                                      \
+            throw std::bad_alloc();                             \
+        m_obj = (obj);                                          \
+    } while (0)
+
+#define JSON_CHECK_CONTAINER() do {                             \
+        if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
+            std::string s("JSONObject is not a container");     \
+            throw JSONException(m_obj);                         \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK_OBJECT() do {                                \
+        if (!json_is_object(m_obj)) {                           \
+            std::string s("JSONObject is not a dictionary");    \
+            throw JSONException(m_obj, JSON_OBJECT);            \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK_ARRAY() do {                                 \
+        if (!json_is_array(m_obj)) {                            \
+            throw JSONException(m_obj, JSON_ARRAY);             \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK(s) do {                                      \
+        if ((s) != 0)                                           \
+            throw JSONException();                              \
+    } while (0)
+
+JSONObject
+JSONObject::load(const char *input, size_t flags, json_error_t *error)
+{
+    json_t *obj;
+
+    obj = json_loads(input, flags, error);
+
+    return JSONObject(obj, false);
+}
+
+JSONObject
+JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
+{
+    json_t *obj;
+
+    obj = json_loadf(fp, flags, error);
+
+    return JSONObject(obj, false);
+}
+
+char *
+JSONObject::dump(size_t flags) const
+{
+    char *s = json_dumps(m_obj, flags);
+
+    if (s == NULL)
+        throw std::bad_alloc();
+
+    return s;
+}
+
+void
+JSONObject::dump(FILE *fp, size_t flags) const
+{
+    int r = json_dumpf(m_obj, fp, flags);
+
+    if (r != 0)
+        throw std::bad_alloc();
+}
+
+size_t
+JSONObject::size(void) const
+{
+    if (json_is_object(m_obj))
+        return json_object_size(m_obj);
+    else if (json_is_array(m_obj))
+        return json_array_size(m_obj);
+    else
+        return 0;
+}
+
+JSONObject::JSONObject(json_t *obj, bool retain)
+{
+    if (retain)
+        json_incref(obj);
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(const char *value)
+{
+    json_t *obj = json_string(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(json_int_t value)
+{
+    json_t *obj = json_integer(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(double value)
+{
+    json_t *obj = json_real(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(bool value)
+{
+    json_t *obj = value ? json_true() : json_false();
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(void)
+{
+    json_t *obj = json_object();
+
+    JSON_INIT(obj);
+}
+
+JSONObject
+JSONObject::object(void)
+{
+    return JSONObject();
+}
+
+JSONObject
+JSONObject::null(void)
+{
+    return JSONObject(json_null(), false);
+}
+
+JSONObject
+JSONObject::array(void)
+{
+    return JSONObject(json_array(), false);
+}
+
+void
+JSONObject::set(const char *key, JSONObject &value)
+{
+    JSON_CHECK_OBJECT();
+    JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
+}
+
+void
+JSONObject::set(const char *key, const char *value)
+{
+    JSONObject jobj(value);
+    set(key, jobj);
+}
+
+void
+JSONObject::set(const char *key, json_int_t value)
+{
+    JSONObject jobj(value);
+    set(key, jobj);
+}
+
+void
+JSONObject::del(const char *key)
+{
+    json_object_del(m_obj, key);
+}
+
+JSONObject
+JSONObject::get(const char *key) const
+{
+    json_t *obj;
+
+    obj = json_object_get(m_obj, key);
+    if (obj == NULL)
+        return JSONObject::null();
+
+    return JSONObject(obj, true);
+}
+
+JSONObject
+JSONObject::get(size_t index) const
+{
+    json_t *obj;
+
+    obj = json_array_get(m_obj, index);
+    if (obj == NULL)
+        return JSONObject::null();
+
+    return JSONObject(obj, true);
+}
+
+void
+JSONObject::update(JSONObject &value)
+{
+    JSON_CHECK_OBJECT();
+    json_t *other = value.get();
+    JSON_CHECK(json_object_update(m_obj, other));
+    json_decref(other);
+}
+
+JSONObject
+JSONObject::operator[](size_t index) const
+{
+    return get(index);
+}
+
+JSONObject
+JSONObject::operator[](const char *key) const
+{
+    return get(key);
+}
+
+void
+JSONObject::append(JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_append_new(m_obj, value.get()));
+}
+
+void
+JSONObject::insert(size_t index, JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
+}
+
+void
+JSONObject::remove(size_t index)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_remove(m_obj, index));
+}
+
+void
+JSONObject::clear(void)
+{
+    JSON_CHECK_CONTAINER();
+
+    if (json_is_object(m_obj)) {
+        JSON_CHECK(json_object_clear(m_obj));
+    } else if (json_is_array(m_obj)) {
+        JSON_CHECK(json_array_clear(m_obj));
+    }
+}
+
+void
+JSONObject::extend(JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    json_t *other = value.get();
+    JSON_CHECK(json_array_extend(m_obj, other));
+    json_decref(other);
+}
+
+const char *
+JSONObject::string(void) const
+{
+    return json_string_value(m_obj);
+}
+
+json_int_t
+JSONObject::integer(void) const
+{
+    return json_integer_value(m_obj);
+}
+
+double
+JSONObject::real(void) const
+{
+    return json_real_value(m_obj);
+}
+
+double
+JSONObject::number(void) const
+{
+    return json_number_value(m_obj);
+}
+
+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;
+}
+
+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 (file)
index 0000000..e2c5e29
--- /dev/null
@@ -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.
+ */
+
+/*
+ * JSON object wrapper with not-entirely-toll-free DDF bridging.
+ */
+
+#ifndef _UTIL_JSON_H_
+#define _UTIL_JSON_H_ 1
+
+#ifdef __cplusplus
+#include <string>
+#include <new>
+
+#include <jansson.h>
+#include <shibsp/remoting/ddf.h>
+
+using namespace shibsp;
+
+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);
+        static JSONObject ddf(DDF &value);
+
+        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;
+        DDF ddf(void) const;
+
+        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 (file)
index 0000000..88ad6dd
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Kerberos 5 helpers.
+ */
+
+#include "gssapiP_eap.h"
+
+static GSSEAP_THREAD_ONCE krbContextKeyOnce = GSSEAP_ONCE_INITIALIZER;
+static GSSEAP_THREAD_KEY krbContextKey;
+
+static void
+destroyKrbContext(void *arg)
+{
+    krb5_context context = (krb5_context)arg;
+
+    if (context != NULL)
+        krb5_free_context(context);
+}
+
+static void
+createKrbContextKey(void)
+{
+    GSSEAP_KEY_CREATE(&krbContextKey, destroyKrbContext);
+}
+
+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:
+    if (code != 0 && krbContext != NULL)
+        krb5_free_context(krbContext);
+
+    if (defaultRealm != NULL)
+        GSSEAP_FREE(defaultRealm);
+
+    return code;
+}
+
+OM_uint32
+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
+{
+    *minor = 0;
+
+    GSSEAP_ONCE(&krbContextKeyOnce, createKrbContextKey);
+
+    *context = GSSEAP_GETSPECIFIC(krbContextKey);
+    if (*context == NULL) {
+        *minor = initKrbContext(context);
+        if (*minor == 0) {
+            if (GSSEAP_SETSPECIFIC(krbContextKey, *context) != 0) {
+                *minor = errno;
+                krb5_free_context(*context);
+                *context = NULL;
+            }
+        }
+    }
+
+    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;
+
+    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 = 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;
+
+    GSSEAP_FREE(buf);
+    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)
+        GSSEAP_FREE(buf);
+    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 (file)
index 0000000..359058c
--- /dev/null
@@ -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 (file)
index 0000000..131ac0b
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * 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, tmpMinor;
+    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;
+
+        /* 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;
+
+        gss_release_oid(&tmpMinor, &mechOid);
+    }
+
+    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_name.c b/mech_eap/util_name.c
new file mode 100644 (file)
index 0000000..fbd4b8a
--- /dev/null
@@ -0,0 +1,782 @@
+/*
+ * 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 = errno;
+        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);
+
+    gssEapReleaseAttrContext(&tmpMinor, name);
+
+    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)
+        GSSEAP_FREE(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)
+            GSSEAP_FREE(defaultRealm);
+    }
+
+    if (nameBuffer != GSS_C_NO_BUFFER)
+        GSSEAP_FREE(nameString);
+
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
+    }
+
+    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;
+
+    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;
+    }
+
+    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) {
+        assert(gssEapIsConcreteMechanismOid(mechType));
+        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;
+    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
+        major = gssEapExportAttrContext(minor, name, &attrs);
+        if (GSS_ERROR(major))
+            goto cleanup;
+        exportedNameLen += attrs.length;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    if (input_name->attrCtx != NULL) {
+        major = gssEapDuplicateAttrContext(minor, input_name, name);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    *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 (file)
index 0000000..096c9f8
--- /dev/null
@@ -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 (file)
index 0000000..71ebfb5
--- /dev/null
@@ -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 (file)
index 0000000..5462acc
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * RADIUS attribute provider implementation.
+ */
+
+#include "gssapiP_eap.h"
+
+/* stuff that should be provided by libradsec/libfreeradius-radius */
+#define VENDORATTR(vendor, attr)            (((vendor) << 16) | (attr))
+
+#ifndef ATTRID
+#define ATTRID(attr)                        ((attr) & 0xFFFF)
+#endif
+
+static gss_buffer_desc radiusUrnPrefix = {
+    sizeof("urn:x-radius:") - 1,
+    (void *)"urn:x-radius:"
+};
+
+static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
+
+gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
+{
+    m_vps = NULL;
+    m_authenticated = false;
+}
+
+gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
+{
+    if (m_vps != NULL)
+        pairfree(&m_vps);
+}
+
+bool
+gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
+                                                      const gss_eap_attr_provider *ctx)
+{
+    const gss_eap_radius_attr_provider *radius;
+
+    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
+        return false;
+
+    radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
+
+    if (radius->m_vps != NULL)
+        m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
+
+    m_authenticated = radius->m_authenticated;
+
+    return true;
+}
+
+bool
+gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
+                                                 const gss_cred_id_t gssCred,
+                                                 const gss_ctx_id_t gssCtx)
+{
+    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
+        return false;
+
+    if (gssCtx != GSS_C_NO_CONTEXT) {
+        if (gssCtx->acceptorCtx.vps != NULL) {
+            m_vps = copyAvps(gssCtx->acceptorCtx.vps);
+            if (m_vps == NULL)
+                return false;
+
+            /* We assume libradsec validated this for us */
+            assert(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
+            m_authenticated = true;
+        }
+    }
+
+    return true;
+}
+
+static bool
+alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+{
+    for (std::vector<std::string>::const_iterator a = attrs.begin();
+         a != attrs.end();
+         ++a) {
+        if (strcmp(vp->name, (*a).c_str()) == 0)
+            return true;
+    }
+
+    return false;
+}
+
+static bool
+isSecretAttributeP(uint16_t attrid, uint16_t vendor)
+{
+    bool bSecretAttribute = false;
+
+    switch (vendor) {
+    case VENDORPEC_MS:
+        switch (attrid) {
+        case PW_MS_MPPE_SEND_KEY:
+        case PW_MS_MPPE_RECV_KEY:
+            bSecretAttribute = true;
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    return bSecretAttribute;
+}
+
+static bool
+isSecretAttributeP(uint32_t attribute)
+{
+    return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
+}
+
+static bool
+isInternalAttributeP(uint16_t attrid, uint16_t vendor)
+{
+    bool bInternalAttribute = false;
+
+    /* should have been filtered */
+    assert(!isSecretAttributeP(attrid, vendor));
+
+    switch (vendor) {
+    case VENDORPEC_UKERNA:
+        bInternalAttribute = true;
+        break;
+    default:
+        break;
+    }
+
+    return bInternalAttribute;
+}
+
+static bool
+isInternalAttributeP(uint32_t attribute)
+{
+    return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
+}
+
+/*
+ * Copy AVP list, same as paircopy except it filters out attributes
+ * containing keys.
+ */
+static VALUE_PAIR *
+copyAvps(const VALUE_PAIR *src)
+{
+    const VALUE_PAIR *vp;
+    VALUE_PAIR *dst = NULL, **pDst = &dst;
+
+    for (vp = src; vp != NULL; vp = vp->next) {
+        VALUE_PAIR *vpcopy;
+
+        if (isSecretAttributeP(vp->attribute))
+            continue;
+
+        vpcopy = paircopyvp(vp);
+        if (vpcopy == NULL) {
+            pairfree(&dst);
+            throw std::bad_alloc();
+        }
+        *pDst = vpcopy;
+        pDst = &vpcopy->next;
+     }
+
+    return dst;
+}
+
+bool
+gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+                                                void *data) const
+{
+    VALUE_PAIR *vp;
+    std::vector <std::string> seen;
+
+    for (vp = m_vps; vp != NULL; vp = vp->next) {
+        gss_buffer_desc attribute;
+        char attrid[64];
+
+        /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
+        if (isInternalAttributeP(vp->attribute))
+            continue;
+
+        if (alreadyAddedAttributeP(seen, vp))
+            continue;
+
+        snprintf(attrid, sizeof(attrid), "%s%d",
+            (char *)radiusUrnPrefix.value, vp->attribute);
+
+        attribute.value = attrid;
+        attribute.length = strlen(attrid);
+
+        if (!addAttribute(m_manager, this, &attribute, data))
+            return false;
+
+        seen.push_back(std::string(vp->name));
+    }
+
+    return true;
+}
+
+uint32_t
+getAttributeId(const gss_buffer_t attr)
+{
+    OM_uint32 tmpMinor;
+    gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
+    DICT_ATTR *da;
+    char *s;
+    uint32_t attrid = 0;
+
+    if (attr->length < radiusUrnPrefix.length ||
+        memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
+        return 0;
+
+    /* need to duplicate because attr may not be NUL terminated */
+    duplicateBuffer(*attr, &strAttr);
+    s = (char *)strAttr.value + radiusUrnPrefix.length;
+
+    if (isdigit(*s)) {
+        attrid = strtoul(s, NULL, 10);
+    } else {
+        da = dict_attrbyname(s);
+        if (da != NULL)
+            attrid = da->attr;
+    }
+
+    gss_release_buffer(&tmpMinor, &strAttr);
+
+    return attrid;
+}
+
+bool
+gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
+                                           uint32_t attrid,
+                                           const gss_buffer_t value)
+{
+    OM_uint32 major = GSS_S_UNAVAILABLE, minor;
+
+    if (!isSecretAttributeP(attrid) &&
+        !isInternalAttributeP(attrid)) {
+        deleteAttribute(attrid);
+
+        major = gssEapRadiusAddAvp(&minor, &m_vps,
+                                   ATTRID(attrid), VENDOR(attrid), 
+                                   value);
+    }
+
+    return !GSS_ERROR(major);
+}
+
+bool
+gss_eap_radius_attr_provider::setAttribute(int complete,
+                                           const gss_buffer_t attr,
+                                           const gss_buffer_t value)
+{
+    uint32_t attrid = getAttributeId(attr);
+
+    if (!attrid)
+        return false;
+
+    return setAttribute(complete, attrid, value);
+}
+
+bool
+gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
+{
+    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
+        pairfind(m_vps, attrid) == NULL)
+        return false;
+
+    pairdelete(&m_vps, attrid);
+
+    return true;
+}
+
+bool
+gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
+{
+    uint32_t attrid = getAttributeId(attr);
+
+    if (!attrid)
+        return false;
+
+    return deleteAttribute(attrid);
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
+                                           int *authenticated,
+                                           int *complete,
+                                           gss_buffer_t value,
+                                           gss_buffer_t display_value,
+                                           int *more) const
+{
+    uint32_t attrid;
+
+    attrid = getAttributeId(attr);
+    if (!attrid)
+        return false;
+
+    return getAttribute(attrid, authenticated, complete,
+                        value, display_value, more);
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
+                                           int *authenticated,
+                                           int *complete,
+                                           gss_buffer_t value,
+                                           gss_buffer_t display_value,
+                                           int *more) const
+{
+    VALUE_PAIR *vp;
+    int i = *more, count = 0;
+
+    *more = 0;
+
+    if (i == -1)
+        i = 0;
+
+    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) {
+        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::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)
+{
+    struct rs_context *radContext;
+
+    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext);
+
+#if 1
+    /*
+     * 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);
+
+    buffer->length = 0;
+    buffer->value = NULL;
+
+    vp = pairfind(vps, attr);
+    if (vp == NULL) {
+        *minor = GSSEAP_NO_SUCH_ATTR;
+        return GSS_S_UNAVAILABLE;
+    }
+
+    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;
+
+    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();
+
+    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;
+
+    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 (file)
index 0000000..ebd348b
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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 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);
+
+#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 IS_RADIUS_ERROR(code)               ((code) >= ERROR_TABLE_BASE_rse && \
+                                             (code) <= ERROR_TABLE_BASE_rse + RSE_TIMEOUT_IO)
+
+#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 (file)
index 0000000..a1d7251
--- /dev/null
@@ -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 <dlfcn.h>
+
+/*
+ * Fast reauthentication support for EAP GSS.
+ */
+
+krb5_error_code
+krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
+
+krb5_error_code
+encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
+
+static OM_uint32
+gssDisplayName(OM_uint32 *minor,
+               gss_name_t name,
+               gss_buffer_t buffer,
+               gss_OID *name_type);
+
+static OM_uint32
+gssImportName(OM_uint32 *minor,
+              gss_buffer_t buffer,
+              gss_OID name_type,
+              gss_name_t *name);
+
+static krb5_error_code
+getAcceptorKey(krb5_context krbContext,
+               gss_ctx_id_t ctx,
+               gss_cred_id_t cred,
+               krb5_principal *princ,
+               krb5_keyblock *key)
+{
+    krb5_error_code code;
+    krb5_keytab keytab = NULL;
+    krb5_keytab_entry ktent = { 0 };
+    krb5_kt_cursor cursor;
+
+    *princ = NULL;
+    memset(key, 0, sizeof(*key));
+    memset(&cursor, 0, sizeof(cursor));
+
+    code = krb5_kt_default(krbContext, &keytab);
+    if (code != 0)
+        goto cleanup;
+
+    if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+        code = krb5_kt_get_entry(krbContext, keytab,
+                                 cred->name->krbPrincipal, 0,
+                                 ctx->encryptionType, &ktent);
+        if (code != 0)
+            goto cleanup;
+    } else {
+        /*
+         * It's not clear that looking encrypting the ticket in the
+         * requested EAP enctype provides any value.
+         */
+        code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
+        if (code != 0)
+            goto cleanup;
+
+        while ((code = krb5_kt_next_entry(krbContext, keytab,
+                                          &ktent, &cursor)) == 0) {
+            if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType)
+                break;
+            else
+                KRB_KT_ENT_FREE(krbContext, &ktent);
+        }
+    }
+
+    if (code == 0) {
+        *princ = ktent.principal;
+        *key = *KRB_KT_ENT_KEYBLOCK(&ktent);
+    }
+
+cleanup:
+    if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
+        krb5_kt_end_seq_get(krbContext, keytab, &cursor);
+    krb5_kt_close(krbContext, keytab);
+    if (code != 0)
+        KRB_KT_ENT_FREE(krbContext, &ktent);
+
+    return code;
+}
+
+static OM_uint32
+freezeAttrContext(OM_uint32 *minor,
+                  gss_name_t initiatorName,
+                  krb5_const_principal acceptorPrinc,
+                  krb5_keyblock *session,
+#ifdef HAVE_HEIMDAL_VERSION
+                  krb5_authdata *kdcIssuedAuthData
+#else
+                  krb5_authdata ***kdcIssuedAuthData
+#endif
+                  )
+{
+    OM_uint32 major, tmpMinor;
+    krb5_error_code code;
+    krb5_context krbContext;
+    gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_authdata authDataBuf, *authData = &authDataBuf;
+    AuthorizationDataElement authDatum = { 0 };
+#else
+    krb5_authdata *authData[2], authDatum = { 0 };
+#endif
+
+    memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData));
+
+    GSSEAP_KRB_INIT(&krbContext);
+
+    major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
+    if (GSS_ERROR(major))
+        return major;
+
+    authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
+#ifdef HAVE_HEIMDAL_VERSION
+    authDatum.ad_data.length = attrBuf.length;
+    authDatum.ad_data.data = attrBuf.value;
+    authData->len = 1;
+    authData->val = &authDatum;
+#else
+    authDatum.length = attrBuf.length;
+    authDatum.contents = attrBuf.value;
+    authData[0] = &authDatum;
+    authData[1] = NULL;
+#endif
+
+    code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc,
+                                    authData, kdcIssuedAuthData);
+    if (code != 0) {
+        major = GSS_S_FAILURE;
+        *minor = code;
+    } else {
+        major = GSS_S_COMPLETE;
+    }
+
+    gss_release_buffer(&tmpMinor, &attrBuf);
+
+    return major;
+}
+
+/*
+ * Fabricate a ticket to ourselves given a GSS EAP context.
+ */
+OM_uint32
+gssEapMakeReauthCreds(OM_uint32 *minor,
+                      gss_ctx_id_t ctx,
+                      gss_cred_id_t cred,
+                      gss_buffer_t credBuf)
+{
+    OM_uint32 major = GSS_S_COMPLETE;
+    krb5_error_code code;
+    krb5_context krbContext = NULL;
+    krb5_keyblock session = { 0 }, acceptorKey = { 0 };
+    krb5_principal server = NULL;
+#ifdef HAVE_HEIMDAL_VERSION
+    Ticket ticket;
+    EncTicketPart enc_part;
+    AuthorizationData authData = { 0 };
+    krb5_crypto krbCrypto = NULL;
+    krb5_data ticketData = { 0 };
+    krb5_data encPartData = { 0 };
+    size_t len;
+#else
+    krb5_ticket ticket;
+    krb5_enc_tkt_part enc_part;
+    krb5_data *ticketData = NULL;
+#endif
+    krb5_data credsData = { 0 };
+    krb5_creds creds = { 0 };
+    krb5_auth_context authContext = NULL;
+
+    memset(&ticket, 0, sizeof(ticket));
+    memset(&enc_part, 0, sizeof(enc_part));
+
+    credBuf->length = 0;
+    credBuf->value = NULL;
+
+    GSSEAP_KRB_INIT(&krbContext);
+
+    code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_UNAVAILABLE;
+    }
+
+    /*
+     * Generate a random session key to place in the ticket and
+     * sign the "KDC-Issued" authorization data element.
+     */
+#ifdef HAVE_HEIMDAL_VERSION
+    ticket.realm = server->realm;
+    ticket.sname = server->name;
+
+    code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType,
+                                         &session);
+    if (code != 0)
+        goto cleanup;
+
+    enc_part.flags.initial = 1;
+    enc_part.key = session;
+    enc_part.crealm = ctx->initiatorName->krbPrincipal->realm;
+    enc_part.cname = ctx->initiatorName->krbPrincipal->name;
+    enc_part.authtime = time(NULL);
+    enc_part.starttime = &enc_part.authtime;
+    enc_part.endtime = (ctx->expiryTime != 0)
+                       ? ctx->expiryTime : KRB_TIME_FOREVER;
+    enc_part.renew_till = NULL;
+    enc_part.authorization_data = &authData;
+
+    major = freezeAttrContext(minor, ctx->initiatorName, server,
+                              &session, &authData);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length,
+                       &enc_part, &len, code);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_encrypt_EncryptedData(krbContext,
+                                      krbCrypto,
+                                      KRB5_KU_TICKET,
+                                      encPartData.data,
+                                      encPartData.length,
+                                      0,
+                                      &ticket.enc_part);
+    if (code != 0)
+        goto cleanup;
+
+    ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length,
+                       &ticket, &len, code);
+    if (code != 0)
+        goto cleanup;
+#else
+    ticket.server = server;
+
+    code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
+                                  &session);
+    if (code != 0)
+        goto cleanup;
+
+    enc_part.flags = TKT_FLG_INITIAL;
+    enc_part.session = &session;
+    enc_part.client = ctx->initiatorName->krbPrincipal;
+    enc_part.times.authtime = time(NULL);
+    enc_part.times.starttime = enc_part.times.authtime;
+    enc_part.times.endtime = (ctx->expiryTime != 0)
+                             ? ctx->expiryTime
+                             : KRB_TIME_FOREVER;
+    enc_part.times.renew_till = 0;
+
+    major = freezeAttrContext(minor, ctx->initiatorName, server,
+                              &session, &enc_part.authorization_data);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    ticket.enc_part2 = &enc_part;
+
+    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
+    if (code != 0)
+        goto cleanup;
+
+    code = encode_krb5_ticket(&ticket, &ticketData);
+    if (code != 0)
+        goto cleanup;
+#endif /* HAVE_HEIMDAL_VERSION */
+
+    creds.client = ctx->initiatorName->krbPrincipal;
+    creds.server = server;
+#ifdef HAVE_HEIMDAL_VERSION
+    creds.session = session;
+    creds.times.authtime = enc_part.authtime;
+    creds.times.starttime = *enc_part.starttime;
+    creds.times.endtime = enc_part.endtime;
+    creds.times.renew_till = 0;
+    creds.flags.b = enc_part.flags;
+    creds.ticket = ticketData;
+    creds.authdata = authData;
+#else
+    creds.keyblock = session;
+    creds.times = enc_part.times;
+    creds.ticket_flags = enc_part.flags;
+    creds.ticket = *ticketData;
+    creds.authdata = enc_part.authorization_data;
+#endif
+
+    code = krb5_auth_con_init(krbContext, &authContext);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_auth_con_setflags(krbContext, authContext, 0);
+    if (code != 0)
+        goto cleanup;
+
+    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);
+
+    assert(cred != GSS_C_NO_CREDENTIAL);
+    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;
+
+    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 (file)
index 0000000..9b9f264
--- /dev/null
@@ -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 (file)
index 0000000..494aeb9
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * SAML attribute provider implementation.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <sstream>
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/unicode.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/DateTime.h>
+
+#include <saml/exceptions.h>
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
+
+using namespace xmltooling;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xercesc;
+using namespace std;
+
+static const XMLCh
+base64Binary[] = {'b','a','s','e','6','4','B','i','n','a','r','y',0};
+
+/*
+ * gss_eap_saml_assertion_provider is for retrieving the underlying
+ * assertion.
+ */
+gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
+{
+    m_assertion = NULL;
+    m_authenticated = false;
+}
+
+gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
+{
+    delete m_assertion;
+}
+
+bool
+gss_eap_saml_assertion_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
+                                                         const gss_eap_attr_provider *ctx)
+{
+    /* Then we may be creating from an existing attribute context */
+    const gss_eap_saml_assertion_provider *saml;
+
+    assert(m_assertion == NULL);
+
+    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
+        return false;
+
+    saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
+    setAssertion(saml->getAssertion(), saml->authenticated());
+
+    return true;
+}
+
+bool
+gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
+                                                    const gss_cred_id_t gssCred,
+                                                    const gss_ctx_id_t gssCtx)
+{
+    const gss_eap_radius_attr_provider *radius;
+    gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+    int authenticated, complete;
+    OM_uint32 minor;
+
+    assert(m_assertion == NULL);
+
+    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
+        return false;
+
+    /*
+     * XXX TODO we need to support draft-howlett-radius-saml-attr-00
+     */
+    radius = static_cast<const gss_eap_radius_attr_provider *>
+        (m_manager->getProvider(ATTR_TYPE_RADIUS));
+    if (radius != NULL &&
+        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
+                                       VENDORPEC_UKERNA,
+                                       &authenticated, &complete, &value)) {
+        setAssertion(&value, authenticated);
+        gss_release_buffer(&minor, &value);
+    } else {
+        m_assertion = NULL;
+    }
+
+    return true;
+}
+
+void
+gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
+                                              bool authenticated)
+{
+
+    delete m_assertion;
+
+    if (assertion != NULL) {
+#ifdef __APPLE__
+        m_assertion = (saml2::Assertion *)((void *)assertion->clone());
+#else
+        m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
+#endif
+        m_authenticated = authenticated;
+    } else {
+        m_assertion = NULL;
+        m_authenticated = false;
+    }
+}
+
+void
+gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
+                                              bool authenticated)
+{
+    delete m_assertion;
+
+    m_assertion = parseAssertion(buffer);
+    m_authenticated = (m_assertion != NULL && authenticated);
+}
+
+saml2::Assertion *
+gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
+{
+    string str((char *)buffer->value, buffer->length);
+    istringstream istream(str);
+    DOMDocument *doc;
+    const XMLObjectBuilder *b;
+
+    try {
+        doc = XMLToolingConfig::getConfig().getParser().parse(istream);
+        if (doc == NULL)
+            return NULL;
+
+        b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
+
+#ifdef __APPLE__
+        return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
+#else
+        return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
+#endif
+    } catch (exception &e) {
+        return NULL;
+    }
+}
+
+bool
+gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+                                                   void *data) const
+{
+    bool ret;
+
+    /* just add the prefix */
+    if (m_assertion != NULL)
+        ret = addAttribute(m_manager, this, GSS_C_NO_BUFFER, data);
+    else
+        ret = true;
+
+    return ret;
+}
+
+bool
+gss_eap_saml_assertion_provider::setAttribute(int complete GSSEAP_UNUSED,
+                                              const gss_buffer_t attr,
+                                              const gss_buffer_t value)
+{
+    if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
+        setAssertion(value);
+        return true;
+    }
+
+    return false;
+}
+
+bool
+gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
+{
+    delete m_assertion;
+    m_assertion = NULL;
+    m_authenticated = false;
+
+    return true;
+}
+
+time_t
+gss_eap_saml_assertion_provider::getExpiryTime(void) const
+{
+    saml2::Conditions *conditions;
+    time_t expiryTime = 0;
+
+    if (m_assertion == NULL)
+        return 0;
+
+    conditions = m_assertion->getConditions();
+
+    if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
+        expiryTime = conditions->getNotOnOrAfter()->getEpoch();
+
+    return expiryTime;
+}
+
+OM_uint32
+gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor,
+                                              std::exception &e) const
+{
+    if (typeid(e) == typeid(SecurityPolicyException))
+        *minor = GSSEAP_SAML_SEC_POLICY_FAILURE;
+    else if (typeid(e) == typeid(BindingException))
+        *minor = GSSEAP_SAML_BINDING_FAILURE;
+    else if (typeid(e) == typeid(ProfileException))
+        *minor = GSSEAP_SAML_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(FatalProfileException))
+        *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(RetryableProfileException))
+        *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(MetadataException))
+        *minor = GSSEAP_SAML_METADATA_FAILURE;
+    else
+        return GSS_S_CONTINUE_NEEDED;
+
+    gssEapSaveStatusInfo(*minor, "%s", e.what());
+
+    return GSS_S_FAILURE;
+}
+
+bool
+gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
+                                              int *authenticated,
+                                              int *complete,
+                                              gss_buffer_t value,
+                                              gss_buffer_t display_value GSSEAP_UNUSED,
+                                              int *more) const
+{
+    string str;
+
+    if (attr != GSS_C_NO_BUFFER && attr->length != 0)
+        return false;
+
+    if (m_assertion == NULL)
+        return false;
+
+    if (*more != -1)
+        return false;
+
+    if (authenticated != NULL)
+        *authenticated = m_authenticated;
+    if (complete != NULL)
+        *complete = true;
+
+    XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
+
+    if (value != NULL)
+        duplicateBuffer(str, value);
+    if (display_value != NULL)
+        duplicateBuffer(str, display_value);
+
+    *more = 0;
+
+    return true;
+}
+
+gss_any_t
+gss_eap_saml_assertion_provider::mapToAny(int authenticated,
+                                          gss_buffer_t type_id GSSEAP_UNUSED) const
+{
+    if (authenticated && !m_authenticated)
+        return (gss_any_t)NULL;
+
+    return (gss_any_t)m_assertion;
+}
+
+void
+gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
+                                                       gss_any_t input) const
+{
+    delete ((saml2::Assertion *)input);
+}
+
+const char *
+gss_eap_saml_assertion_provider::prefix(void) const
+{
+    return "urn:ietf:params:gss-eap:saml-aaa-assertion";
+}
+
+bool
+gss_eap_saml_assertion_provider::init(void)
+{
+    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION, createAttrContext);
+    return true;
+}
+
+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<const gss_eap_saml_assertion_provider *>
+        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
+    if (saml == NULL)
+        return false;
+
+    if (authenticated != NULL)
+        *authenticated = saml->authenticated();
+    if (pAssertion != NULL)
+        *pAssertion = saml->getAssertion();
+
+    if (saml->getAssertion() == NULL) {
+        if (createIfAbsent) {
+            if (authenticated != NULL)
+                *authenticated = false;
+            if (pAssertion != NULL)
+                *pAssertion = saml->initAssertion();
+        } else
+            return false;
+    }
+
+    return true;
+}
+
+bool
+gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+                                              void *data) const
+{
+    saml2::Assertion *assertion;
+    int authenticated;
+
+    if (!getAssertion(&authenticated, &assertion))
+        return true;
+
+    /*
+     * Note: the first prefix is added by the attribute provider manager
+     *
+     * From draft-hartman-gss-eap-naming-00:
+     *
+     *   Each attribute carried in the assertion SHOULD also be a GSS name
+     *   attribute.  The name of this attribute has three parts, all separated
+     *   by an ASCII space character.  The first part is
+     *   urn:ietf:params:gss-eap:saml-attr.  The second part is the URI for
+     *   the SAML attribute name format.  The final part is the name of the
+     *   SAML attribute.  If the mechanism performs an additional attribute
+     *   query, the retrieved attributes SHOULD be GSS-API name attributes
+     *   using the same name syntax.
+     */
+    /* For each attribute statement, look for an attribute match */
+    const vector <saml2::AttributeStatement *> &statements =
+        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+        s != statements.end();
+        ++s) {
+        const vector<saml2::Attribute*> &attrs =
+            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+        for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
+            const XMLCh *attributeName, *attributeNameFormat;
+            XMLCh space[2] = { ' ', 0 };
+            gss_buffer_desc utf8;
+
+            attributeName = (*a)->getName();
+            attributeNameFormat = (*a)->getNameFormat();
+            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
+                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
+
+            XMLCh qualifiedName[XMLString::stringLen(attributeNameFormat) + 1 +
+                                XMLString::stringLen(attributeName) + 1];
+            XMLString::copyString(qualifiedName, attributeNameFormat);
+            XMLString::catString(qualifiedName, space);
+            XMLString::catString(qualifiedName, attributeName);
+
+            utf8.value = (void *)toUTF8(qualifiedName);
+            utf8.length = strlen((char *)utf8.value);
+
+            if (!addAttribute(m_manager, this, &utf8, data))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+static BaseRefVectorOf<XMLCh> *
+decomposeAttributeName(const gss_buffer_t attr)
+{
+    BaseRefVectorOf<XMLCh> *components;
+    string str((const char *)attr->value, attr->length);
+    auto_ptr_XMLCh qualifiedAttr(str.c_str());
+
+    components = XMLString::tokenizeString(qualifiedAttr.get());
+
+    if (components->size() != 2) {
+        delete components;
+        components = NULL;
+    }
+
+    return components;
+}
+
+bool
+gss_eap_saml_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
+                                         const gss_buffer_t attr,
+                                         const gss_buffer_t value)
+{
+    saml2::Assertion *assertion;
+    saml2::Attribute *attribute;
+    saml2::AttributeValue *attributeValue;
+    saml2::AttributeStatement *attributeStatement;
+
+    if (!getAssertion(NULL, &assertion, true))
+        return false;
+
+    if (assertion->getAttributeStatements().size() != 0) {
+        attributeStatement = assertion->getAttributeStatements().front();
+    } else {
+        attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement();
+        assertion->getAttributeStatements().push_back(attributeStatement);
+    }
+
+    /* Check the attribute name consists of name format | whsp | name */
+    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+    if (components == NULL)
+        return false;
+
+    attribute = saml2::AttributeBuilder::buildAttribute();
+    attribute->setNameFormat(components->elementAt(0));
+    attribute->setName(components->elementAt(1));
+
+    attributeValue = saml2::AttributeValueBuilder::buildAttributeValue();
+    auto_ptr_XMLCh unistr((char *)value->value, value->length);
+    attributeValue->setTextContent(unistr.get());
+
+    attribute->getAttributeValues().push_back(attributeValue);
+
+    assert(attributeStatement != NULL);
+    attributeStatement->getAttributes().push_back(attribute);
+
+    delete components;
+
+    return true;
+}
+
+bool
+gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr)
+{
+    saml2::Assertion *assertion;
+    bool ret = false;
+
+    if (!getAssertion(NULL, &assertion) ||
+        assertion->getAttributeStatements().size() == 0)
+        return false;
+
+    /* Check the attribute name consists of name format | whsp | name */
+    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+    if (components == NULL)
+        return false;
+
+    /* For each attribute statement, look for an attribute match */
+    const vector<saml2::AttributeStatement *> &statements =
+        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+        s != statements.end();
+        ++s) {
+        const vector<saml2::Attribute *> &attrs =
+            const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
+        ssize_t index = -1, i = 0;
+
+        /* There's got to be an easier way to do this */
+        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin();
+             a != attrs.end();
+             ++a) {
+            if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
+                XMLString::equals((*a)->getName(), components->elementAt(1))) {
+                index = i;
+                break;
+            }
+            ++i;
+        }
+        if (index != -1) {
+            (*s)->getAttributes().erase((*s)->getAttributes().begin() + index);
+            ret = true;
+        }
+    }
+
+    delete components;
+
+    return ret;
+}
+
+bool
+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
+                                         int *authenticated,
+                                         int *complete,
+                                         const saml2::Attribute **pAttribute) const
+{
+    saml2::Assertion *assertion;
+
+    if (authenticated != NULL)
+        *authenticated = false;
+    if (complete != NULL)
+        *complete = true;
+    *pAttribute = NULL;
+
+    if (!getAssertion(authenticated, &assertion) ||
+        assertion->getAttributeStatements().size() == 0)
+        return false;
+
+    /* Check the attribute name consists of name format | whsp | name */
+    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+    if (components == NULL)
+        return false;
+
+    /* For each attribute statement, look for an attribute match */
+    const vector <saml2::AttributeStatement *> &statements =
+        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+    const saml2::Attribute *ret = NULL;
+
+    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+        s != statements.end();
+        ++s) {
+        const vector<saml2::Attribute *> &attrs =
+            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
+            const XMLCh *attributeName, *attributeNameFormat;
+
+            attributeName = (*a)->getName();
+            attributeNameFormat = (*a)->getNameFormat();
+            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
+                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
+
+            if (XMLString::equals(attributeNameFormat, components->elementAt(0)) &&
+                XMLString::equals(attributeName, components->elementAt(1))) {
+                ret = *a;
+                break;
+            }
+        }
+
+        if (ret != NULL)
+            break;
+    }
+
+    delete components;
+
+    *pAttribute = ret;
+
+    return (ret != NULL);
+}
+
+static bool
+isBase64EncodedAttributeValueP(const saml2::AttributeValue *av)
+{
+    const xmltooling::QName *type = av->getSchemaType();
+
+    if (type == NULL)
+        return false;
+
+    if (!type->hasNamespaceURI() ||
+        !XMLString::equals(type->getNamespaceURI(), xmlconstants::XSD_NS))
+        return false;
+
+    if (!type->hasLocalPart() ||
+        !XMLString::equals(type->getLocalPart(), base64Binary))
+        return false;
+
+    return true;
+}
+
+bool
+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
+                                         int *authenticated,
+                                         int *complete,
+                                         gss_buffer_t value,
+                                         gss_buffer_t display_value,
+                                         int *more) const
+{
+    const saml2::Attribute *a;
+    const saml2::AttributeValue *av;
+    int nvalues, i = *more;
+
+    *more = 0;
+
+    if (!getAttribute(attr, authenticated, complete, &a))
+        return false;
+
+    nvalues = a->getAttributeValues().size();
+
+    if (i == -1)
+        i = 0;
+    if (i >= nvalues)
+        return false;
+#ifdef __APPLE__
+    av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
+#else
+    av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
+#endif
+    if (av != NULL) {
+        bool base64Encoded = isBase64EncodedAttributeValueP(av);
+
+        if (value != NULL) {
+            char *stringValue = toUTF8(av->getTextContent(), true);
+            size_t stringValueLen = strlen(stringValue);
+
+            if (base64Encoded) {
+                ssize_t octetLen;
+
+                value->value = GSSEAP_MALLOC(stringValueLen);
+                if (value->value == NULL) {
+                    GSSEAP_FREE(stringValue);
+                    throw new std::bad_alloc;
+                }
+
+                octetLen = base64Decode(stringValue, value->value);
+                if (octetLen < 0) {
+                    GSSEAP_FREE(value->value);
+                    GSSEAP_FREE(stringValue);
+                    value->value = NULL;
+                    return false;
+                }
+                value->length = octetLen;
+                GSSEAP_FREE(stringValue);
+            } else {
+                value->value = stringValue;
+                value->length = stringValueLen;
+            }
+        }
+        if (display_value != NULL && base64Encoded == false) {
+            display_value->value = toUTF8(av->getTextContent(), true);
+            display_value->length = strlen((char *)value->value);
+        }
+    }
+
+    if (nvalues > ++i)
+        *more = i;
+
+    return true;
+}
+
+gss_any_t
+gss_eap_saml_attr_provider::mapToAny(int authenticated GSSEAP_UNUSED,
+                                     gss_buffer_t type_id GSSEAP_UNUSED) const
+{
+    return (gss_any_t)NULL;
+}
+
+void
+gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
+                                                  gss_any_t input GSSEAP_UNUSED) const
+{
+}
+
+const char *
+gss_eap_saml_attr_provider::prefix(void) const
+{
+    return "urn:ietf:params:gss-eap:saml-attr";
+}
+
+bool
+gss_eap_saml_attr_provider::init(void)
+{
+    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML, createAttrContext);
+    return true;
+}
+
+void
+gss_eap_saml_attr_provider::finalize(void)
+{
+    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
+}
+
+gss_eap_attr_provider *
+gss_eap_saml_attr_provider::createAttrContext(void)
+{
+    return new gss_eap_saml_attr_provider;
+}
+
+OM_uint32
+gssEapSamlAttrProvidersInit(OM_uint32 *minor)
+{
+    if (!gss_eap_saml_assertion_provider::init() ||
+        !gss_eap_saml_attr_provider::init()) {
+        *minor = GSSEAP_SAML_INIT_FAILURE;
+        return GSS_S_FAILURE;
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
+{
+    gss_eap_saml_attr_provider::finalize();
+    gss_eap_saml_assertion_provider::finalize();
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/mech_eap/util_saml.h b/mech_eap/util_saml.h
new file mode 100644 (file)
index 0000000..9110ad4
--- /dev/null
@@ -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 (file)
index 0000000..3d2aa2c
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * 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 <xmltooling/XMLObject.h>
+
+#include <saml/saml2/core/Assertions.h>
+
+#include <shibsp/exceptions.h>
+#include <shibsp/attribute/SimpleAttribute.h>
+#include <shibresolver/resolver.h>
+
+#include <sstream>
+
+#include "gssapiP_eap.h"
+
+using namespace shibsp;
+using namespace shibresolver;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
+{
+    m_initialized = false;
+    m_authenticated = false;
+}
+
+gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void)
+{
+    for_each(m_attributes.begin(),
+             m_attributes.end(),
+             xmltooling::cleanup<Attribute>())
+        ;
+}
+
+bool
+gss_eap_shib_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
+                                                    const gss_eap_attr_provider *ctx)
+{
+    const gss_eap_shib_attr_provider *shib;
+
+    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) {
+        return false;
+    }
+
+    m_authenticated = false;
+
+    shib = static_cast<const gss_eap_shib_attr_provider *>(ctx);
+    if (shib != NULL) {
+        m_attributes = duplicateAttributes(shib->getAttributes());
+        m_authenticated = shib->authenticated();
+    }
+
+    m_initialized = true;
+
+    return true;
+}
+
+bool
+gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
+                                               const gss_cred_id_t gssCred,
+                                               const gss_ctx_id_t gssCtx)
+{
+    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
+        return false;
+
+    auto_ptr<ShibbolethResolver> resolver(ShibbolethResolver::create());
+
+    /*
+     * For now, leave ApplicationID defaulted.
+     * Later on, we could allow this via config option to the mechanism
+     * or rely on an SPRequest interface to pass in a URI identifying the
+     * acceptor.
+     */
+#if 0
+    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+    if (gssCred != GSS_C_NO_CREDENTIAL &&
+        gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) {
+        resolver->setApplicationID((const char *)nameBuf.value);
+        gss_release_buffer(&minor, &nameBuf);
+    }
+#endif
+
+    gss_buffer_desc mechName = GSS_C_EMPTY_BUFFER;
+    OM_uint32 major, minor;
+
+    major = gssEapExportNameInternal(&minor, gssCtx->initiatorName, &mechName,
+                                     EXPORT_NAME_FLAG_OID |
+                                     EXPORT_NAME_FLAG_COMPOSITE);
+    if (major == GSS_S_COMPLETE) {
+        resolver->addToken(&mechName);
+        gss_release_buffer(&minor, &mechName);
+    }
+
+    const gss_eap_saml_assertion_provider *saml;
+    saml = static_cast<const gss_eap_saml_assertion_provider *>
+        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
+    if (saml != NULL && saml->getAssertion() != NULL) {
+        resolver->addToken(saml->getAssertion());
+    }
+
+    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;
+
+    assert(m_initialized);
+
+    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
+         a != m_attributes.end();
+         ++a)
+    {
+        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
+             s != (*a)->getAliases().end();
+             ++s) {
+            if (attr->length == (*s).length() &&
+                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
+                return i;
+            }
+        }
+    }
+
+    return -1;
+}
+
+bool
+gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
+                                         const gss_buffer_t attr,
+                                         const gss_buffer_t value)
+{
+    string attrStr((char *)attr->value, attr->length);
+    vector <string> ids(1, attrStr);
+    SimpleAttribute *a = new SimpleAttribute(ids);
+
+    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;
+
+    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
+{
+    assert(m_initialized);
+
+    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
+        a != m_attributes.end();
+        ++a)
+    {
+        gss_buffer_desc attribute;
+
+        attribute.value = (void *)((*a)->getId());
+        attribute.length = strlen((char *)attribute.value);
+
+        if (!addAttribute(m_manager, this, &attribute, data))
+            return false;
+    }
+
+    return true;
+}
+
+const Attribute *
+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
+{
+    const Attribute *ret = NULL;
+
+    assert(m_initialized);
+
+    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
+         a != m_attributes.end();
+         ++a)
+    {
+        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
+             s != (*a)->getAliases().end();
+             ++s) {
+            if (attr->length == (*s).length() &&
+                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
+                ret = *a;
+                break;
+            }
+        }
+        if (ret != NULL)
+            break;
+    }
+
+    return ret;
+}
+
+bool
+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
+                                         int *authenticated,
+                                         int *complete,
+                                         gss_buffer_t value,
+                                         gss_buffer_t display_value,
+                                         int *more) const
+{
+    const Attribute *shibAttr = NULL;
+    gss_buffer_desc buf;
+    int nvalues, i = *more;
+
+    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;
+
+    buf.value = (void *)shibAttr->getSerializedValues()[*more].c_str();
+    buf.length = strlen((char *)buf.value);
+
+    if (buf.length != 0) {
+        if (value != NULL)
+            duplicateBuffer(buf, value);
+
+        if (display_value != NULL)
+            duplicateBuffer(buf, display_value);
+    }
+
+    if (authenticated != NULL)
+        *authenticated = m_authenticated;
+    if (complete != NULL)
+        *complete = false;
+
+    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;
+
+    assert(m_initialized);
+
+    if (authenticated && !m_authenticated)
+        return (gss_any_t)NULL;
+
+    vector <Attribute *>v = duplicateAttributes(m_attributes);
+
+    output = (gss_any_t)new vector <Attribute *>(v);
+
+    return output;
+}
+
+void
+gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
+                                                  gss_any_t input) const
+{
+    assert(m_initialized);
+
+    vector <Attribute *> *v = ((vector <Attribute *> *)input);
+    delete v;
+}
+
+const char *
+gss_eap_shib_attr_provider::prefix(void) const
+{
+    return NULL;
+}
+
+const char *
+gss_eap_shib_attr_provider::name(void) const
+{
+    return "local";
+}
+
+JSONObject
+gss_eap_shib_attr_provider::jsonRepresentation(void) const
+{
+    JSONObject obj;
+
+    if (m_initialized == false)
+        return obj; /* don't export incomplete context */
+
+    JSONObject jattrs = JSONObject::array();
+
+    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
+         a != m_attributes.end(); ++a) {
+        DDF attr = (*a)->marshall();
+        JSONObject jattr = JSONObject::ddf(attr);
+        jattrs.append(jattr);
+    }
+
+    obj.set("attributes", jattrs);
+
+    obj.set("authenticated", m_authenticated);
+
+    return obj;
+}
+
+bool
+gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
+                                               JSONObject &obj)
+{
+    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
+        return false;
+
+    assert(m_authenticated == false);
+    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)
+{
+    if (SPConfig::getConfig().getFeatures() == 0 &&
+        ShibbolethResolver::init() == false)
+        return false;
+
+    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
+
+    return true;
+}
+
+void
+gss_eap_shib_attr_provider::finalize(void)
+{
+    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
+    ShibbolethResolver::term();
+}
+
+OM_uint32
+gss_eap_shib_attr_provider::mapException(OM_uint32 *minor,
+                                         std::exception &e) const
+{
+    if (typeid(e) == typeid(AttributeException))
+        *minor = GSSEAP_SHIB_ATTR_FAILURE;
+    else if (typeid(e) == typeid(AttributeExtractionException))
+        *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE;
+    else if (typeid(e) == typeid(AttributeFilteringException))
+        *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE;
+    else if (typeid(e) == typeid(AttributeResolutionException))
+        *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE;
+    else if (typeid(e) == typeid(ConfigurationException))
+        *minor = GSSEAP_SHIB_CONFIG_FAILURE;
+    else if (typeid(e) == typeid(ListenerException))
+        *minor = GSSEAP_SHIB_LISTENER_FAILURE;
+    else
+        return GSS_S_CONTINUE_NEEDED;
+
+    gssEapSaveStatusInfo(*minor, "%s", e.what());
+
+    return GSS_S_FAILURE;
+}
+
+gss_eap_attr_provider *
+gss_eap_shib_attr_provider::createAttrContext(void)
+{
+    return new gss_eap_shib_attr_provider;
+}
+
+Attribute *
+gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src)
+{
+    DDF obj = src->marshall();
+    Attribute *attribute = Attribute::unmarshall(obj);
+    obj.destroy();
+
+    return attribute;
+}
+
+vector <Attribute *>
+gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
+{
+    vector <Attribute *> dst;
+
+    for (vector<Attribute *>::const_iterator a = src.begin();
+         a != src.end();
+         ++a)
+        dst.push_back(duplicateAttribute(*a));
+
+    return dst;
+}
+
+OM_uint32
+gssEapLocalAttrProviderInit(OM_uint32 *minor)
+{
+    if (!gss_eap_shib_attr_provider::init()) {
+        *minor = GSSEAP_SHIB_INIT_FAILURE;
+        return GSS_S_FAILURE;
+    }
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
+{
+    gss_eap_shib_attr_provider::finalize();
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/mech_eap/util_shib.h b/mech_eap/util_shib.h
new file mode 100644 (file)
index 0000000..4cf7481
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Local attribute provider.
+ */
+
+#ifndef _UTIL_SHIB_H_
+#define _UTIL_SHIB_H_ 1
+
+#ifdef __cplusplus
+
+#include <vector>
+
+namespace shibsp {
+    class Attribute;
+};
+
+namespace shibresolver {
+    class ShibbolethResolver;
+};
+
+struct gss_eap_shib_attr_provider : gss_eap_attr_provider {
+public:
+    gss_eap_shib_attr_provider(void);
+    ~gss_eap_shib_attr_provider(void);
+
+    bool initWithExistingContext(const gss_eap_attr_ctx *source,
+                                 const gss_eap_attr_provider *ctx);
+    bool initWithGssContext(const gss_eap_attr_ctx *source,
+                            const gss_cred_id_t cred,
+                            const gss_ctx_id_t ctx);
+
+    bool setAttribute(int complete,
+                      const gss_buffer_t attr,
+                      const gss_buffer_t value);
+    bool deleteAttribute(const gss_buffer_t value);
+    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+    bool getAttribute(const gss_buffer_t attr,
+                      int *authenticated,
+                      int *complete,
+                      gss_buffer_t value,
+                      gss_buffer_t display_value,
+                      int *more) const;
+    gss_any_t mapToAny(int authenticated,
+                       gss_buffer_t type_id) const;
+    void releaseAnyNameMapping(gss_buffer_t type_id,
+                               gss_any_t input) const;
+
+    const char *prefix(void) const;
+    const char *name(void) const;
+    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
+                            JSONObject &obj);
+    JSONObject jsonRepresentation(void) const;
+
+    static bool init(void);
+    static void finalize(void);
+
+    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
+
+    static gss_eap_attr_provider *createAttrContext(void);
+
+    std::vector<shibsp::Attribute *> getAttributes(void) const {
+        return m_attributes;
+    }
+
+private:
+    static shibsp::Attribute *
+        duplicateAttribute(const shibsp::Attribute *src);
+    static std::vector <shibsp::Attribute *>
+        duplicateAttributes(const std::vector <shibsp::Attribute *>src);
+
+    ssize_t getAttributeIndex(const gss_buffer_t attr) const;
+    const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const;
+
+    bool authenticated(void) const { return m_authenticated; }
+
+    bool m_initialized;
+    bool m_authenticated;
+    std::vector<shibsp::Attribute *> m_attributes;
+};
+
+extern "C" {
+#endif
+
+OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
+OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_SHIB_H_ */
diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c
new file mode 100644 (file)
index 0000000..ca69923
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * 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 { \
+        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)
+{
+    assert(state >= GSSEAP_STATE_INITIAL);
+    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,
+               gss_buffer_set_t *outputToken)
+{
+    OM_uint32 major;
+    unsigned char errorData[8];
+    gss_buffer_desc errorBuffer;
+
+    assert(GSS_ERROR(majorStatus));
+
+    major = gss_create_empty_buffer_set(minor, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    /*
+     * 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]);
+
+    errorBuffer.length = sizeof(errorData);
+    errorBuffer.value = errorData;
+
+    major = gss_add_buffer_set_member(minor, &errorBuffer, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+allocInnerTokens(OM_uint32 *minor,
+                 size_t count,
+                 gss_buffer_set_t *pTokens,
+                 OM_uint32 **pTokenTypes)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_set_t tokens = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *tokenTypes = NULL;
+
+    major = gss_create_empty_buffer_set(minor, &tokens);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    assert(tokens->count == 0);
+    assert(tokens->elements == NULL);
+
+    tokens->elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc));
+    if (tokens->elements == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    tokenTypes = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32));
+    if (tokenTypes == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    if (GSS_ERROR(major)) {
+        gss_release_buffer_set(&tmpMinor, &tokens);
+        tokens = GSS_C_NO_BUFFER_SET;
+        if (tokenTypes != NULL) {
+            GSSEAP_FREE(tokenTypes);
+            tokenTypes = NULL;
+        }
+    }
+
+    *pTokens = tokens;
+    *pTokenTypes = tokenTypes;
+
+    return major;
+}
+
+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;
+    gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER;
+    gss_buffer_set_t innerInputTokens = GSS_C_NO_BUFFER_SET;
+    gss_buffer_set_t innerOutputTokens = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *inputTokenTypes = NULL, *outputTokenTypes = NULL;
+    unsigned int smFlags = 0;
+    size_t i, j;
+    int initialContextToken = 0;
+    enum gss_eap_token_type tokType;
+
+    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;
+    }
+
+    assert(ctx->state < GSSEAP_STATE_ESTABLISHED);
+
+    major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken,
+                                    &innerInputTokens, &inputTokenTypes);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    assert(innerInputTokens != GSS_C_NO_BUFFER_SET);
+
+    major = allocInnerTokens(minor, smCount, &innerOutputTokens, &outputTokenTypes);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    /* 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 < innerInputTokens->count; j++) {
+                if ((inputTokenTypes[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 = &innerInputTokens->elements[j];
+                    inputTokenType = &inputTokenTypes[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) {
+                innerOutputTokens->elements[innerOutputTokens->count] = innerOutputToken;
+                assert(smp->outputTokenType != ITOK_TYPE_NONE);
+                outputTokenTypes[innerOutputTokens->count] = smp->outputTokenType;
+                if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL)
+                    outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL;
+                innerOutputTokens->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) || innerOutputTokens->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;
+        }
+    }
+
+    assert(innerOutputTokens->count <= smCount);
+
+    /* Check we understood all critical tokens sent by peer */
+    if (!GSS_ERROR(major)) {
+        for (j = 0; j < innerInputTokens->count; j++) {
+            if ((inputTokenTypes[j] & ITOK_FLAG_CRITICAL) &&
+                (inputTokenTypes[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 */
+        gss_release_buffer_set(&tmpMinor, &innerOutputTokens);
+
+        tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &innerOutputTokens);
+        if (GSS_ERROR(tmpMajor)) {
+            major = tmpMajor;
+            *minor = tmpMinor;
+            goto cleanup;
+        }
+
+        if (innerOutputTokens->count != 0)
+            outputTokenTypes[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL;
+    }
+
+    /* Format output token from inner tokens */
+    if (innerOutputTokens->count != 0 ||            /* inner tokens to send */
+        !CTX_IS_INITIATOR(ctx) ||                   /* any leg acceptor */
+        !CTX_IS_ESTABLISHED(ctx)) {                 /* non-last leg initiator */
+        tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, innerOutputTokens,
+                                           outputTokenTypes, &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 */
+    assert(!CTX_IS_ESTABLISHED(ctx) || ((outputToken->length == 0) == CTX_IS_INITIATOR(ctx)));
+
+    SM_ASSERT_VALID(ctx, major);
+
+cleanup:
+    gss_release_buffer_set(&tmpMinor, &innerInputTokens);
+    gss_release_buffer_set(&tmpMinor, &innerOutputTokens);
+    if (inputTokenTypes != NULL)
+        GSSEAP_FREE(inputTokenTypes);
+    if (outputTokenTypes != NULL)
+    gss_release_buffer(&tmpMinor, &unwrappedOutputToken);
+        GSSEAP_FREE(outputTokenTypes);
+
+    return major;
+}
diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c
new file mode 100644 (file)
index 0000000..a929198
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * 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,
+                        gss_buffer_set_t extensions,
+                        OM_uint32 *types,
+                        gss_buffer_t buffer)
+{
+    OM_uint32 major, tmpMinor;
+    size_t required = 0, i;
+    unsigned char *p;
+
+    buffer->value = NULL;
+    buffer->length = 0;
+
+    if (extensions != GSS_C_NO_BUFFER_SET) {
+        for (i = 0; i < extensions->count; i++) {
+            required += 8 + extensions->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;
+
+    if (extensions != GSS_C_NO_BUFFER_SET) {
+        for (i = 0; i < extensions->count; i++) {
+            gss_buffer_t extension = &extensions->elements[i];
+
+            assert((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(types[i], &p[0]);
+            store_uint32_be(extension->length, &p[4]);
+            memcpy(&p[8], extension->value, extension->length);
+
+            p += 8 + extension->length;
+        }
+    }
+
+    assert(p == (unsigned char *)buffer->value + required);
+    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,
+                        gss_buffer_set_t *pExtensions,
+                        OM_uint32 **pTypes)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *types = NULL;
+    unsigned char *p;
+    size_t remain;
+
+    *pExtensions = GSS_C_NO_BUFFER_SET;
+    *pTypes = NULL;
+
+    major = gss_create_empty_buffer_set(minor, &extensions);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    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 extension;
+
+        if (remain < 8) {
+            major = GSS_S_DEFECTIVE_TOKEN;
+            *minor = GSSEAP_TOK_TRUNC;
+            goto cleanup;
+        }
+
+        ntypes = GSSEAP_REALLOC(types,
+                                (extensions->count + 1) * sizeof(OM_uint32));
+        if (ntypes == NULL) {
+            major = GSS_S_FAILURE;
+            *minor = ENOMEM;
+            goto cleanup;
+        }
+        types = ntypes;
+
+        types[extensions->count] = load_uint32_be(&p[0]);
+        extension.length = load_uint32_be(&p[4]);
+
+        if (remain < 8 + extension.length) {
+            major = GSS_S_DEFECTIVE_TOKEN;
+            *minor = GSSEAP_TOK_TRUNC;
+            goto cleanup;
+        }
+        extension.value = &p[8];
+
+        major = gss_add_buffer_set_member(minor, &extension, &extensions);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        p      += 8 + extension.length;
+        remain -= 8 + extension.length;
+    } while (remain != 0);
+
+cleanup:
+    if (GSS_ERROR(major)) {
+        gss_release_buffer_set(&tmpMinor, &extensions);
+        if (types != NULL)
+            GSSEAP_FREE(types);
+    } else {
+        *pExtensions = extensions;
+        *pTypes = types;
+    }
+
+    return major;
+}
+
+/*
+ * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
+ */
+
+/* XXXX this code currently makes the assumption that a mech oid will
+   never be longer than 127 bytes.  This assumption is not inherent in
+   the interfaces, so the code can be fixed if the OSI namespace
+   balloons unexpectedly. */
+
+/*
+ * Each token looks like this:
+ * 0x60                 tag for APPLICATION 0, SEQUENCE
+ *                              (constructed, definite-length)
+ * <length>             possible multiple bytes, need to parse/generate
+ * 0x06                 tag for OBJECT IDENTIFIER
+ * <moid_length>        compile-time constant string (assume 1 byte)
+ * <moid_bytes>         compile-time constant string
+ * <inner_bytes>        the ANY containing the application token
+ * bytes 0,1 are the token type
+ * bytes 2,n are the token data
+ *
+ * Note that the token type field is a feature of RFC 1964 mechanisms and
+ * is not used by other GSSAPI mechanisms.  As such, a token type of -1
+ * is interpreted to mean that no token type should be expected or
+ * generated.
+ *
+ * For the purposes of this abstraction, the token "header" consists of
+ * the sequence tag and length octets, the mech OID DER encoding, and the
+ * first two inner bytes, which indicate the token type.  The token
+ * "body" consists of everything else.
+ */
+
+static size_t
+der_length_size(size_t length)
+{
+    if (length < (1<<7))
+        return 1;
+    else if (length < (1<<8))
+        return 2;
+#if INT_MAX == 0x7fff
+    else
+        return 3;
+#else
+    else if (length < (1<<16))
+        return 3;
+    else if (length < (1<<24))
+        return 4;
+    else
+        return 5;
+#endif
+}
+
+static void
+der_write_length(unsigned char **buf, size_t length)
+{
+    if (length < (1<<7)) {
+        *(*buf)++ = (unsigned char)length;
+    } else {
+        *(*buf)++ = (unsigned char)(der_length_size(length)+127);
+#if INT_MAX > 0x7fff
+        if (length >= (1<<24))
+            *(*buf)++ = (unsigned char)(length>>24);
+        if (length >= (1<<16))
+            *(*buf)++ = (unsigned char)((length>>16)&0xff);
+#endif
+        if (length >= (1<<8))
+            *(*buf)++ = (unsigned char)((length>>8)&0xff);
+        *(*buf)++ = (unsigned char)(length&0xff);
+    }
+}
+
+/* returns decoded length, or < 0 on failure.  Advances buf and
+   decrements bufsize */
+
+static int
+der_read_length(unsigned char **buf, ssize_t *bufsize)
+{
+    unsigned char sf;
+    int ret;
+
+    if (*bufsize < 1)
+        return -1;
+
+    sf = *(*buf)++;
+    (*bufsize)--;
+    if (sf & 0x80) {
+        if ((sf &= 0x7f) > ((*bufsize)-1))
+            return -1;
+        if (sf > sizeof(int))
+            return -1;
+        ret = 0;
+        for (; sf; sf--) {
+            ret = (ret<<8) + (*(*buf)++);
+            (*bufsize)--;
+        }
+    } else {
+        ret = sf;
+    }
+
+    return ret;
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+size_t
+tokenSize(const gss_OID_desc *mech, size_t body_size)
+{
+    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;
+    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;
+}
diff --git a/mech_eap/verify_mic.c b/mech_eap/verify_mic.c
new file mode 100644 (file)
index 0000000..0a56949
--- /dev/null
@@ -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
+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 (file)
index 0000000..a89bcb6
--- /dev/null
@@ -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
+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 (file)
index 0000000..31450fc
--- /dev/null
@@ -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;
+
+        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
+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 (file)
index 0000000..229fec7
--- /dev/null
@@ -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;
+
+    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
+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 (file)
index 0000000..aadf1b4
--- /dev/null
@@ -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
+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;
+}