1/* 2 * hostapd / EAP-Identity 3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "eap_i.h" 13 14 15struct eap_identity_data { 16 enum { CONTINUE, SUCCESS, FAILURE } state; 17 int pick_up; 18}; 19 20 21static void * eap_identity_init(struct eap_sm *sm) 22{ 23 struct eap_identity_data *data; 24 25 data = os_zalloc(sizeof(*data)); 26 if (data == NULL) 27 return NULL; 28 data->state = CONTINUE; 29 30 return data; 31} 32 33 34static void * eap_identity_initPickUp(struct eap_sm *sm) 35{ 36 struct eap_identity_data *data; 37 data = eap_identity_init(sm); 38 if (data) { 39 data->pick_up = 1; 40 } 41 return data; 42} 43 44 45static void eap_identity_reset(struct eap_sm *sm, void *priv) 46{ 47 struct eap_identity_data *data = priv; 48 os_free(data); 49} 50 51 52static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv, 53 u8 id) 54{ 55 struct eap_identity_data *data = priv; 56 struct wpabuf *req; 57 const char *req_data; 58 size_t req_data_len; 59 60 if (sm->eapol_cb->get_eap_req_id_text) { 61 req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx, 62 &req_data_len); 63 } else { 64 req_data = NULL; 65 req_data_len = 0; 66 } 67 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len, 68 EAP_CODE_REQUEST, id); 69 if (req == NULL) { 70 wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate " 71 "memory for request"); 72 data->state = FAILURE; 73 return NULL; 74 } 75 76 wpabuf_put_data(req, req_data, req_data_len); 77 78 return req; 79} 80 81 82static Boolean eap_identity_check(struct eap_sm *sm, void *priv, 83 struct wpabuf *respData) 84{ 85 const u8 *pos; 86 size_t len; 87 88 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 89 respData, &len); 90 if (pos == NULL) { 91 wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame"); 92 return TRUE; 93 } 94 95 return FALSE; 96} 97 98 99static void eap_identity_process(struct eap_sm *sm, void *priv, 100 struct wpabuf *respData) 101{ 102 struct eap_identity_data *data = priv; 103 const u8 *pos; 104 size_t len; 105 106 if (data->pick_up) { 107 if (eap_identity_check(sm, data, respData)) { 108 wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick " 109 "up already started negotiation"); 110 data->state = FAILURE; 111 return; 112 } 113 data->pick_up = 0; 114 } 115 116 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 117 respData, &len); 118 if (pos == NULL) 119 return; /* Should not happen - frame already validated */ 120 121 wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len); 122 if (sm->identity) 123 sm->update_user = TRUE; 124 os_free(sm->identity); 125 sm->identity = os_malloc(len ? len : 1); 126 if (sm->identity == NULL) { 127 data->state = FAILURE; 128 } else { 129 os_memcpy(sm->identity, pos, len); 130 sm->identity_len = len; 131 data->state = SUCCESS; 132 } 133} 134 135 136static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv) 137{ 138 struct eap_identity_data *data = priv; 139 return data->state != CONTINUE; 140} 141 142 143static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv) 144{ 145 struct eap_identity_data *data = priv; 146 return data->state == SUCCESS; 147} 148 149 150int eap_server_identity_register(void) 151{ 152 struct eap_method *eap; 153 int ret; 154 155 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 156 EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 157 "Identity"); 158 if (eap == NULL) 159 return -1; 160 161 eap->init = eap_identity_init; 162 eap->initPickUp = eap_identity_initPickUp; 163 eap->reset = eap_identity_reset; 164 eap->buildReq = eap_identity_buildReq; 165 eap->check = eap_identity_check; 166 eap->process = eap_identity_process; 167 eap->isDone = eap_identity_isDone; 168 eap->isSuccess = eap_identity_isSuccess; 169 170 ret = eap_server_method_register(eap); 171 if (ret) 172 eap_server_method_free(eap); 173 return ret; 174} 175