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