$search
00001 /* 00002 * hostapd / EAP Full Authenticator state machine (RFC 4137) 00003 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 * 00014 * This state machine is based on the full authenticator state machine defined 00015 * in RFC 4137. However, to support backend authentication in RADIUS 00016 * authentication server functionality, parts of backend authenticator (also 00017 * from RFC 4137) are mixed in. This functionality is enabled by setting 00018 * backend_auth configuration variable to TRUE. 00019 */ 00020 00021 #include "includes.h" 00022 00023 #include "common.h" 00024 #include "eap_i.h" 00025 #include "state_machine.h" 00026 #include "common/wpa_ctrl.h" 00027 00028 #define STATE_MACHINE_DATA struct eap_sm 00029 #define STATE_MACHINE_DEBUG_PREFIX "EAP" 00030 00031 #define EAP_MAX_AUTH_ROUNDS 50 00032 00033 static void eap_user_free(struct eap_user *user); 00034 00035 00036 /* EAP state machines are described in RFC 4137 */ 00037 00038 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 00039 int eapSRTT, int eapRTTVAR, 00040 int methodTimeout); 00041 static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); 00042 static int eap_sm_getId(const struct wpabuf *data); 00043 static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); 00044 static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); 00045 static int eap_sm_nextId(struct eap_sm *sm, int id); 00046 static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 00047 size_t len); 00048 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor); 00049 static int eap_sm_Policy_getDecision(struct eap_sm *sm); 00050 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method); 00051 00052 00053 static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) 00054 { 00055 if (src == NULL) 00056 return -1; 00057 00058 wpabuf_free(*dst); 00059 *dst = wpabuf_dup(src); 00060 return *dst ? 0 : -1; 00061 } 00062 00063 00064 static int eap_copy_data(u8 **dst, size_t *dst_len, 00065 const u8 *src, size_t src_len) 00066 { 00067 if (src == NULL) 00068 return -1; 00069 00070 os_free(*dst); 00071 *dst = os_malloc(src_len); 00072 if (*dst) { 00073 os_memcpy(*dst, src, src_len); 00074 *dst_len = src_len; 00075 return 0; 00076 } else { 00077 *dst_len = 0; 00078 return -1; 00079 } 00080 } 00081 00082 #define EAP_COPY(dst, src) \ 00083 eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) 00084 00085 00099 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, 00100 int phase2) 00101 { 00102 struct eap_user *user; 00103 00104 if (sm == NULL || sm->eapol_cb == NULL || 00105 sm->eapol_cb->get_eap_user == NULL) 00106 return -1; 00107 00108 eap_user_free(sm->user); 00109 sm->user = NULL; 00110 00111 user = os_zalloc(sizeof(*user)); 00112 if (user == NULL) 00113 return -1; 00114 00115 if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, 00116 identity_len, phase2, user) != 0) { 00117 eap_user_free(user); 00118 return -1; 00119 } 00120 00121 sm->user = user; 00122 sm->user_eap_method_index = 0; 00123 00124 return 0; 00125 } 00126 00127 00128 SM_STATE(EAP, DISABLED) 00129 { 00130 SM_ENTRY(EAP, DISABLED); 00131 sm->num_rounds = 0; 00132 } 00133 00134 00135 SM_STATE(EAP, INITIALIZE) 00136 { 00137 SM_ENTRY(EAP, INITIALIZE); 00138 00139 sm->currentId = -1; 00140 sm->eap_if.eapSuccess = FALSE; 00141 sm->eap_if.eapFail = FALSE; 00142 sm->eap_if.eapTimeout = FALSE; 00143 os_free(sm->eap_if.eapKeyData); 00144 sm->eap_if.eapKeyData = NULL; 00145 sm->eap_if.eapKeyDataLen = 0; 00146 sm->eap_if.eapKeyAvailable = FALSE; 00147 sm->eap_if.eapRestart = FALSE; 00148 00149 /* 00150 * This is not defined in RFC 4137, but method state needs to be 00151 * reseted here so that it does not remain in success state when 00152 * re-authentication starts. 00153 */ 00154 if (sm->m && sm->eap_method_priv) { 00155 sm->m->reset(sm, sm->eap_method_priv); 00156 sm->eap_method_priv = NULL; 00157 } 00158 sm->m = NULL; 00159 sm->user_eap_method_index = 0; 00160 00161 if (sm->backend_auth) { 00162 sm->currentMethod = EAP_TYPE_NONE; 00163 /* parse rxResp, respId, respMethod */ 00164 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 00165 if (sm->rxResp) { 00166 sm->currentId = sm->respId; 00167 } 00168 } 00169 sm->num_rounds = 0; 00170 sm->method_pending = METHOD_PENDING_NONE; 00171 00172 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED 00173 MACSTR, MAC2STR(sm->peer_addr)); 00174 } 00175 00176 00177 SM_STATE(EAP, PICK_UP_METHOD) 00178 { 00179 SM_ENTRY(EAP, PICK_UP_METHOD); 00180 00181 if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { 00182 sm->currentMethod = sm->respMethod; 00183 if (sm->m && sm->eap_method_priv) { 00184 sm->m->reset(sm, sm->eap_method_priv); 00185 sm->eap_method_priv = NULL; 00186 } 00187 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, 00188 sm->currentMethod); 00189 if (sm->m && sm->m->initPickUp) { 00190 sm->eap_method_priv = sm->m->initPickUp(sm); 00191 if (sm->eap_method_priv == NULL) { 00192 wpa_printf(MSG_DEBUG, "EAP: Failed to " 00193 "initialize EAP method %d", 00194 sm->currentMethod); 00195 sm->m = NULL; 00196 sm->currentMethod = EAP_TYPE_NONE; 00197 } 00198 } else { 00199 sm->m = NULL; 00200 sm->currentMethod = EAP_TYPE_NONE; 00201 } 00202 } 00203 00204 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 00205 "method=%u", sm->currentMethod); 00206 } 00207 00208 00209 SM_STATE(EAP, IDLE) 00210 { 00211 SM_ENTRY(EAP, IDLE); 00212 00213 sm->eap_if.retransWhile = eap_sm_calculateTimeout( 00214 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 00215 sm->methodTimeout); 00216 } 00217 00218 00219 SM_STATE(EAP, RETRANSMIT) 00220 { 00221 SM_ENTRY(EAP, RETRANSMIT); 00222 00223 sm->retransCount++; 00224 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 00225 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 00226 sm->eap_if.eapReq = TRUE; 00227 } 00228 } 00229 00230 00231 SM_STATE(EAP, RECEIVED) 00232 { 00233 SM_ENTRY(EAP, RECEIVED); 00234 00235 /* parse rxResp, respId, respMethod */ 00236 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 00237 sm->num_rounds++; 00238 } 00239 00240 00241 SM_STATE(EAP, DISCARD) 00242 { 00243 SM_ENTRY(EAP, DISCARD); 00244 sm->eap_if.eapResp = FALSE; 00245 sm->eap_if.eapNoReq = TRUE; 00246 } 00247 00248 00249 SM_STATE(EAP, SEND_REQUEST) 00250 { 00251 SM_ENTRY(EAP, SEND_REQUEST); 00252 00253 sm->retransCount = 0; 00254 if (sm->eap_if.eapReqData) { 00255 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 00256 { 00257 sm->eap_if.eapResp = FALSE; 00258 sm->eap_if.eapReq = TRUE; 00259 } else { 00260 sm->eap_if.eapResp = FALSE; 00261 sm->eap_if.eapReq = FALSE; 00262 } 00263 } else { 00264 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); 00265 sm->eap_if.eapResp = FALSE; 00266 sm->eap_if.eapReq = FALSE; 00267 sm->eap_if.eapNoReq = TRUE; 00268 } 00269 } 00270 00271 00272 SM_STATE(EAP, INTEGRITY_CHECK) 00273 { 00274 SM_ENTRY(EAP, INTEGRITY_CHECK); 00275 00276 if (sm->m->check) { 00277 sm->ignore = sm->m->check(sm, sm->eap_method_priv, 00278 sm->eap_if.eapRespData); 00279 } 00280 } 00281 00282 00283 SM_STATE(EAP, METHOD_REQUEST) 00284 { 00285 SM_ENTRY(EAP, METHOD_REQUEST); 00286 00287 if (sm->m == NULL) { 00288 wpa_printf(MSG_DEBUG, "EAP: method not initialized"); 00289 return; 00290 } 00291 00292 sm->currentId = eap_sm_nextId(sm, sm->currentId); 00293 wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", 00294 sm->currentId); 00295 sm->lastId = sm->currentId; 00296 wpabuf_free(sm->eap_if.eapReqData); 00297 sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, 00298 sm->currentId); 00299 if (sm->m->getTimeout) 00300 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); 00301 else 00302 sm->methodTimeout = 0; 00303 } 00304 00305 00306 SM_STATE(EAP, METHOD_RESPONSE) 00307 { 00308 SM_ENTRY(EAP, METHOD_RESPONSE); 00309 00310 sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); 00311 if (sm->m->isDone(sm, sm->eap_method_priv)) { 00312 eap_sm_Policy_update(sm, NULL, 0); 00313 os_free(sm->eap_if.eapKeyData); 00314 if (sm->m->getKey) { 00315 sm->eap_if.eapKeyData = sm->m->getKey( 00316 sm, sm->eap_method_priv, 00317 &sm->eap_if.eapKeyDataLen); 00318 } else { 00319 sm->eap_if.eapKeyData = NULL; 00320 sm->eap_if.eapKeyDataLen = 0; 00321 } 00322 sm->methodState = METHOD_END; 00323 } else { 00324 sm->methodState = METHOD_CONTINUE; 00325 } 00326 } 00327 00328 00329 SM_STATE(EAP, PROPOSE_METHOD) 00330 { 00331 int vendor; 00332 EapType type; 00333 00334 SM_ENTRY(EAP, PROPOSE_METHOD); 00335 00336 type = eap_sm_Policy_getNextMethod(sm, &vendor); 00337 if (vendor == EAP_VENDOR_IETF) 00338 sm->currentMethod = type; 00339 else 00340 sm->currentMethod = EAP_TYPE_EXPANDED; 00341 if (sm->m && sm->eap_method_priv) { 00342 sm->m->reset(sm, sm->eap_method_priv); 00343 sm->eap_method_priv = NULL; 00344 } 00345 sm->m = eap_server_get_eap_method(vendor, type); 00346 if (sm->m) { 00347 sm->eap_method_priv = sm->m->init(sm); 00348 if (sm->eap_method_priv == NULL) { 00349 wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " 00350 "method %d", sm->currentMethod); 00351 sm->m = NULL; 00352 sm->currentMethod = EAP_TYPE_NONE; 00353 } 00354 } 00355 if (sm->currentMethod == EAP_TYPE_IDENTITY || 00356 sm->currentMethod == EAP_TYPE_NOTIFICATION) 00357 sm->methodState = METHOD_CONTINUE; 00358 else 00359 sm->methodState = METHOD_PROPOSED; 00360 00361 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 00362 "vendor=%u method=%u", vendor, sm->currentMethod); 00363 } 00364 00365 00366 SM_STATE(EAP, NAK) 00367 { 00368 const struct eap_hdr *nak; 00369 size_t len = 0; 00370 const u8 *pos; 00371 const u8 *nak_list = NULL; 00372 00373 SM_ENTRY(EAP, NAK); 00374 00375 if (sm->eap_method_priv) { 00376 sm->m->reset(sm, sm->eap_method_priv); 00377 sm->eap_method_priv = NULL; 00378 } 00379 sm->m = NULL; 00380 00381 nak = wpabuf_head(sm->eap_if.eapRespData); 00382 if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { 00383 len = be_to_host16(nak->length); 00384 if (len > wpabuf_len(sm->eap_if.eapRespData)) 00385 len = wpabuf_len(sm->eap_if.eapRespData); 00386 pos = (const u8 *) (nak + 1); 00387 len -= sizeof(*nak); 00388 if (*pos == EAP_TYPE_NAK) { 00389 pos++; 00390 len--; 00391 nak_list = pos; 00392 } 00393 } 00394 eap_sm_Policy_update(sm, nak_list, len); 00395 } 00396 00397 00398 SM_STATE(EAP, SELECT_ACTION) 00399 { 00400 SM_ENTRY(EAP, SELECT_ACTION); 00401 00402 sm->decision = eap_sm_Policy_getDecision(sm); 00403 } 00404 00405 00406 SM_STATE(EAP, TIMEOUT_FAILURE) 00407 { 00408 SM_ENTRY(EAP, TIMEOUT_FAILURE); 00409 00410 sm->eap_if.eapTimeout = TRUE; 00411 } 00412 00413 00414 SM_STATE(EAP, FAILURE) 00415 { 00416 SM_ENTRY(EAP, FAILURE); 00417 00418 wpabuf_free(sm->eap_if.eapReqData); 00419 sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); 00420 wpabuf_free(sm->lastReqData); 00421 sm->lastReqData = NULL; 00422 sm->eap_if.eapFail = TRUE; 00423 00424 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE 00425 MACSTR, MAC2STR(sm->peer_addr)); 00426 } 00427 00428 00429 SM_STATE(EAP, SUCCESS) 00430 { 00431 SM_ENTRY(EAP, SUCCESS); 00432 00433 wpabuf_free(sm->eap_if.eapReqData); 00434 sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); 00435 wpabuf_free(sm->lastReqData); 00436 sm->lastReqData = NULL; 00437 if (sm->eap_if.eapKeyData) 00438 sm->eap_if.eapKeyAvailable = TRUE; 00439 sm->eap_if.eapSuccess = TRUE; 00440 00441 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS 00442 MACSTR, MAC2STR(sm->peer_addr)); 00443 } 00444 00445 00446 SM_STATE(EAP, INITIALIZE_PASSTHROUGH) 00447 { 00448 SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); 00449 00450 wpabuf_free(sm->eap_if.aaaEapRespData); 00451 sm->eap_if.aaaEapRespData = NULL; 00452 } 00453 00454 00455 SM_STATE(EAP, IDLE2) 00456 { 00457 SM_ENTRY(EAP, IDLE2); 00458 00459 sm->eap_if.retransWhile = eap_sm_calculateTimeout( 00460 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 00461 sm->methodTimeout); 00462 } 00463 00464 00465 SM_STATE(EAP, RETRANSMIT2) 00466 { 00467 SM_ENTRY(EAP, RETRANSMIT2); 00468 00469 sm->retransCount++; 00470 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 00471 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 00472 sm->eap_if.eapReq = TRUE; 00473 } 00474 } 00475 00476 00477 SM_STATE(EAP, RECEIVED2) 00478 { 00479 SM_ENTRY(EAP, RECEIVED2); 00480 00481 /* parse rxResp, respId, respMethod */ 00482 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 00483 } 00484 00485 00486 SM_STATE(EAP, DISCARD2) 00487 { 00488 SM_ENTRY(EAP, DISCARD2); 00489 sm->eap_if.eapResp = FALSE; 00490 sm->eap_if.eapNoReq = TRUE; 00491 } 00492 00493 00494 SM_STATE(EAP, SEND_REQUEST2) 00495 { 00496 SM_ENTRY(EAP, SEND_REQUEST2); 00497 00498 sm->retransCount = 0; 00499 if (sm->eap_if.eapReqData) { 00500 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 00501 { 00502 sm->eap_if.eapResp = FALSE; 00503 sm->eap_if.eapReq = TRUE; 00504 } else { 00505 sm->eap_if.eapResp = FALSE; 00506 sm->eap_if.eapReq = FALSE; 00507 } 00508 } else { 00509 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); 00510 sm->eap_if.eapResp = FALSE; 00511 sm->eap_if.eapReq = FALSE; 00512 sm->eap_if.eapNoReq = TRUE; 00513 } 00514 } 00515 00516 00517 SM_STATE(EAP, AAA_REQUEST) 00518 { 00519 SM_ENTRY(EAP, AAA_REQUEST); 00520 00521 if (sm->eap_if.eapRespData == NULL) { 00522 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); 00523 return; 00524 } 00525 00526 /* 00527 * if (respMethod == IDENTITY) 00528 * aaaIdentity = eapRespData 00529 * This is already taken care of by the EAP-Identity method which 00530 * stores the identity into sm->identity. 00531 */ 00532 00533 eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); 00534 } 00535 00536 00537 SM_STATE(EAP, AAA_RESPONSE) 00538 { 00539 SM_ENTRY(EAP, AAA_RESPONSE); 00540 00541 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 00542 sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); 00543 sm->methodTimeout = sm->eap_if.aaaMethodTimeout; 00544 } 00545 00546 00547 SM_STATE(EAP, AAA_IDLE) 00548 { 00549 SM_ENTRY(EAP, AAA_IDLE); 00550 00551 sm->eap_if.aaaFail = FALSE; 00552 sm->eap_if.aaaSuccess = FALSE; 00553 sm->eap_if.aaaEapReq = FALSE; 00554 sm->eap_if.aaaEapNoReq = FALSE; 00555 sm->eap_if.aaaEapResp = TRUE; 00556 } 00557 00558 00559 SM_STATE(EAP, TIMEOUT_FAILURE2) 00560 { 00561 SM_ENTRY(EAP, TIMEOUT_FAILURE2); 00562 00563 sm->eap_if.eapTimeout = TRUE; 00564 } 00565 00566 00567 SM_STATE(EAP, FAILURE2) 00568 { 00569 SM_ENTRY(EAP, FAILURE2); 00570 00571 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 00572 sm->eap_if.eapFail = TRUE; 00573 } 00574 00575 00576 SM_STATE(EAP, SUCCESS2) 00577 { 00578 SM_ENTRY(EAP, SUCCESS2); 00579 00580 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 00581 00582 sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; 00583 if (sm->eap_if.aaaEapKeyAvailable) { 00584 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); 00585 } else { 00586 os_free(sm->eap_if.eapKeyData); 00587 sm->eap_if.eapKeyData = NULL; 00588 sm->eap_if.eapKeyDataLen = 0; 00589 } 00590 00591 sm->eap_if.eapSuccess = TRUE; 00592 00593 /* 00594 * Start reauthentication with identity request even though we know the 00595 * previously used identity. This is needed to get reauthentication 00596 * started properly. 00597 */ 00598 sm->start_reauth = TRUE; 00599 } 00600 00601 00602 SM_STEP(EAP) 00603 { 00604 if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) 00605 SM_ENTER_GLOBAL(EAP, INITIALIZE); 00606 else if (!sm->eap_if.portEnabled) 00607 SM_ENTER_GLOBAL(EAP, DISABLED); 00608 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { 00609 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { 00610 wpa_printf(MSG_DEBUG, "EAP: more than %d " 00611 "authentication rounds - abort", 00612 EAP_MAX_AUTH_ROUNDS); 00613 sm->num_rounds++; 00614 SM_ENTER_GLOBAL(EAP, FAILURE); 00615 } 00616 } else switch (sm->EAP_state) { 00617 case EAP_INITIALIZE: 00618 if (sm->backend_auth) { 00619 if (!sm->rxResp) 00620 SM_ENTER(EAP, SELECT_ACTION); 00621 else if (sm->rxResp && 00622 (sm->respMethod == EAP_TYPE_NAK || 00623 (sm->respMethod == EAP_TYPE_EXPANDED && 00624 sm->respVendor == EAP_VENDOR_IETF && 00625 sm->respVendorMethod == EAP_TYPE_NAK))) 00626 SM_ENTER(EAP, NAK); 00627 else 00628 SM_ENTER(EAP, PICK_UP_METHOD); 00629 } else { 00630 SM_ENTER(EAP, SELECT_ACTION); 00631 } 00632 break; 00633 case EAP_PICK_UP_METHOD: 00634 if (sm->currentMethod == EAP_TYPE_NONE) { 00635 SM_ENTER(EAP, SELECT_ACTION); 00636 } else { 00637 SM_ENTER(EAP, METHOD_RESPONSE); 00638 } 00639 break; 00640 case EAP_DISABLED: 00641 if (sm->eap_if.portEnabled) 00642 SM_ENTER(EAP, INITIALIZE); 00643 break; 00644 case EAP_IDLE: 00645 if (sm->eap_if.retransWhile == 0) 00646 SM_ENTER(EAP, RETRANSMIT); 00647 else if (sm->eap_if.eapResp) 00648 SM_ENTER(EAP, RECEIVED); 00649 break; 00650 case EAP_RETRANSMIT: 00651 if (sm->retransCount > sm->MaxRetrans) 00652 SM_ENTER(EAP, TIMEOUT_FAILURE); 00653 else 00654 SM_ENTER(EAP, IDLE); 00655 break; 00656 case EAP_RECEIVED: 00657 if (sm->rxResp && (sm->respId == sm->currentId) && 00658 (sm->respMethod == EAP_TYPE_NAK || 00659 (sm->respMethod == EAP_TYPE_EXPANDED && 00660 sm->respVendor == EAP_VENDOR_IETF && 00661 sm->respVendorMethod == EAP_TYPE_NAK)) 00662 && (sm->methodState == METHOD_PROPOSED)) 00663 SM_ENTER(EAP, NAK); 00664 else if (sm->rxResp && (sm->respId == sm->currentId) && 00665 ((sm->respMethod == sm->currentMethod) || 00666 (sm->respMethod == EAP_TYPE_EXPANDED && 00667 sm->respVendor == EAP_VENDOR_IETF && 00668 sm->respVendorMethod == sm->currentMethod))) 00669 SM_ENTER(EAP, INTEGRITY_CHECK); 00670 else { 00671 wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " 00672 "rxResp=%d respId=%d currentId=%d " 00673 "respMethod=%d currentMethod=%d", 00674 sm->rxResp, sm->respId, sm->currentId, 00675 sm->respMethod, sm->currentMethod); 00676 SM_ENTER(EAP, DISCARD); 00677 } 00678 break; 00679 case EAP_DISCARD: 00680 SM_ENTER(EAP, IDLE); 00681 break; 00682 case EAP_SEND_REQUEST: 00683 SM_ENTER(EAP, IDLE); 00684 break; 00685 case EAP_INTEGRITY_CHECK: 00686 if (sm->ignore) 00687 SM_ENTER(EAP, DISCARD); 00688 else 00689 SM_ENTER(EAP, METHOD_RESPONSE); 00690 break; 00691 case EAP_METHOD_REQUEST: 00692 SM_ENTER(EAP, SEND_REQUEST); 00693 break; 00694 case EAP_METHOD_RESPONSE: 00695 /* 00696 * Note: Mechanism to allow EAP methods to wait while going 00697 * through pending processing is an extension to RFC 4137 00698 * which only defines the transits to SELECT_ACTION and 00699 * METHOD_REQUEST from this METHOD_RESPONSE state. 00700 */ 00701 if (sm->methodState == METHOD_END) 00702 SM_ENTER(EAP, SELECT_ACTION); 00703 else if (sm->method_pending == METHOD_PENDING_WAIT) { 00704 wpa_printf(MSG_DEBUG, "EAP: Method has pending " 00705 "processing - wait before proceeding to " 00706 "METHOD_REQUEST state"); 00707 } else if (sm->method_pending == METHOD_PENDING_CONT) { 00708 wpa_printf(MSG_DEBUG, "EAP: Method has completed " 00709 "pending processing - reprocess pending " 00710 "EAP message"); 00711 sm->method_pending = METHOD_PENDING_NONE; 00712 SM_ENTER(EAP, METHOD_RESPONSE); 00713 } else 00714 SM_ENTER(EAP, METHOD_REQUEST); 00715 break; 00716 case EAP_PROPOSE_METHOD: 00717 /* 00718 * Note: Mechanism to allow EAP methods to wait while going 00719 * through pending processing is an extension to RFC 4137 00720 * which only defines the transit to METHOD_REQUEST from this 00721 * PROPOSE_METHOD state. 00722 */ 00723 if (sm->method_pending == METHOD_PENDING_WAIT) { 00724 wpa_printf(MSG_DEBUG, "EAP: Method has pending " 00725 "processing - wait before proceeding to " 00726 "METHOD_REQUEST state"); 00727 if (sm->user_eap_method_index > 0) 00728 sm->user_eap_method_index--; 00729 } else if (sm->method_pending == METHOD_PENDING_CONT) { 00730 wpa_printf(MSG_DEBUG, "EAP: Method has completed " 00731 "pending processing - reprocess pending " 00732 "EAP message"); 00733 sm->method_pending = METHOD_PENDING_NONE; 00734 SM_ENTER(EAP, PROPOSE_METHOD); 00735 } else 00736 SM_ENTER(EAP, METHOD_REQUEST); 00737 break; 00738 case EAP_NAK: 00739 SM_ENTER(EAP, SELECT_ACTION); 00740 break; 00741 case EAP_SELECT_ACTION: 00742 if (sm->decision == DECISION_FAILURE) 00743 SM_ENTER(EAP, FAILURE); 00744 else if (sm->decision == DECISION_SUCCESS) 00745 SM_ENTER(EAP, SUCCESS); 00746 else if (sm->decision == DECISION_PASSTHROUGH) 00747 SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); 00748 else 00749 SM_ENTER(EAP, PROPOSE_METHOD); 00750 break; 00751 case EAP_TIMEOUT_FAILURE: 00752 break; 00753 case EAP_FAILURE: 00754 break; 00755 case EAP_SUCCESS: 00756 break; 00757 00758 case EAP_INITIALIZE_PASSTHROUGH: 00759 if (sm->currentId == -1) 00760 SM_ENTER(EAP, AAA_IDLE); 00761 else 00762 SM_ENTER(EAP, AAA_REQUEST); 00763 break; 00764 case EAP_IDLE2: 00765 if (sm->eap_if.eapResp) 00766 SM_ENTER(EAP, RECEIVED2); 00767 else if (sm->eap_if.retransWhile == 0) 00768 SM_ENTER(EAP, RETRANSMIT2); 00769 break; 00770 case EAP_RETRANSMIT2: 00771 if (sm->retransCount > sm->MaxRetrans) 00772 SM_ENTER(EAP, TIMEOUT_FAILURE2); 00773 else 00774 SM_ENTER(EAP, IDLE2); 00775 break; 00776 case EAP_RECEIVED2: 00777 if (sm->rxResp && (sm->respId == sm->currentId)) 00778 SM_ENTER(EAP, AAA_REQUEST); 00779 else 00780 SM_ENTER(EAP, DISCARD2); 00781 break; 00782 case EAP_DISCARD2: 00783 SM_ENTER(EAP, IDLE2); 00784 break; 00785 case EAP_SEND_REQUEST2: 00786 SM_ENTER(EAP, IDLE2); 00787 break; 00788 case EAP_AAA_REQUEST: 00789 SM_ENTER(EAP, AAA_IDLE); 00790 break; 00791 case EAP_AAA_RESPONSE: 00792 SM_ENTER(EAP, SEND_REQUEST2); 00793 break; 00794 case EAP_AAA_IDLE: 00795 if (sm->eap_if.aaaFail) 00796 SM_ENTER(EAP, FAILURE2); 00797 else if (sm->eap_if.aaaSuccess) 00798 SM_ENTER(EAP, SUCCESS2); 00799 else if (sm->eap_if.aaaEapReq) 00800 SM_ENTER(EAP, AAA_RESPONSE); 00801 else if (sm->eap_if.aaaTimeout) 00802 SM_ENTER(EAP, TIMEOUT_FAILURE2); 00803 break; 00804 case EAP_TIMEOUT_FAILURE2: 00805 break; 00806 case EAP_FAILURE2: 00807 break; 00808 case EAP_SUCCESS2: 00809 break; 00810 } 00811 } 00812 00813 00814 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 00815 int eapSRTT, int eapRTTVAR, 00816 int methodTimeout) 00817 { 00818 int rto, i; 00819 00820 if (methodTimeout) { 00821 /* 00822 * EAP method (either internal or through AAA server, provided 00823 * timeout hint. Use that as-is as a timeout for retransmitting 00824 * the EAP request if no response is received. 00825 */ 00826 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 00827 "(from EAP method hint)", methodTimeout); 00828 return methodTimeout; 00829 } 00830 00831 /* 00832 * RFC 3748 recommends algorithms described in RFC 2988 for estimation 00833 * of the retransmission timeout. This should be implemented once 00834 * round-trip time measurements are available. For nowm a simple 00835 * backoff mechanism is used instead if there are no EAP method 00836 * specific hints. 00837 * 00838 * SRTT = smoothed round-trip time 00839 * RTTVAR = round-trip time variation 00840 * RTO = retransmission timeout 00841 */ 00842 00843 /* 00844 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for 00845 * initial retransmission and then double the RTO to provide back off 00846 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 00847 * modified RTOmax. 00848 */ 00849 rto = 3; 00850 for (i = 0; i < retransCount; i++) { 00851 rto *= 2; 00852 if (rto >= 20) { 00853 rto = 20; 00854 break; 00855 } 00856 } 00857 00858 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 00859 "(from dynamic back off; retransCount=%d)", 00860 rto, retransCount); 00861 00862 return rto; 00863 } 00864 00865 00866 static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) 00867 { 00868 const struct eap_hdr *hdr; 00869 size_t plen; 00870 00871 /* parse rxResp, respId, respMethod */ 00872 sm->rxResp = FALSE; 00873 sm->respId = -1; 00874 sm->respMethod = EAP_TYPE_NONE; 00875 sm->respVendor = EAP_VENDOR_IETF; 00876 sm->respVendorMethod = EAP_TYPE_NONE; 00877 00878 if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { 00879 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " 00880 "len=%lu", resp, 00881 resp ? (unsigned long) wpabuf_len(resp) : 0); 00882 return; 00883 } 00884 00885 hdr = wpabuf_head(resp); 00886 plen = be_to_host16(hdr->length); 00887 if (plen > wpabuf_len(resp)) { 00888 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " 00889 "(len=%lu plen=%lu)", 00890 (unsigned long) wpabuf_len(resp), 00891 (unsigned long) plen); 00892 return; 00893 } 00894 00895 sm->respId = hdr->identifier; 00896 00897 if (hdr->code == EAP_CODE_RESPONSE) 00898 sm->rxResp = TRUE; 00899 00900 if (plen > sizeof(*hdr)) { 00901 u8 *pos = (u8 *) (hdr + 1); 00902 sm->respMethod = *pos++; 00903 if (sm->respMethod == EAP_TYPE_EXPANDED) { 00904 if (plen < sizeof(*hdr) + 8) { 00905 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " 00906 "expanded EAP-Packet (plen=%lu)", 00907 (unsigned long) plen); 00908 return; 00909 } 00910 sm->respVendor = WPA_GET_BE24(pos); 00911 pos += 3; 00912 sm->respVendorMethod = WPA_GET_BE32(pos); 00913 } 00914 } 00915 00916 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " 00917 "respMethod=%u respVendor=%u respVendorMethod=%u", 00918 sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, 00919 sm->respVendorMethod); 00920 } 00921 00922 00923 static int eap_sm_getId(const struct wpabuf *data) 00924 { 00925 const struct eap_hdr *hdr; 00926 00927 if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) 00928 return -1; 00929 00930 hdr = wpabuf_head(data); 00931 wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); 00932 return hdr->identifier; 00933 } 00934 00935 00936 static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) 00937 { 00938 struct wpabuf *msg; 00939 struct eap_hdr *resp; 00940 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); 00941 00942 msg = wpabuf_alloc(sizeof(*resp)); 00943 if (msg == NULL) 00944 return NULL; 00945 resp = wpabuf_put(msg, sizeof(*resp)); 00946 resp->code = EAP_CODE_SUCCESS; 00947 resp->identifier = id; 00948 resp->length = host_to_be16(sizeof(*resp)); 00949 00950 return msg; 00951 } 00952 00953 00954 static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) 00955 { 00956 struct wpabuf *msg; 00957 struct eap_hdr *resp; 00958 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); 00959 00960 msg = wpabuf_alloc(sizeof(*resp)); 00961 if (msg == NULL) 00962 return NULL; 00963 resp = wpabuf_put(msg, sizeof(*resp)); 00964 resp->code = EAP_CODE_FAILURE; 00965 resp->identifier = id; 00966 resp->length = host_to_be16(sizeof(*resp)); 00967 00968 return msg; 00969 } 00970 00971 00972 static int eap_sm_nextId(struct eap_sm *sm, int id) 00973 { 00974 if (id < 0) { 00975 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a 00976 * random number */ 00977 id = rand() & 0xff; 00978 if (id != sm->lastId) 00979 return id; 00980 } 00981 return (id + 1) & 0xff; 00982 } 00983 00984 00994 void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) 00995 { 00996 int i; 00997 size_t j; 00998 00999 if (sm->user == NULL) 01000 return; 01001 01002 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " 01003 "index %d)", sm->user_eap_method_index); 01004 01005 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", 01006 (u8 *) sm->user->methods, 01007 EAP_MAX_METHODS * sizeof(sm->user->methods[0])); 01008 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", 01009 nak_list, len); 01010 01011 i = sm->user_eap_method_index; 01012 while (i < EAP_MAX_METHODS && 01013 (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 01014 sm->user->methods[i].method != EAP_TYPE_NONE)) { 01015 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) 01016 goto not_found; 01017 for (j = 0; j < len; j++) { 01018 if (nak_list[j] == sm->user->methods[i].method) { 01019 break; 01020 } 01021 } 01022 01023 if (j < len) { 01024 /* found */ 01025 i++; 01026 continue; 01027 } 01028 01029 not_found: 01030 /* not found - remove from the list */ 01031 os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1], 01032 (EAP_MAX_METHODS - i - 1) * 01033 sizeof(sm->user->methods[0])); 01034 sm->user->methods[EAP_MAX_METHODS - 1].vendor = 01035 EAP_VENDOR_IETF; 01036 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; 01037 } 01038 01039 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", 01040 (u8 *) sm->user->methods, EAP_MAX_METHODS * 01041 sizeof(sm->user->methods[0])); 01042 } 01043 01044 01045 static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 01046 size_t len) 01047 { 01048 if (nak_list == NULL || sm == NULL || sm->user == NULL) 01049 return; 01050 01051 if (sm->user->phase2) { 01052 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" 01053 " info was selected - reject"); 01054 sm->decision = DECISION_FAILURE; 01055 return; 01056 } 01057 01058 eap_sm_process_nak(sm, nak_list, len); 01059 } 01060 01061 01062 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) 01063 { 01064 EapType next; 01065 int idx = sm->user_eap_method_index; 01066 01067 /* In theory, there should be no problems with starting 01068 * re-authentication with something else than EAP-Request/Identity and 01069 * this does indeed work with wpa_supplicant. However, at least Funk 01070 * Supplicant seemed to ignore re-auth if it skipped 01071 * EAP-Request/Identity. 01072 * Re-auth sets currentId == -1, so that can be used here to select 01073 * whether Identity needs to be requested again. */ 01074 if (sm->identity == NULL || sm->currentId == -1) { 01075 *vendor = EAP_VENDOR_IETF; 01076 next = EAP_TYPE_IDENTITY; 01077 sm->update_user = TRUE; 01078 } else if (sm->user && idx < EAP_MAX_METHODS && 01079 (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || 01080 sm->user->methods[idx].method != EAP_TYPE_NONE)) { 01081 *vendor = sm->user->methods[idx].vendor; 01082 next = sm->user->methods[idx].method; 01083 sm->user_eap_method_index++; 01084 } else { 01085 *vendor = EAP_VENDOR_IETF; 01086 next = EAP_TYPE_NONE; 01087 } 01088 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", 01089 *vendor, next); 01090 return next; 01091 } 01092 01093 01094 static int eap_sm_Policy_getDecision(struct eap_sm *sm) 01095 { 01096 if (!sm->eap_server && sm->identity && !sm->start_reauth) { 01097 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); 01098 return DECISION_PASSTHROUGH; 01099 } 01100 01101 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && 01102 sm->m->isSuccess(sm, sm->eap_method_priv)) { 01103 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " 01104 "SUCCESS"); 01105 sm->update_user = TRUE; 01106 return DECISION_SUCCESS; 01107 } 01108 01109 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && 01110 !sm->m->isSuccess(sm, sm->eap_method_priv)) { 01111 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " 01112 "FAILURE"); 01113 sm->update_user = TRUE; 01114 return DECISION_FAILURE; 01115 } 01116 01117 if ((sm->user == NULL || sm->update_user) && sm->identity && 01118 !sm->start_reauth) { 01119 /* 01120 * Allow Identity method to be started once to allow identity 01121 * selection hint to be sent from the authentication server, 01122 * but prevent a loop of Identity requests by only allowing 01123 * this to happen once. 01124 */ 01125 int id_req = 0; 01126 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && 01127 sm->user->methods[0].vendor == EAP_VENDOR_IETF && 01128 sm->user->methods[0].method == EAP_TYPE_IDENTITY) 01129 id_req = 1; 01130 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { 01131 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " 01132 "found from database -> FAILURE"); 01133 return DECISION_FAILURE; 01134 } 01135 if (id_req && sm->user && 01136 sm->user->methods[0].vendor == EAP_VENDOR_IETF && 01137 sm->user->methods[0].method == EAP_TYPE_IDENTITY) { 01138 wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " 01139 "identity request loop -> FAILURE"); 01140 sm->update_user = TRUE; 01141 return DECISION_FAILURE; 01142 } 01143 sm->update_user = FALSE; 01144 } 01145 sm->start_reauth = FALSE; 01146 01147 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 01148 (sm->user->methods[sm->user_eap_method_index].vendor != 01149 EAP_VENDOR_IETF || 01150 sm->user->methods[sm->user_eap_method_index].method != 01151 EAP_TYPE_NONE)) { 01152 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " 01153 "available -> CONTINUE"); 01154 return DECISION_CONTINUE; 01155 } 01156 01157 if (sm->identity == NULL || sm->currentId == -1) { 01158 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " 01159 "yet -> CONTINUE"); 01160 return DECISION_CONTINUE; 01161 } 01162 01163 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " 01164 "FAILURE"); 01165 return DECISION_FAILURE; 01166 } 01167 01168 01169 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method) 01170 { 01171 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE; 01172 } 01173 01174 01184 int eap_server_sm_step(struct eap_sm *sm) 01185 { 01186 int res = 0; 01187 do { 01188 sm->changed = FALSE; 01189 SM_STEP_RUN(EAP); 01190 if (sm->changed) 01191 res = 1; 01192 } while (sm->changed); 01193 return res; 01194 } 01195 01196 01197 static void eap_user_free(struct eap_user *user) 01198 { 01199 if (user == NULL) 01200 return; 01201 os_free(user->password); 01202 user->password = NULL; 01203 os_free(user); 01204 } 01205 01206 01216 struct eap_sm * eap_server_sm_init(void *eapol_ctx, 01217 struct eapol_callbacks *eapol_cb, 01218 struct eap_config *conf) 01219 { 01220 struct eap_sm *sm; 01221 01222 sm = os_zalloc(sizeof(*sm)); 01223 if (sm == NULL) 01224 return NULL; 01225 sm->eapol_ctx = eapol_ctx; 01226 sm->eapol_cb = eapol_cb; 01227 sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ 01228 sm->ssl_ctx = conf->ssl_ctx; 01229 sm->msg_ctx = conf->msg_ctx; 01230 sm->eap_sim_db_priv = conf->eap_sim_db_priv; 01231 sm->backend_auth = conf->backend_auth; 01232 sm->eap_server = conf->eap_server; 01233 if (conf->pac_opaque_encr_key) { 01234 sm->pac_opaque_encr_key = os_malloc(16); 01235 if (sm->pac_opaque_encr_key) { 01236 os_memcpy(sm->pac_opaque_encr_key, 01237 conf->pac_opaque_encr_key, 16); 01238 } 01239 } 01240 if (conf->eap_fast_a_id) { 01241 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 01242 if (sm->eap_fast_a_id) { 01243 os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id, 01244 conf->eap_fast_a_id_len); 01245 sm->eap_fast_a_id_len = conf->eap_fast_a_id_len; 01246 } 01247 } 01248 if (conf->eap_fast_a_id_info) 01249 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 01250 sm->eap_fast_prov = conf->eap_fast_prov; 01251 sm->pac_key_lifetime = conf->pac_key_lifetime; 01252 sm->pac_key_refresh_time = conf->pac_key_refresh_time; 01253 sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 01254 sm->tnc = conf->tnc; 01255 sm->wps = conf->wps; 01256 if (conf->assoc_wps_ie) 01257 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); 01258 if (conf->peer_addr) 01259 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); 01260 01261 wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); 01262 01263 return sm; 01264 } 01265 01266 01274 void eap_server_sm_deinit(struct eap_sm *sm) 01275 { 01276 if (sm == NULL) 01277 return; 01278 wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); 01279 if (sm->m && sm->eap_method_priv) 01280 sm->m->reset(sm, sm->eap_method_priv); 01281 wpabuf_free(sm->eap_if.eapReqData); 01282 os_free(sm->eap_if.eapKeyData); 01283 wpabuf_free(sm->lastReqData); 01284 wpabuf_free(sm->eap_if.eapRespData); 01285 os_free(sm->identity); 01286 os_free(sm->pac_opaque_encr_key); 01287 os_free(sm->eap_fast_a_id); 01288 os_free(sm->eap_fast_a_id_info); 01289 wpabuf_free(sm->eap_if.aaaEapReqData); 01290 wpabuf_free(sm->eap_if.aaaEapRespData); 01291 os_free(sm->eap_if.aaaEapKeyData); 01292 eap_user_free(sm->user); 01293 wpabuf_free(sm->assoc_wps_ie); 01294 os_free(sm); 01295 } 01296 01297 01305 void eap_sm_notify_cached(struct eap_sm *sm) 01306 { 01307 if (sm == NULL) 01308 return; 01309 01310 sm->EAP_state = EAP_SUCCESS; 01311 } 01312 01313 01320 void eap_sm_pending_cb(struct eap_sm *sm) 01321 { 01322 if (sm == NULL) 01323 return; 01324 wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); 01325 if (sm->method_pending == METHOD_PENDING_WAIT) 01326 sm->method_pending = METHOD_PENDING_CONT; 01327 } 01328 01329 01335 int eap_sm_method_pending(struct eap_sm *sm) 01336 { 01337 if (sm == NULL) 01338 return 0; 01339 return sm->method_pending == METHOD_PENDING_WAIT; 01340 } 01341 01342 01349 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) 01350 { 01351 *len = sm->identity_len; 01352 return sm->identity; 01353 } 01354 01355 01361 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) 01362 { 01363 return &sm->eap_if; 01364 }