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