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