+#define EAP_MAX_METHODS 8
+
+#define EAP_TTLS_AUTH_PAP 1
+#define EAP_TTLS_AUTH_CHAP 2
+#define EAP_TTLS_AUTH_MSCHAP 4
+#define EAP_TTLS_AUTH_MSCHAPV2 8
+
+#if 1
+struct eap_user {
+ struct {
+ int vendor;
+ u32 method;
+ } methods[EAP_MAX_METHODS];
+ u8 *password;
+ size_t password_len;
+ int password_hash; /* whether password is hashed with
+ * nt_password_hash() */
+ int phase2;
+ int force_version;
+ int ttls_auth; /* bitfield of
+ * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
+};
+
+struct eap_eapol_interface {
+ /* Lower layer to full authenticator variables */
+ Boolean eapResp; /* shared with EAPOL Backend Authentication */
+ struct wpabuf *eapRespData;
+ Boolean portEnabled;
+ int retransWhile;
+ Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
+ int eapSRTT;
+ int eapRTTVAR;
+
+ /* Full authenticator to lower layer variables */
+ Boolean eapReq; /* shared with EAPOL Backend Authentication */
+ Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
+ Boolean eapSuccess;
+ Boolean eapFail;
+ Boolean eapTimeout;
+ struct wpabuf *eapReqData;
+ u8 *eapKeyData;
+ size_t eapKeyDataLen;
+ Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
+
+ /* AAA interface to full authenticator variables */
+ Boolean aaaEapReq;
+ Boolean aaaEapNoReq;
+ Boolean aaaSuccess;
+ Boolean aaaFail;
+ struct wpabuf *aaaEapReqData;
+ u8 *aaaEapKeyData;
+ size_t aaaEapKeyDataLen;
+ Boolean aaaEapKeyAvailable;
+ int aaaMethodTimeout;
+
+ /* Full authenticator to AAA interface variables */
+ Boolean aaaEapResp;
+ struct wpabuf *aaaEapRespData;
+ /* aaaIdentity -> eap_get_identity() */
+ Boolean aaaTimeout;
+};
+
+#define eapol_callbacks SERVER_eapol_callbacks
+
+struct eapol_callbacks {
+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+ int phase2, struct eap_user *user);
+ const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
+};
+
+#define eap_config SERVER_eap_config
+
+struct eap_config {
+ void *ssl_ctx;
+ void *msg_ctx;
+ void *eap_sim_db_priv;
+ Boolean backend_auth;
+ int eap_server;
+ u8 *pac_opaque_encr_key;
+ u8 *eap_fast_a_id;
+ size_t eap_fast_a_id_len;
+ char *eap_fast_a_id_info;
+ int eap_fast_prov;
+ int pac_key_lifetime;
+ int pac_key_refresh_time;
+ int eap_sim_aka_result_ind;
+ int tnc;
+ struct wps_context *wps;
+ const struct wpabuf *assoc_wps_ie;
+ const u8 *peer_addr;
+ int fragment_size;
+};
+
+struct eap_sm * eap_server_sm_init(void *eapol_ctx,
+ struct eapol_callbacks *eapol_cb,
+ struct eap_config *eap_conf);
+void eap_server_sm_deinit(struct eap_sm *sm);
+int eap_server_sm_step(struct eap_sm *sm);
+void eap_sm_notify_cached(struct eap_sm *sm);
+void eap_sm_pending_cb(struct eap_sm *sm);
+int eap_sm_method_pending(struct eap_sm *sm);
+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+
+static OM_uint32
+initTls(OM_uint32 *minor,
+ gss_ctx_id_t ctx)
+{
+ struct tls_config tconf;
+ struct tls_connection_params tparams;
+
+ memset(&tconf, 0, sizeof(tconf));
+ ctx->acceptorCtx.tlsContext = tls_init(&tconf);
+ if (ctx->acceptorCtx.tlsContext == NULL)
+ return GSS_S_FAILURE;
+
+ memset(&tparams, 0, sizeof(tparams));
+ tparams.ca_cert = "ca.pem";
+ tparams.client_cert = "server.pem";
+ tparams.private_key = "server-key.pem";
+
+ if (tls_global_set_params(ctx->acceptorCtx.tlsContext, &tparams)) {
+ return GSS_S_FAILURE;
+ }
+
+ if (tls_global_set_verify(ctx->acceptorCtx.tlsContext, 0)) {
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static int
+serverGetEapUser(void *ctx,
+ const unsigned char *identity,
+ size_t identityLength,
+ int phase2,
+ struct eap_user *user)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+ OM_uint32 major, minor;
+ gss_buffer_desc buf;
+
+ memset(user, 0, sizeof(*user));
+
+ buf.length = identityLength;
+ buf.value = (void *)identity;
+
+ if (phase2 == 0) {
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_PEAP;
+ return 0;
+ }
+
+ major = gssEapImportName(&minor, &buf, GSS_C_NT_USER_NAME,
+ &gssCtx->initiatorName);
+ if (GSS_ERROR(major))
+ return -1;
+
+ /*
+ * OK, obviously there is no real security here, this is simply
+ * for testing the token exchange; this code will be completely
+ * replaced with libradsec once that library is available.
+ */
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_MSCHAPV2;
+ user->password = (unsigned char *)strdup("");
+ user->password_len = 0;
+
+ return 0;
+}
+
+static const char *
+serverGetEapReqIdText(void *ctx,
+ size_t *len)
+{
+ *len = 0;
+ return NULL;
+}
+#endif
+
+static OM_uint32
+serverDeriveKey(OM_uint32 *minor,
+ gss_ctx_id_t ctx)
+{
+ OM_uint32 major;
+ krb5_context krbContext;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (ctx->encryptionType != ENCTYPE_NULL &&
+ ctx->acceptorCtx.eapPolInterface->eapKeyAvailable) {
+ major = gssEapDeriveRFC3961Key(minor,
+ ctx->acceptorCtx.eapPolInterface->eapKeyData,
+ ctx->acceptorCtx.eapPolInterface->eapKeyDataLen,
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+ } else {
+ /*
+ * draft-howlett-eap-gss says that integrity/confidentialty should
+ * always be advertised as available, but if we have no keying
+ * material it seems confusing to the caller to advertise this.
+ */
+ ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+ }
+
+ return GSS_S_COMPLETE;
+}
+