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