1/* 2 * hostapd / EAP Full Authenticator state machine (RFC 4137) 3 * Copyright (c) 2004-2007, 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 * This state machine is based on the full authenticator state machine defined 9 * in RFC 4137. However, to support backend authentication in RADIUS 10 * authentication server functionality, parts of backend authenticator (also 11 * from RFC 4137) are mixed in. This functionality is enabled by setting 12 * backend_auth configuration variable to TRUE. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "eap_i.h" 19#include "state_machine.h" 20#include "common/wpa_ctrl.h" 21 22#define STATE_MACHINE_DATA struct eap_sm 23#define STATE_MACHINE_DEBUG_PREFIX "EAP" 24 25#define EAP_MAX_AUTH_ROUNDS 50 26 27static void eap_user_free(struct eap_user *user); 28 29 30/* EAP state machines are described in RFC 4137 */ 31 32static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 33 int eapSRTT, int eapRTTVAR, 34 int methodTimeout); 35static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); 36static int eap_sm_getId(const struct wpabuf *data); 37static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); 38static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); 39static int eap_sm_nextId(struct eap_sm *sm, int id); 40static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 41 size_t len); 42static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor); 43static int eap_sm_Policy_getDecision(struct eap_sm *sm); 44static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method); 45 46 47static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) 48{ 49 if (src == NULL) 50 return -1; 51 52 wpabuf_free(*dst); 53 *dst = wpabuf_dup(src); 54 return *dst ? 0 : -1; 55} 56 57 58static int eap_copy_data(u8 **dst, size_t *dst_len, 59 const u8 *src, size_t src_len) 60{ 61 if (src == NULL) 62 return -1; 63 64 os_free(*dst); 65 *dst = os_malloc(src_len); 66 if (*dst) { 67 os_memcpy(*dst, src, src_len); 68 *dst_len = src_len; 69 return 0; 70 } else { 71 *dst_len = 0; 72 return -1; 73 } 74} 75 76#define EAP_COPY(dst, src) \ 77 eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) 78 79 80/** 81 * eap_user_get - Fetch user information from the database 82 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 83 * @identity: Identity (User-Name) of the user 84 * @identity_len: Length of identity in bytes 85 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user 86 * Returns: 0 on success, or -1 on failure 87 * 88 * This function is used to fetch user information for EAP. The user will be 89 * selected based on the specified identity. sm->user and 90 * sm->user_eap_method_index are updated for the new user when a matching user 91 * is found. sm->user can be used to get user information (e.g., password). 92 */ 93int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, 94 int phase2) 95{ 96 struct eap_user *user; 97 98 if (sm == NULL || sm->eapol_cb == NULL || 99 sm->eapol_cb->get_eap_user == NULL) 100 return -1; 101 102 eap_user_free(sm->user); 103 sm->user = NULL; 104 105 user = os_zalloc(sizeof(*user)); 106 if (user == NULL) 107 return -1; 108 109 if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, 110 identity_len, phase2, user) != 0) { 111 eap_user_free(user); 112 return -1; 113 } 114 115 sm->user = user; 116 sm->user_eap_method_index = 0; 117 118 return 0; 119} 120 121 122SM_STATE(EAP, DISABLED) 123{ 124 SM_ENTRY(EAP, DISABLED); 125 sm->num_rounds = 0; 126} 127 128 129SM_STATE(EAP, INITIALIZE) 130{ 131 SM_ENTRY(EAP, INITIALIZE); 132 133 if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) { 134 /* 135 * Need to allow internal Identity method to be used instead 136 * of passthrough at the beginning of reauthentication. 137 */ 138 eap_server_clear_identity(sm); 139 } 140 141 sm->currentId = -1; 142 sm->eap_if.eapSuccess = FALSE; 143 sm->eap_if.eapFail = FALSE; 144 sm->eap_if.eapTimeout = FALSE; 145 os_free(sm->eap_if.eapKeyData); 146 sm->eap_if.eapKeyData = NULL; 147 sm->eap_if.eapKeyDataLen = 0; 148 sm->eap_if.eapKeyAvailable = FALSE; 149 sm->eap_if.eapRestart = FALSE; 150 151 /* 152 * This is not defined in RFC 4137, but method state needs to be 153 * reseted here so that it does not remain in success state when 154 * re-authentication starts. 155 */ 156 if (sm->m && sm->eap_method_priv) { 157 sm->m->reset(sm, sm->eap_method_priv); 158 sm->eap_method_priv = NULL; 159 } 160 sm->m = NULL; 161 sm->user_eap_method_index = 0; 162 163 if (sm->backend_auth) { 164 sm->currentMethod = EAP_TYPE_NONE; 165 /* parse rxResp, respId, respMethod */ 166 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 167 if (sm->rxResp) { 168 sm->currentId = sm->respId; 169 } 170 } 171 sm->num_rounds = 0; 172 sm->method_pending = METHOD_PENDING_NONE; 173 174 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED 175 MACSTR, MAC2STR(sm->peer_addr)); 176} 177 178 179SM_STATE(EAP, PICK_UP_METHOD) 180{ 181 SM_ENTRY(EAP, PICK_UP_METHOD); 182 183 if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { 184 sm->currentMethod = sm->respMethod; 185 if (sm->m && sm->eap_method_priv) { 186 sm->m->reset(sm, sm->eap_method_priv); 187 sm->eap_method_priv = NULL; 188 } 189 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, 190 sm->currentMethod); 191 if (sm->m && sm->m->initPickUp) { 192 sm->eap_method_priv = sm->m->initPickUp(sm); 193 if (sm->eap_method_priv == NULL) { 194 wpa_printf(MSG_DEBUG, "EAP: Failed to " 195 "initialize EAP method %d", 196 sm->currentMethod); 197 sm->m = NULL; 198 sm->currentMethod = EAP_TYPE_NONE; 199 } 200 } else { 201 sm->m = NULL; 202 sm->currentMethod = EAP_TYPE_NONE; 203 } 204 } 205 206 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 207 "method=%u", sm->currentMethod); 208} 209 210 211SM_STATE(EAP, IDLE) 212{ 213 SM_ENTRY(EAP, IDLE); 214 215 sm->eap_if.retransWhile = eap_sm_calculateTimeout( 216 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 217 sm->methodTimeout); 218} 219 220 221SM_STATE(EAP, RETRANSMIT) 222{ 223 SM_ENTRY(EAP, RETRANSMIT); 224 225 sm->retransCount++; 226 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 227 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 228 sm->eap_if.eapReq = TRUE; 229 } 230} 231 232 233SM_STATE(EAP, RECEIVED) 234{ 235 SM_ENTRY(EAP, RECEIVED); 236 237 /* parse rxResp, respId, respMethod */ 238 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 239 sm->num_rounds++; 240} 241 242 243SM_STATE(EAP, DISCARD) 244{ 245 SM_ENTRY(EAP, DISCARD); 246 sm->eap_if.eapResp = FALSE; 247 sm->eap_if.eapNoReq = TRUE; 248} 249 250 251SM_STATE(EAP, SEND_REQUEST) 252{ 253 SM_ENTRY(EAP, SEND_REQUEST); 254 255 sm->retransCount = 0; 256 if (sm->eap_if.eapReqData) { 257 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 258 { 259 sm->eap_if.eapResp = FALSE; 260 sm->eap_if.eapReq = TRUE; 261 } else { 262 sm->eap_if.eapResp = FALSE; 263 sm->eap_if.eapReq = FALSE; 264 } 265 } else { 266 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); 267 sm->eap_if.eapResp = FALSE; 268 sm->eap_if.eapReq = FALSE; 269 sm->eap_if.eapNoReq = TRUE; 270 } 271} 272 273 274SM_STATE(EAP, INTEGRITY_CHECK) 275{ 276 SM_ENTRY(EAP, INTEGRITY_CHECK); 277 278 if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) { 279 sm->ignore = TRUE; 280 return; 281 } 282 283 if (sm->m->check) { 284 sm->ignore = sm->m->check(sm, sm->eap_method_priv, 285 sm->eap_if.eapRespData); 286 } 287} 288 289 290SM_STATE(EAP, METHOD_REQUEST) 291{ 292 SM_ENTRY(EAP, METHOD_REQUEST); 293 294 if (sm->m == NULL) { 295 wpa_printf(MSG_DEBUG, "EAP: method not initialized"); 296 return; 297 } 298 299 sm->currentId = eap_sm_nextId(sm, sm->currentId); 300 wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", 301 sm->currentId); 302 sm->lastId = sm->currentId; 303 wpabuf_free(sm->eap_if.eapReqData); 304 sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, 305 sm->currentId); 306 if (sm->m->getTimeout) 307 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); 308 else 309 sm->methodTimeout = 0; 310} 311 312 313SM_STATE(EAP, METHOD_RESPONSE) 314{ 315 SM_ENTRY(EAP, METHOD_RESPONSE); 316 317 if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) 318 return; 319 320 sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); 321 if (sm->m->isDone(sm, sm->eap_method_priv)) { 322 eap_sm_Policy_update(sm, NULL, 0); 323 os_free(sm->eap_if.eapKeyData); 324 if (sm->m->getKey) { 325 sm->eap_if.eapKeyData = sm->m->getKey( 326 sm, sm->eap_method_priv, 327 &sm->eap_if.eapKeyDataLen); 328 } else { 329 sm->eap_if.eapKeyData = NULL; 330 sm->eap_if.eapKeyDataLen = 0; 331 } 332 sm->methodState = METHOD_END; 333 } else { 334 sm->methodState = METHOD_CONTINUE; 335 } 336} 337 338 339SM_STATE(EAP, PROPOSE_METHOD) 340{ 341 int vendor; 342 EapType type; 343 344 SM_ENTRY(EAP, PROPOSE_METHOD); 345 346 type = eap_sm_Policy_getNextMethod(sm, &vendor); 347 if (vendor == EAP_VENDOR_IETF) 348 sm->currentMethod = type; 349 else 350 sm->currentMethod = EAP_TYPE_EXPANDED; 351 if (sm->m && sm->eap_method_priv) { 352 sm->m->reset(sm, sm->eap_method_priv); 353 sm->eap_method_priv = NULL; 354 } 355 sm->m = eap_server_get_eap_method(vendor, type); 356 if (sm->m) { 357 sm->eap_method_priv = sm->m->init(sm); 358 if (sm->eap_method_priv == NULL) { 359 wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " 360 "method %d", sm->currentMethod); 361 sm->m = NULL; 362 sm->currentMethod = EAP_TYPE_NONE; 363 } 364 } 365 if (sm->currentMethod == EAP_TYPE_IDENTITY || 366 sm->currentMethod == EAP_TYPE_NOTIFICATION) 367 sm->methodState = METHOD_CONTINUE; 368 else 369 sm->methodState = METHOD_PROPOSED; 370 371 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 372 "vendor=%u method=%u", vendor, sm->currentMethod); 373} 374 375 376SM_STATE(EAP, NAK) 377{ 378 const struct eap_hdr *nak; 379 size_t len = 0; 380 const u8 *pos; 381 const u8 *nak_list = NULL; 382 383 SM_ENTRY(EAP, NAK); 384 385 if (sm->eap_method_priv) { 386 sm->m->reset(sm, sm->eap_method_priv); 387 sm->eap_method_priv = NULL; 388 } 389 sm->m = NULL; 390 391 if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) 392 return; 393 394 nak = wpabuf_head(sm->eap_if.eapRespData); 395 if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { 396 len = be_to_host16(nak->length); 397 if (len > wpabuf_len(sm->eap_if.eapRespData)) 398 len = wpabuf_len(sm->eap_if.eapRespData); 399 pos = (const u8 *) (nak + 1); 400 len -= sizeof(*nak); 401 if (*pos == EAP_TYPE_NAK) { 402 pos++; 403 len--; 404 nak_list = pos; 405 } 406 } 407 eap_sm_Policy_update(sm, nak_list, len); 408} 409 410 411SM_STATE(EAP, SELECT_ACTION) 412{ 413 SM_ENTRY(EAP, SELECT_ACTION); 414 415 sm->decision = eap_sm_Policy_getDecision(sm); 416} 417 418 419SM_STATE(EAP, TIMEOUT_FAILURE) 420{ 421 SM_ENTRY(EAP, TIMEOUT_FAILURE); 422 423 sm->eap_if.eapTimeout = TRUE; 424} 425 426 427SM_STATE(EAP, FAILURE) 428{ 429 SM_ENTRY(EAP, FAILURE); 430 431 wpabuf_free(sm->eap_if.eapReqData); 432 sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); 433 wpabuf_free(sm->lastReqData); 434 sm->lastReqData = NULL; 435 sm->eap_if.eapFail = TRUE; 436 437 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE 438 MACSTR, MAC2STR(sm->peer_addr)); 439} 440 441 442SM_STATE(EAP, SUCCESS) 443{ 444 SM_ENTRY(EAP, SUCCESS); 445 446 wpabuf_free(sm->eap_if.eapReqData); 447 sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); 448 wpabuf_free(sm->lastReqData); 449 sm->lastReqData = NULL; 450 if (sm->eap_if.eapKeyData) 451 sm->eap_if.eapKeyAvailable = TRUE; 452 sm->eap_if.eapSuccess = TRUE; 453 454 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS 455 MACSTR, MAC2STR(sm->peer_addr)); 456} 457 458 459SM_STATE(EAP, INITIALIZE_PASSTHROUGH) 460{ 461 SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); 462 463 wpabuf_free(sm->eap_if.aaaEapRespData); 464 sm->eap_if.aaaEapRespData = NULL; 465} 466 467 468SM_STATE(EAP, IDLE2) 469{ 470 SM_ENTRY(EAP, IDLE2); 471 472 sm->eap_if.retransWhile = eap_sm_calculateTimeout( 473 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 474 sm->methodTimeout); 475} 476 477 478SM_STATE(EAP, RETRANSMIT2) 479{ 480 SM_ENTRY(EAP, RETRANSMIT2); 481 482 sm->retransCount++; 483 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 484 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 485 sm->eap_if.eapReq = TRUE; 486 } 487} 488 489 490SM_STATE(EAP, RECEIVED2) 491{ 492 SM_ENTRY(EAP, RECEIVED2); 493 494 /* parse rxResp, respId, respMethod */ 495 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 496} 497 498 499SM_STATE(EAP, DISCARD2) 500{ 501 SM_ENTRY(EAP, DISCARD2); 502 sm->eap_if.eapResp = FALSE; 503 sm->eap_if.eapNoReq = TRUE; 504} 505 506 507SM_STATE(EAP, SEND_REQUEST2) 508{ 509 SM_ENTRY(EAP, SEND_REQUEST2); 510 511 sm->retransCount = 0; 512 if (sm->eap_if.eapReqData) { 513 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 514 { 515 sm->eap_if.eapResp = FALSE; 516 sm->eap_if.eapReq = TRUE; 517 } else { 518 sm->eap_if.eapResp = FALSE; 519 sm->eap_if.eapReq = FALSE; 520 } 521 } else { 522 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); 523 sm->eap_if.eapResp = FALSE; 524 sm->eap_if.eapReq = FALSE; 525 sm->eap_if.eapNoReq = TRUE; 526 } 527} 528 529 530SM_STATE(EAP, AAA_REQUEST) 531{ 532 SM_ENTRY(EAP, AAA_REQUEST); 533 534 if (sm->eap_if.eapRespData == NULL) { 535 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); 536 return; 537 } 538 539 /* 540 * if (respMethod == IDENTITY) 541 * aaaIdentity = eapRespData 542 * This is already taken care of by the EAP-Identity method which 543 * stores the identity into sm->identity. 544 */ 545 546 eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); 547} 548 549 550SM_STATE(EAP, AAA_RESPONSE) 551{ 552 SM_ENTRY(EAP, AAA_RESPONSE); 553 554 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 555 sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); 556 sm->methodTimeout = sm->eap_if.aaaMethodTimeout; 557} 558 559 560SM_STATE(EAP, AAA_IDLE) 561{ 562 SM_ENTRY(EAP, AAA_IDLE); 563 564 sm->eap_if.aaaFail = FALSE; 565 sm->eap_if.aaaSuccess = FALSE; 566 sm->eap_if.aaaEapReq = FALSE; 567 sm->eap_if.aaaEapNoReq = FALSE; 568 sm->eap_if.aaaEapResp = TRUE; 569} 570 571 572SM_STATE(EAP, TIMEOUT_FAILURE2) 573{ 574 SM_ENTRY(EAP, TIMEOUT_FAILURE2); 575 576 sm->eap_if.eapTimeout = TRUE; 577} 578 579 580SM_STATE(EAP, FAILURE2) 581{ 582 SM_ENTRY(EAP, FAILURE2); 583 584 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 585 sm->eap_if.eapFail = TRUE; 586} 587 588 589SM_STATE(EAP, SUCCESS2) 590{ 591 SM_ENTRY(EAP, SUCCESS2); 592 593 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 594 595 sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; 596 if (sm->eap_if.aaaEapKeyAvailable) { 597 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); 598 } else { 599 os_free(sm->eap_if.eapKeyData); 600 sm->eap_if.eapKeyData = NULL; 601 sm->eap_if.eapKeyDataLen = 0; 602 } 603 604 sm->eap_if.eapSuccess = TRUE; 605 606 /* 607 * Start reauthentication with identity request even though we know the 608 * previously used identity. This is needed to get reauthentication 609 * started properly. 610 */ 611 sm->start_reauth = TRUE; 612} 613 614 615SM_STEP(EAP) 616{ 617 if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) 618 SM_ENTER_GLOBAL(EAP, INITIALIZE); 619 else if (!sm->eap_if.portEnabled) 620 SM_ENTER_GLOBAL(EAP, DISABLED); 621 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { 622 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { 623 wpa_printf(MSG_DEBUG, "EAP: more than %d " 624 "authentication rounds - abort", 625 EAP_MAX_AUTH_ROUNDS); 626 sm->num_rounds++; 627 SM_ENTER_GLOBAL(EAP, FAILURE); 628 } 629 } else switch (sm->EAP_state) { 630 case EAP_INITIALIZE: 631 if (sm->backend_auth) { 632 if (!sm->rxResp) 633 SM_ENTER(EAP, SELECT_ACTION); 634 else if (sm->rxResp && 635 (sm->respMethod == EAP_TYPE_NAK || 636 (sm->respMethod == EAP_TYPE_EXPANDED && 637 sm->respVendor == EAP_VENDOR_IETF && 638 sm->respVendorMethod == EAP_TYPE_NAK))) 639 SM_ENTER(EAP, NAK); 640 else 641 SM_ENTER(EAP, PICK_UP_METHOD); 642 } else { 643 SM_ENTER(EAP, SELECT_ACTION); 644 } 645 break; 646 case EAP_PICK_UP_METHOD: 647 if (sm->currentMethod == EAP_TYPE_NONE) { 648 SM_ENTER(EAP, SELECT_ACTION); 649 } else { 650 SM_ENTER(EAP, METHOD_RESPONSE); 651 } 652 break; 653 case EAP_DISABLED: 654 if (sm->eap_if.portEnabled) 655 SM_ENTER(EAP, INITIALIZE); 656 break; 657 case EAP_IDLE: 658 if (sm->eap_if.retransWhile == 0) 659 SM_ENTER(EAP, RETRANSMIT); 660 else if (sm->eap_if.eapResp) 661 SM_ENTER(EAP, RECEIVED); 662 break; 663 case EAP_RETRANSMIT: 664 if (sm->retransCount > sm->MaxRetrans) 665 SM_ENTER(EAP, TIMEOUT_FAILURE); 666 else 667 SM_ENTER(EAP, IDLE); 668 break; 669 case EAP_RECEIVED: 670 if (sm->rxResp && (sm->respId == sm->currentId) && 671 (sm->respMethod == EAP_TYPE_NAK || 672 (sm->respMethod == EAP_TYPE_EXPANDED && 673 sm->respVendor == EAP_VENDOR_IETF && 674 sm->respVendorMethod == EAP_TYPE_NAK)) 675 && (sm->methodState == METHOD_PROPOSED)) 676 SM_ENTER(EAP, NAK); 677 else if (sm->rxResp && (sm->respId == sm->currentId) && 678 ((sm->respMethod == sm->currentMethod) || 679 (sm->respMethod == EAP_TYPE_EXPANDED && 680 sm->respVendor == EAP_VENDOR_IETF && 681 sm->respVendorMethod == sm->currentMethod))) 682 SM_ENTER(EAP, INTEGRITY_CHECK); 683 else { 684 wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " 685 "rxResp=%d respId=%d currentId=%d " 686 "respMethod=%d currentMethod=%d", 687 sm->rxResp, sm->respId, sm->currentId, 688 sm->respMethod, sm->currentMethod); 689 SM_ENTER(EAP, DISCARD); 690 } 691 break; 692 case EAP_DISCARD: 693 SM_ENTER(EAP, IDLE); 694 break; 695 case EAP_SEND_REQUEST: 696 SM_ENTER(EAP, IDLE); 697 break; 698 case EAP_INTEGRITY_CHECK: 699 if (sm->ignore) 700 SM_ENTER(EAP, DISCARD); 701 else 702 SM_ENTER(EAP, METHOD_RESPONSE); 703 break; 704 case EAP_METHOD_REQUEST: 705 SM_ENTER(EAP, SEND_REQUEST); 706 break; 707 case EAP_METHOD_RESPONSE: 708 /* 709 * Note: Mechanism to allow EAP methods to wait while going 710 * through pending processing is an extension to RFC 4137 711 * which only defines the transits to SELECT_ACTION and 712 * METHOD_REQUEST from this METHOD_RESPONSE state. 713 */ 714 if (sm->methodState == METHOD_END) 715 SM_ENTER(EAP, SELECT_ACTION); 716 else if (sm->method_pending == METHOD_PENDING_WAIT) { 717 wpa_printf(MSG_DEBUG, "EAP: Method has pending " 718 "processing - wait before proceeding to " 719 "METHOD_REQUEST state"); 720 } else if (sm->method_pending == METHOD_PENDING_CONT) { 721 wpa_printf(MSG_DEBUG, "EAP: Method has completed " 722 "pending processing - reprocess pending " 723 "EAP message"); 724 sm->method_pending = METHOD_PENDING_NONE; 725 SM_ENTER(EAP, METHOD_RESPONSE); 726 } else 727 SM_ENTER(EAP, METHOD_REQUEST); 728 break; 729 case EAP_PROPOSE_METHOD: 730 /* 731 * Note: Mechanism to allow EAP methods to wait while going 732 * through pending processing is an extension to RFC 4137 733 * which only defines the transit to METHOD_REQUEST from this 734 * PROPOSE_METHOD state. 735 */ 736 if (sm->method_pending == METHOD_PENDING_WAIT) { 737 wpa_printf(MSG_DEBUG, "EAP: Method has pending " 738 "processing - wait before proceeding to " 739 "METHOD_REQUEST state"); 740 if (sm->user_eap_method_index > 0) 741 sm->user_eap_method_index--; 742 } else if (sm->method_pending == METHOD_PENDING_CONT) { 743 wpa_printf(MSG_DEBUG, "EAP: Method has completed " 744 "pending processing - reprocess pending " 745 "EAP message"); 746 sm->method_pending = METHOD_PENDING_NONE; 747 SM_ENTER(EAP, PROPOSE_METHOD); 748 } else 749 SM_ENTER(EAP, METHOD_REQUEST); 750 break; 751 case EAP_NAK: 752 SM_ENTER(EAP, SELECT_ACTION); 753 break; 754 case EAP_SELECT_ACTION: 755 if (sm->decision == DECISION_FAILURE) 756 SM_ENTER(EAP, FAILURE); 757 else if (sm->decision == DECISION_SUCCESS) 758 SM_ENTER(EAP, SUCCESS); 759 else if (sm->decision == DECISION_PASSTHROUGH) 760 SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); 761 else 762 SM_ENTER(EAP, PROPOSE_METHOD); 763 break; 764 case EAP_TIMEOUT_FAILURE: 765 break; 766 case EAP_FAILURE: 767 break; 768 case EAP_SUCCESS: 769 break; 770 771 case EAP_INITIALIZE_PASSTHROUGH: 772 if (sm->currentId == -1) 773 SM_ENTER(EAP, AAA_IDLE); 774 else 775 SM_ENTER(EAP, AAA_REQUEST); 776 break; 777 case EAP_IDLE2: 778 if (sm->eap_if.eapResp) 779 SM_ENTER(EAP, RECEIVED2); 780 else if (sm->eap_if.retransWhile == 0) 781 SM_ENTER(EAP, RETRANSMIT2); 782 break; 783 case EAP_RETRANSMIT2: 784 if (sm->retransCount > sm->MaxRetrans) 785 SM_ENTER(EAP, TIMEOUT_FAILURE2); 786 else 787 SM_ENTER(EAP, IDLE2); 788 break; 789 case EAP_RECEIVED2: 790 if (sm->rxResp && (sm->respId == sm->currentId)) 791 SM_ENTER(EAP, AAA_REQUEST); 792 else 793 SM_ENTER(EAP, DISCARD2); 794 break; 795 case EAP_DISCARD2: 796 SM_ENTER(EAP, IDLE2); 797 break; 798 case EAP_SEND_REQUEST2: 799 SM_ENTER(EAP, IDLE2); 800 break; 801 case EAP_AAA_REQUEST: 802 SM_ENTER(EAP, AAA_IDLE); 803 break; 804 case EAP_AAA_RESPONSE: 805 SM_ENTER(EAP, SEND_REQUEST2); 806 break; 807 case EAP_AAA_IDLE: 808 if (sm->eap_if.aaaFail) 809 SM_ENTER(EAP, FAILURE2); 810 else if (sm->eap_if.aaaSuccess) 811 SM_ENTER(EAP, SUCCESS2); 812 else if (sm->eap_if.aaaEapReq) 813 SM_ENTER(EAP, AAA_RESPONSE); 814 else if (sm->eap_if.aaaTimeout) 815 SM_ENTER(EAP, TIMEOUT_FAILURE2); 816 break; 817 case EAP_TIMEOUT_FAILURE2: 818 break; 819 case EAP_FAILURE2: 820 break; 821 case EAP_SUCCESS2: 822 break; 823 } 824} 825 826 827static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 828 int eapSRTT, int eapRTTVAR, 829 int methodTimeout) 830{ 831 int rto, i; 832 833 if (methodTimeout) { 834 /* 835 * EAP method (either internal or through AAA server, provided 836 * timeout hint. Use that as-is as a timeout for retransmitting 837 * the EAP request if no response is received. 838 */ 839 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 840 "(from EAP method hint)", methodTimeout); 841 return methodTimeout; 842 } 843 844 /* 845 * RFC 3748 recommends algorithms described in RFC 2988 for estimation 846 * of the retransmission timeout. This should be implemented once 847 * round-trip time measurements are available. For nowm a simple 848 * backoff mechanism is used instead if there are no EAP method 849 * specific hints. 850 * 851 * SRTT = smoothed round-trip time 852 * RTTVAR = round-trip time variation 853 * RTO = retransmission timeout 854 */ 855 856 /* 857 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for 858 * initial retransmission and then double the RTO to provide back off 859 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 860 * modified RTOmax. 861 */ 862 rto = 3; 863 for (i = 0; i < retransCount; i++) { 864 rto *= 2; 865 if (rto >= 20) { 866 rto = 20; 867 break; 868 } 869 } 870 871 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 872 "(from dynamic back off; retransCount=%d)", 873 rto, retransCount); 874 875 return rto; 876} 877 878 879static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) 880{ 881 const struct eap_hdr *hdr; 882 size_t plen; 883 884 /* parse rxResp, respId, respMethod */ 885 sm->rxResp = FALSE; 886 sm->respId = -1; 887 sm->respMethod = EAP_TYPE_NONE; 888 sm->respVendor = EAP_VENDOR_IETF; 889 sm->respVendorMethod = EAP_TYPE_NONE; 890 891 if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { 892 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " 893 "len=%lu", resp, 894 resp ? (unsigned long) wpabuf_len(resp) : 0); 895 return; 896 } 897 898 hdr = wpabuf_head(resp); 899 plen = be_to_host16(hdr->length); 900 if (plen > wpabuf_len(resp)) { 901 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " 902 "(len=%lu plen=%lu)", 903 (unsigned long) wpabuf_len(resp), 904 (unsigned long) plen); 905 return; 906 } 907 908 sm->respId = hdr->identifier; 909 910 if (hdr->code == EAP_CODE_RESPONSE) 911 sm->rxResp = TRUE; 912 913 if (plen > sizeof(*hdr)) { 914 u8 *pos = (u8 *) (hdr + 1); 915 sm->respMethod = *pos++; 916 if (sm->respMethod == EAP_TYPE_EXPANDED) { 917 if (plen < sizeof(*hdr) + 8) { 918 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " 919 "expanded EAP-Packet (plen=%lu)", 920 (unsigned long) plen); 921 return; 922 } 923 sm->respVendor = WPA_GET_BE24(pos); 924 pos += 3; 925 sm->respVendorMethod = WPA_GET_BE32(pos); 926 } 927 } 928 929 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " 930 "respMethod=%u respVendor=%u respVendorMethod=%u", 931 sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, 932 sm->respVendorMethod); 933} 934 935 936static int eap_sm_getId(const struct wpabuf *data) 937{ 938 const struct eap_hdr *hdr; 939 940 if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) 941 return -1; 942 943 hdr = wpabuf_head(data); 944 wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); 945 return hdr->identifier; 946} 947 948 949static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) 950{ 951 struct wpabuf *msg; 952 struct eap_hdr *resp; 953 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); 954 955 msg = wpabuf_alloc(sizeof(*resp)); 956 if (msg == NULL) 957 return NULL; 958 resp = wpabuf_put(msg, sizeof(*resp)); 959 resp->code = EAP_CODE_SUCCESS; 960 resp->identifier = id; 961 resp->length = host_to_be16(sizeof(*resp)); 962 963 return msg; 964} 965 966 967static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) 968{ 969 struct wpabuf *msg; 970 struct eap_hdr *resp; 971 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); 972 973 msg = wpabuf_alloc(sizeof(*resp)); 974 if (msg == NULL) 975 return NULL; 976 resp = wpabuf_put(msg, sizeof(*resp)); 977 resp->code = EAP_CODE_FAILURE; 978 resp->identifier = id; 979 resp->length = host_to_be16(sizeof(*resp)); 980 981 return msg; 982} 983 984 985static int eap_sm_nextId(struct eap_sm *sm, int id) 986{ 987 if (id < 0) { 988 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a 989 * random number */ 990 id = rand() & 0xff; 991 if (id != sm->lastId) 992 return id; 993 } 994 return (id + 1) & 0xff; 995} 996 997 998/** 999 * eap_sm_process_nak - Process EAP-Response/Nak 1000 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1001 * @nak_list: Nak list (allowed methods) from the supplicant 1002 * @len: Length of nak_list in bytes 1003 * 1004 * This function is called when EAP-Response/Nak is received from the 1005 * supplicant. This can happen for both phase 1 and phase 2 authentications. 1006 */ 1007void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) 1008{ 1009 int i; 1010 size_t j; 1011 1012 if (sm->user == NULL) 1013 return; 1014 1015 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " 1016 "index %d)", sm->user_eap_method_index); 1017 1018 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", 1019 (u8 *) sm->user->methods, 1020 EAP_MAX_METHODS * sizeof(sm->user->methods[0])); 1021 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", 1022 nak_list, len); 1023 1024 i = sm->user_eap_method_index; 1025 while (i < EAP_MAX_METHODS && 1026 (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 1027 sm->user->methods[i].method != EAP_TYPE_NONE)) { 1028 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) 1029 goto not_found; 1030 for (j = 0; j < len; j++) { 1031 if (nak_list[j] == sm->user->methods[i].method) { 1032 break; 1033 } 1034 } 1035 1036 if (j < len) { 1037 /* found */ 1038 i++; 1039 continue; 1040 } 1041 1042 not_found: 1043 /* not found - remove from the list */ 1044 if (i + 1 < EAP_MAX_METHODS) { 1045 os_memmove(&sm->user->methods[i], 1046 &sm->user->methods[i + 1], 1047 (EAP_MAX_METHODS - i - 1) * 1048 sizeof(sm->user->methods[0])); 1049 } 1050 sm->user->methods[EAP_MAX_METHODS - 1].vendor = 1051 EAP_VENDOR_IETF; 1052 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; 1053 } 1054 1055 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", 1056 (u8 *) sm->user->methods, EAP_MAX_METHODS * 1057 sizeof(sm->user->methods[0])); 1058} 1059 1060 1061static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 1062 size_t len) 1063{ 1064 if (nak_list == NULL || sm == NULL || sm->user == NULL) 1065 return; 1066 1067 if (sm->user->phase2) { 1068 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" 1069 " info was selected - reject"); 1070 sm->decision = DECISION_FAILURE; 1071 return; 1072 } 1073 1074 eap_sm_process_nak(sm, nak_list, len); 1075} 1076 1077 1078static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) 1079{ 1080 EapType next; 1081 int idx = sm->user_eap_method_index; 1082 1083 /* In theory, there should be no problems with starting 1084 * re-authentication with something else than EAP-Request/Identity and 1085 * this does indeed work with wpa_supplicant. However, at least Funk 1086 * Supplicant seemed to ignore re-auth if it skipped 1087 * EAP-Request/Identity. 1088 * Re-auth sets currentId == -1, so that can be used here to select 1089 * whether Identity needs to be requested again. */ 1090 if (sm->identity == NULL || sm->currentId == -1) { 1091 *vendor = EAP_VENDOR_IETF; 1092 next = EAP_TYPE_IDENTITY; 1093 sm->update_user = TRUE; 1094 } else if (sm->user && idx < EAP_MAX_METHODS && 1095 (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || 1096 sm->user->methods[idx].method != EAP_TYPE_NONE)) { 1097 *vendor = sm->user->methods[idx].vendor; 1098 next = sm->user->methods[idx].method; 1099 sm->user_eap_method_index++; 1100 } else { 1101 *vendor = EAP_VENDOR_IETF; 1102 next = EAP_TYPE_NONE; 1103 } 1104 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", 1105 *vendor, next); 1106 return next; 1107} 1108 1109 1110static int eap_sm_Policy_getDecision(struct eap_sm *sm) 1111{ 1112 if (!sm->eap_server && sm->identity && !sm->start_reauth) { 1113 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); 1114 return DECISION_PASSTHROUGH; 1115 } 1116 1117 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && 1118 sm->m->isSuccess(sm, sm->eap_method_priv)) { 1119 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " 1120 "SUCCESS"); 1121 sm->update_user = TRUE; 1122 return DECISION_SUCCESS; 1123 } 1124 1125 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && 1126 !sm->m->isSuccess(sm, sm->eap_method_priv)) { 1127 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " 1128 "FAILURE"); 1129 sm->update_user = TRUE; 1130 return DECISION_FAILURE; 1131 } 1132 1133 if ((sm->user == NULL || sm->update_user) && sm->identity && 1134 !sm->start_reauth) { 1135 /* 1136 * Allow Identity method to be started once to allow identity 1137 * selection hint to be sent from the authentication server, 1138 * but prevent a loop of Identity requests by only allowing 1139 * this to happen once. 1140 */ 1141 int id_req = 0; 1142 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && 1143 sm->user->methods[0].vendor == EAP_VENDOR_IETF && 1144 sm->user->methods[0].method == EAP_TYPE_IDENTITY) 1145 id_req = 1; 1146 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { 1147 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " 1148 "found from database -> FAILURE"); 1149 return DECISION_FAILURE; 1150 } 1151 if (id_req && sm->user && 1152 sm->user->methods[0].vendor == EAP_VENDOR_IETF && 1153 sm->user->methods[0].method == EAP_TYPE_IDENTITY) { 1154 wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " 1155 "identity request loop -> FAILURE"); 1156 sm->update_user = TRUE; 1157 return DECISION_FAILURE; 1158 } 1159 sm->update_user = FALSE; 1160 } 1161 sm->start_reauth = FALSE; 1162 1163 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 1164 (sm->user->methods[sm->user_eap_method_index].vendor != 1165 EAP_VENDOR_IETF || 1166 sm->user->methods[sm->user_eap_method_index].method != 1167 EAP_TYPE_NONE)) { 1168 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " 1169 "available -> CONTINUE"); 1170 return DECISION_CONTINUE; 1171 } 1172 1173 if (sm->identity == NULL || sm->currentId == -1) { 1174 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " 1175 "yet -> CONTINUE"); 1176 return DECISION_CONTINUE; 1177 } 1178 1179 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " 1180 "FAILURE"); 1181 return DECISION_FAILURE; 1182} 1183 1184 1185static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method) 1186{ 1187 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE; 1188} 1189 1190 1191/** 1192 * eap_server_sm_step - Step EAP server state machine 1193 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1194 * Returns: 1 if EAP state was changed or 0 if not 1195 * 1196 * This function advances EAP state machine to a new state to match with the 1197 * current variables. This should be called whenever variables used by the EAP 1198 * state machine have changed. 1199 */ 1200int eap_server_sm_step(struct eap_sm *sm) 1201{ 1202 int res = 0; 1203 do { 1204 sm->changed = FALSE; 1205 SM_STEP_RUN(EAP); 1206 if (sm->changed) 1207 res = 1; 1208 } while (sm->changed); 1209 return res; 1210} 1211 1212 1213static void eap_user_free(struct eap_user *user) 1214{ 1215 if (user == NULL) 1216 return; 1217 os_free(user->password); 1218 user->password = NULL; 1219 os_free(user); 1220} 1221 1222 1223/** 1224 * eap_server_sm_init - Allocate and initialize EAP server state machine 1225 * @eapol_ctx: Context data to be used with eapol_cb calls 1226 * @eapol_cb: Pointer to EAPOL callback functions 1227 * @conf: EAP configuration 1228 * Returns: Pointer to the allocated EAP state machine or %NULL on failure 1229 * 1230 * This function allocates and initializes an EAP state machine. 1231 */ 1232struct eap_sm * eap_server_sm_init(void *eapol_ctx, 1233 struct eapol_callbacks *eapol_cb, 1234 struct eap_config *conf) 1235{ 1236 struct eap_sm *sm; 1237 1238 sm = os_zalloc(sizeof(*sm)); 1239 if (sm == NULL) 1240 return NULL; 1241 sm->eapol_ctx = eapol_ctx; 1242 sm->eapol_cb = eapol_cb; 1243 sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ 1244 sm->ssl_ctx = conf->ssl_ctx; 1245 sm->msg_ctx = conf->msg_ctx; 1246 sm->eap_sim_db_priv = conf->eap_sim_db_priv; 1247 sm->backend_auth = conf->backend_auth; 1248 sm->eap_server = conf->eap_server; 1249 if (conf->pac_opaque_encr_key) { 1250 sm->pac_opaque_encr_key = os_malloc(16); 1251 if (sm->pac_opaque_encr_key) { 1252 os_memcpy(sm->pac_opaque_encr_key, 1253 conf->pac_opaque_encr_key, 16); 1254 } 1255 } 1256 if (conf->eap_fast_a_id) { 1257 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 1258 if (sm->eap_fast_a_id) { 1259 os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id, 1260 conf->eap_fast_a_id_len); 1261 sm->eap_fast_a_id_len = conf->eap_fast_a_id_len; 1262 } 1263 } 1264 if (conf->eap_fast_a_id_info) 1265 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 1266 sm->eap_fast_prov = conf->eap_fast_prov; 1267 sm->pac_key_lifetime = conf->pac_key_lifetime; 1268 sm->pac_key_refresh_time = conf->pac_key_refresh_time; 1269 sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 1270 sm->tnc = conf->tnc; 1271 sm->wps = conf->wps; 1272 if (conf->assoc_wps_ie) 1273 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); 1274 if (conf->assoc_p2p_ie) 1275 sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie); 1276 if (conf->peer_addr) 1277 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); 1278 sm->fragment_size = conf->fragment_size; 1279 sm->pwd_group = conf->pwd_group; 1280 sm->pbc_in_m1 = conf->pbc_in_m1; 1281 1282 wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); 1283 1284 return sm; 1285} 1286 1287 1288/** 1289 * eap_server_sm_deinit - Deinitialize and free an EAP server state machine 1290 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1291 * 1292 * This function deinitializes EAP state machine and frees all allocated 1293 * resources. 1294 */ 1295void eap_server_sm_deinit(struct eap_sm *sm) 1296{ 1297 if (sm == NULL) 1298 return; 1299 wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); 1300 if (sm->m && sm->eap_method_priv) 1301 sm->m->reset(sm, sm->eap_method_priv); 1302 wpabuf_free(sm->eap_if.eapReqData); 1303 os_free(sm->eap_if.eapKeyData); 1304 wpabuf_free(sm->lastReqData); 1305 wpabuf_free(sm->eap_if.eapRespData); 1306 os_free(sm->identity); 1307 os_free(sm->pac_opaque_encr_key); 1308 os_free(sm->eap_fast_a_id); 1309 os_free(sm->eap_fast_a_id_info); 1310 wpabuf_free(sm->eap_if.aaaEapReqData); 1311 wpabuf_free(sm->eap_if.aaaEapRespData); 1312 os_free(sm->eap_if.aaaEapKeyData); 1313 eap_user_free(sm->user); 1314 wpabuf_free(sm->assoc_wps_ie); 1315 wpabuf_free(sm->assoc_p2p_ie); 1316 os_free(sm); 1317} 1318 1319 1320/** 1321 * eap_sm_notify_cached - Notify EAP state machine of cached PMK 1322 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1323 * 1324 * This function is called when PMKSA caching is used to skip EAP 1325 * authentication. 1326 */ 1327void eap_sm_notify_cached(struct eap_sm *sm) 1328{ 1329 if (sm == NULL) 1330 return; 1331 1332 sm->EAP_state = EAP_SUCCESS; 1333} 1334 1335 1336/** 1337 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request 1338 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1339 * 1340 * This function is called when data for a pending EAP-Request is received. 1341 */ 1342void eap_sm_pending_cb(struct eap_sm *sm) 1343{ 1344 if (sm == NULL) 1345 return; 1346 wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); 1347 if (sm->method_pending == METHOD_PENDING_WAIT) 1348 sm->method_pending = METHOD_PENDING_CONT; 1349} 1350 1351 1352/** 1353 * eap_sm_method_pending - Query whether EAP method is waiting for pending data 1354 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1355 * Returns: 1 if method is waiting for pending data or 0 if not 1356 */ 1357int eap_sm_method_pending(struct eap_sm *sm) 1358{ 1359 if (sm == NULL) 1360 return 0; 1361 return sm->method_pending == METHOD_PENDING_WAIT; 1362} 1363 1364 1365/** 1366 * eap_get_identity - Get the user identity (from EAP-Response/Identity) 1367 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1368 * @len: Buffer for returning identity length 1369 * Returns: Pointer to the user identity or %NULL if not available 1370 */ 1371const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) 1372{ 1373 *len = sm->identity_len; 1374 return sm->identity; 1375} 1376 1377 1378/** 1379 * eap_get_interface - Get pointer to EAP-EAPOL interface data 1380 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1381 * Returns: Pointer to the EAP-EAPOL interface data 1382 */ 1383struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) 1384{ 1385 return &sm->eap_if; 1386} 1387 1388 1389/** 1390 * eap_server_clear_identity - Clear EAP identity information 1391 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1392 * 1393 * This function can be used to clear the EAP identity information in the EAP 1394 * server context. This allows the EAP/Identity method to be used again after 1395 * EAPOL-Start or EAPOL-Logoff. 1396 */ 1397void eap_server_clear_identity(struct eap_sm *sm) 1398{ 1399 os_free(sm->identity); 1400 sm->identity = NULL; 1401} 1402