00001
00022 #include "includes.h"
00023
00024 #include "common.h"
00025 #include "eap_i.h"
00026 #include "state_machine.h"
00027
00028 #define STATE_MACHINE_DATA struct eap_sm
00029 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
00030
00031 #define EAP_MAX_AUTH_ROUNDS 50
00032
00033 static void eap_user_free(struct eap_user *user);
00034
00035
00036
00037
00038 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
00039 int eapSRTT, int eapRTTVAR,
00040 int methodTimeout);
00041 static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
00042 static int eap_sm_getId(const struct wpabuf *data);
00043 static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
00044 static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
00045 static int eap_sm_nextId(struct eap_sm *sm, int id);
00046 static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
00047 size_t len);
00048 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
00049 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
00050 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
00051
00052
00053 static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
00054 {
00055 if (src == NULL)
00056 return -1;
00057
00058 wpabuf_free(*dst);
00059 *dst = wpabuf_dup(src);
00060 return *dst ? 0 : -1;
00061 }
00062
00063
00064 static int eap_copy_data(u8 **dst, size_t *dst_len,
00065 const u8 *src, size_t src_len)
00066 {
00067 if (src == NULL)
00068 return -1;
00069
00070 os_free(*dst);
00071 *dst = os_malloc(src_len);
00072 if (*dst) {
00073 os_memcpy(*dst, src, src_len);
00074 *dst_len = src_len;
00075 return 0;
00076 } else {
00077 *dst_len = 0;
00078 return -1;
00079 }
00080 }
00081
00082 #define EAP_COPY(dst, src) \
00083 eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
00084
00085
00100 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
00101 int phase2)
00102 {
00103 struct eap_user *user;
00104
00105 if (sm == NULL || sm->eapol_cb == NULL ||
00106 sm->eapol_cb->get_eap_user == NULL)
00107 return -1;
00108
00109 eap_user_free(sm->user);
00110 sm->user = NULL;
00111
00112 user = os_zalloc(sizeof(*user));
00113 if (user == NULL)
00114 return -1;
00115
00116 if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
00117 identity_len, phase2, user) != 0) {
00118 eap_user_free(user);
00119 return -1;
00120 }
00121
00122 sm->user = user;
00123 sm->user_eap_method_index = 0;
00124
00125 return 0;
00126 }
00127
00128
00129 SM_STATE(EAP, DISABLED)
00130 {
00131 SM_ENTRY(EAP, DISABLED);
00132 sm->num_rounds = 0;
00133 }
00134
00135
00136 SM_STATE(EAP, INITIALIZE)
00137 {
00138 SM_ENTRY(EAP, INITIALIZE);
00139
00140 sm->currentId = -1;
00141 sm->eap_if.eapSuccess = FALSE;
00142 sm->eap_if.eapFail = FALSE;
00143 sm->eap_if.eapTimeout = FALSE;
00144 os_free(sm->eap_if.eapKeyData);
00145 sm->eap_if.eapKeyData = NULL;
00146 sm->eap_if.eapKeyDataLen = 0;
00147 sm->eap_if.eapKeyAvailable = FALSE;
00148 sm->eap_if.eapRestart = FALSE;
00149
00150
00151
00152
00153
00154
00155 if (sm->m && sm->eap_method_priv) {
00156 sm->m->reset(sm, sm->eap_method_priv);
00157 sm->eap_method_priv = NULL;
00158 }
00159 sm->m = NULL;
00160 sm->user_eap_method_index = 0;
00161
00162 if (sm->backend_auth) {
00163 sm->currentMethod = EAP_TYPE_NONE;
00164
00165 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
00166 if (sm->rxResp) {
00167 sm->currentId = sm->respId;
00168 }
00169 }
00170 sm->num_rounds = 0;
00171 sm->method_pending = METHOD_PENDING_NONE;
00172 }
00173
00174
00175 SM_STATE(EAP, PICK_UP_METHOD)
00176 {
00177 SM_ENTRY(EAP, PICK_UP_METHOD);
00178
00179 if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
00180 sm->currentMethod = sm->respMethod;
00181 if (sm->m && sm->eap_method_priv) {
00182 sm->m->reset(sm, sm->eap_method_priv);
00183 sm->eap_method_priv = NULL;
00184 }
00185 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
00186 sm->currentMethod);
00187 if (sm->m && sm->m->initPickUp) {
00188 sm->eap_method_priv = sm->m->initPickUp(sm);
00189 if (sm->eap_method_priv == NULL) {
00190 wpa_printf(MSG_DEBUG, "EAP: Failed to "
00191 "initialize EAP method %d",
00192 sm->currentMethod);
00193 sm->m = NULL;
00194 sm->currentMethod = EAP_TYPE_NONE;
00195 }
00196 } else {
00197 sm->m = NULL;
00198 sm->currentMethod = EAP_TYPE_NONE;
00199 }
00200 }
00201 }
00202
00203
00204 SM_STATE(EAP, IDLE)
00205 {
00206 SM_ENTRY(EAP, IDLE);
00207
00208 sm->eap_if.retransWhile = eap_sm_calculateTimeout(
00209 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
00210 sm->methodTimeout);
00211 }
00212
00213
00214 SM_STATE(EAP, RETRANSMIT)
00215 {
00216 SM_ENTRY(EAP, RETRANSMIT);
00217
00218 sm->retransCount++;
00219 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
00220 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
00221 sm->eap_if.eapReq = TRUE;
00222 }
00223 }
00224
00225
00226 SM_STATE(EAP, RECEIVED)
00227 {
00228 SM_ENTRY(EAP, RECEIVED);
00229
00230
00231 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
00232 sm->num_rounds++;
00233 }
00234
00235
00236 SM_STATE(EAP, DISCARD)
00237 {
00238 SM_ENTRY(EAP, DISCARD);
00239 sm->eap_if.eapResp = FALSE;
00240 sm->eap_if.eapNoReq = TRUE;
00241 }
00242
00243
00244 SM_STATE(EAP, SEND_REQUEST)
00245 {
00246 SM_ENTRY(EAP, SEND_REQUEST);
00247
00248 sm->retransCount = 0;
00249 if (sm->eap_if.eapReqData) {
00250 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
00251 {
00252 sm->eap_if.eapResp = FALSE;
00253 sm->eap_if.eapReq = TRUE;
00254 } else {
00255 sm->eap_if.eapResp = FALSE;
00256 sm->eap_if.eapReq = FALSE;
00257 }
00258 } else {
00259 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
00260 sm->eap_if.eapResp = FALSE;
00261 sm->eap_if.eapReq = FALSE;
00262 sm->eap_if.eapNoReq = TRUE;
00263 }
00264 }
00265
00266
00267 SM_STATE(EAP, INTEGRITY_CHECK)
00268 {
00269 SM_ENTRY(EAP, INTEGRITY_CHECK);
00270
00271 if (sm->m->check) {
00272 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
00273 sm->eap_if.eapRespData);
00274 }
00275 }
00276
00277
00278 SM_STATE(EAP, METHOD_REQUEST)
00279 {
00280 SM_ENTRY(EAP, METHOD_REQUEST);
00281
00282 if (sm->m == NULL) {
00283 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
00284 return;
00285 }
00286
00287 sm->currentId = eap_sm_nextId(sm, sm->currentId);
00288 wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
00289 sm->currentId);
00290 sm->lastId = sm->currentId;
00291 wpabuf_free(sm->eap_if.eapReqData);
00292 sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
00293 sm->currentId);
00294 if (sm->m->getTimeout)
00295 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
00296 else
00297 sm->methodTimeout = 0;
00298 }
00299
00300
00301 SM_STATE(EAP, METHOD_RESPONSE)
00302 {
00303 SM_ENTRY(EAP, METHOD_RESPONSE);
00304
00305 sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
00306 if (sm->m->isDone(sm, sm->eap_method_priv)) {
00307 eap_sm_Policy_update(sm, NULL, 0);
00308 os_free(sm->eap_if.eapKeyData);
00309 if (sm->m->getKey) {
00310 sm->eap_if.eapKeyData = sm->m->getKey(
00311 sm, sm->eap_method_priv,
00312 &sm->eap_if.eapKeyDataLen);
00313 } else {
00314 sm->eap_if.eapKeyData = NULL;
00315 sm->eap_if.eapKeyDataLen = 0;
00316 }
00317 sm->methodState = METHOD_END;
00318 } else {
00319 sm->methodState = METHOD_CONTINUE;
00320 }
00321 }
00322
00323
00324 SM_STATE(EAP, PROPOSE_METHOD)
00325 {
00326 int vendor;
00327 EapType type;
00328
00329 SM_ENTRY(EAP, PROPOSE_METHOD);
00330
00331 type = eap_sm_Policy_getNextMethod(sm, &vendor);
00332 if (vendor == EAP_VENDOR_IETF)
00333 sm->currentMethod = type;
00334 else
00335 sm->currentMethod = EAP_TYPE_EXPANDED;
00336 if (sm->m && sm->eap_method_priv) {
00337 sm->m->reset(sm, sm->eap_method_priv);
00338 sm->eap_method_priv = NULL;
00339 }
00340 sm->m = eap_server_get_eap_method(vendor, type);
00341 if (sm->m) {
00342 sm->eap_method_priv = sm->m->init(sm);
00343 if (sm->eap_method_priv == NULL) {
00344 wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
00345 "method %d", sm->currentMethod);
00346 sm->m = NULL;
00347 sm->currentMethod = EAP_TYPE_NONE;
00348 }
00349 }
00350 if (sm->currentMethod == EAP_TYPE_IDENTITY ||
00351 sm->currentMethod == EAP_TYPE_NOTIFICATION)
00352 sm->methodState = METHOD_CONTINUE;
00353 else
00354 sm->methodState = METHOD_PROPOSED;
00355 }
00356
00357
00358 SM_STATE(EAP, NAK)
00359 {
00360 const struct eap_hdr *nak;
00361 size_t len = 0;
00362 const u8 *pos;
00363 const u8 *nak_list = NULL;
00364
00365 SM_ENTRY(EAP, NAK);
00366
00367 if (sm->eap_method_priv) {
00368 sm->m->reset(sm, sm->eap_method_priv);
00369 sm->eap_method_priv = NULL;
00370 }
00371 sm->m = NULL;
00372
00373 nak = wpabuf_head(sm->eap_if.eapRespData);
00374 if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
00375 len = be_to_host16(nak->length);
00376 if (len > wpabuf_len(sm->eap_if.eapRespData))
00377 len = wpabuf_len(sm->eap_if.eapRespData);
00378 pos = (const u8 *) (nak + 1);
00379 len -= sizeof(*nak);
00380 if (*pos == EAP_TYPE_NAK) {
00381 pos++;
00382 len--;
00383 nak_list = pos;
00384 }
00385 }
00386 eap_sm_Policy_update(sm, nak_list, len);
00387 }
00388
00389
00390 SM_STATE(EAP, SELECT_ACTION)
00391 {
00392 SM_ENTRY(EAP, SELECT_ACTION);
00393
00394 sm->decision = eap_sm_Policy_getDecision(sm);
00395 }
00396
00397
00398 SM_STATE(EAP, TIMEOUT_FAILURE)
00399 {
00400 SM_ENTRY(EAP, TIMEOUT_FAILURE);
00401
00402 sm->eap_if.eapTimeout = TRUE;
00403 }
00404
00405
00406 SM_STATE(EAP, FAILURE)
00407 {
00408 SM_ENTRY(EAP, FAILURE);
00409
00410 wpabuf_free(sm->eap_if.eapReqData);
00411 sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
00412 wpabuf_free(sm->lastReqData);
00413 sm->lastReqData = NULL;
00414 sm->eap_if.eapFail = TRUE;
00415 }
00416
00417
00418 SM_STATE(EAP, SUCCESS)
00419 {
00420 SM_ENTRY(EAP, SUCCESS);
00421
00422 wpabuf_free(sm->eap_if.eapReqData);
00423 sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
00424 wpabuf_free(sm->lastReqData);
00425 sm->lastReqData = NULL;
00426 if (sm->eap_if.eapKeyData)
00427 sm->eap_if.eapKeyAvailable = TRUE;
00428 sm->eap_if.eapSuccess = TRUE;
00429 }
00430
00431
00432 SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
00433 {
00434 SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
00435
00436 wpabuf_free(sm->eap_if.aaaEapRespData);
00437 sm->eap_if.aaaEapRespData = NULL;
00438 }
00439
00440
00441 SM_STATE(EAP, IDLE2)
00442 {
00443 SM_ENTRY(EAP, IDLE2);
00444
00445 sm->eap_if.retransWhile = eap_sm_calculateTimeout(
00446 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
00447 sm->methodTimeout);
00448 }
00449
00450
00451 SM_STATE(EAP, RETRANSMIT2)
00452 {
00453 SM_ENTRY(EAP, RETRANSMIT2);
00454
00455 sm->retransCount++;
00456 if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
00457 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
00458 sm->eap_if.eapReq = TRUE;
00459 }
00460 }
00461
00462
00463 SM_STATE(EAP, RECEIVED2)
00464 {
00465 SM_ENTRY(EAP, RECEIVED2);
00466
00467
00468 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
00469 }
00470
00471
00472 SM_STATE(EAP, DISCARD2)
00473 {
00474 SM_ENTRY(EAP, DISCARD2);
00475 sm->eap_if.eapResp = FALSE;
00476 sm->eap_if.eapNoReq = TRUE;
00477 }
00478
00479
00480 SM_STATE(EAP, SEND_REQUEST2)
00481 {
00482 SM_ENTRY(EAP, SEND_REQUEST2);
00483
00484 sm->retransCount = 0;
00485 if (sm->eap_if.eapReqData) {
00486 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
00487 {
00488 sm->eap_if.eapResp = FALSE;
00489 sm->eap_if.eapReq = TRUE;
00490 } else {
00491 sm->eap_if.eapResp = FALSE;
00492 sm->eap_if.eapReq = FALSE;
00493 }
00494 } else {
00495 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
00496 sm->eap_if.eapResp = FALSE;
00497 sm->eap_if.eapReq = FALSE;
00498 sm->eap_if.eapNoReq = TRUE;
00499 }
00500 }
00501
00502
00503 SM_STATE(EAP, AAA_REQUEST)
00504 {
00505 SM_ENTRY(EAP, AAA_REQUEST);
00506
00507 if (sm->eap_if.eapRespData == NULL) {
00508 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
00509 return;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519 eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
00520 }
00521
00522
00523 SM_STATE(EAP, AAA_RESPONSE)
00524 {
00525 SM_ENTRY(EAP, AAA_RESPONSE);
00526
00527 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
00528 sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
00529 sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
00530 }
00531
00532
00533 SM_STATE(EAP, AAA_IDLE)
00534 {
00535 SM_ENTRY(EAP, AAA_IDLE);
00536
00537 sm->eap_if.aaaFail = FALSE;
00538 sm->eap_if.aaaSuccess = FALSE;
00539 sm->eap_if.aaaEapReq = FALSE;
00540 sm->eap_if.aaaEapNoReq = FALSE;
00541 sm->eap_if.aaaEapResp = TRUE;
00542 }
00543
00544
00545 SM_STATE(EAP, TIMEOUT_FAILURE2)
00546 {
00547 SM_ENTRY(EAP, TIMEOUT_FAILURE2);
00548
00549 sm->eap_if.eapTimeout = TRUE;
00550 }
00551
00552
00553 SM_STATE(EAP, FAILURE2)
00554 {
00555 SM_ENTRY(EAP, FAILURE2);
00556
00557 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
00558 sm->eap_if.eapFail = TRUE;
00559 }
00560
00561
00562 SM_STATE(EAP, SUCCESS2)
00563 {
00564 SM_ENTRY(EAP, SUCCESS2);
00565
00566 eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
00567
00568 sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
00569 if (sm->eap_if.aaaEapKeyAvailable) {
00570 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
00571 } else {
00572 os_free(sm->eap_if.eapKeyData);
00573 sm->eap_if.eapKeyData = NULL;
00574 sm->eap_if.eapKeyDataLen = 0;
00575 }
00576
00577 sm->eap_if.eapSuccess = TRUE;
00578
00579
00580
00581
00582
00583
00584 sm->start_reauth = TRUE;
00585 }
00586
00587
00588 SM_STEP(EAP)
00589 {
00590 if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
00591 SM_ENTER_GLOBAL(EAP, INITIALIZE);
00592 else if (!sm->eap_if.portEnabled)
00593 SM_ENTER_GLOBAL(EAP, DISABLED);
00594 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
00595 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
00596 wpa_printf(MSG_DEBUG, "EAP: more than %d "
00597 "authentication rounds - abort",
00598 EAP_MAX_AUTH_ROUNDS);
00599 sm->num_rounds++;
00600 SM_ENTER_GLOBAL(EAP, FAILURE);
00601 }
00602 } else switch (sm->EAP_state) {
00603 case EAP_INITIALIZE:
00604 if (sm->backend_auth) {
00605 if (!sm->rxResp)
00606 SM_ENTER(EAP, SELECT_ACTION);
00607 else if (sm->rxResp &&
00608 (sm->respMethod == EAP_TYPE_NAK ||
00609 (sm->respMethod == EAP_TYPE_EXPANDED &&
00610 sm->respVendor == EAP_VENDOR_IETF &&
00611 sm->respVendorMethod == EAP_TYPE_NAK)))
00612 SM_ENTER(EAP, NAK);
00613 else
00614 SM_ENTER(EAP, PICK_UP_METHOD);
00615 } else {
00616 SM_ENTER(EAP, SELECT_ACTION);
00617 }
00618 break;
00619 case EAP_PICK_UP_METHOD:
00620 if (sm->currentMethod == EAP_TYPE_NONE) {
00621 SM_ENTER(EAP, SELECT_ACTION);
00622 } else {
00623 SM_ENTER(EAP, METHOD_RESPONSE);
00624 }
00625 break;
00626 case EAP_DISABLED:
00627 if (sm->eap_if.portEnabled)
00628 SM_ENTER(EAP, INITIALIZE);
00629 break;
00630 case EAP_IDLE:
00631 if (sm->eap_if.retransWhile == 0)
00632 SM_ENTER(EAP, RETRANSMIT);
00633 else if (sm->eap_if.eapResp)
00634 SM_ENTER(EAP, RECEIVED);
00635 break;
00636 case EAP_RETRANSMIT:
00637 if (sm->retransCount > sm->MaxRetrans)
00638 SM_ENTER(EAP, TIMEOUT_FAILURE);
00639 else
00640 SM_ENTER(EAP, IDLE);
00641 break;
00642 case EAP_RECEIVED:
00643 if (sm->rxResp && (sm->respId == sm->currentId) &&
00644 (sm->respMethod == EAP_TYPE_NAK ||
00645 (sm->respMethod == EAP_TYPE_EXPANDED &&
00646 sm->respVendor == EAP_VENDOR_IETF &&
00647 sm->respVendorMethod == EAP_TYPE_NAK))
00648 && (sm->methodState == METHOD_PROPOSED))
00649 SM_ENTER(EAP, NAK);
00650 else if (sm->rxResp && (sm->respId == sm->currentId) &&
00651 ((sm->respMethod == sm->currentMethod) ||
00652 (sm->respMethod == EAP_TYPE_EXPANDED &&
00653 sm->respVendor == EAP_VENDOR_IETF &&
00654 sm->respVendorMethod == sm->currentMethod)))
00655 SM_ENTER(EAP, INTEGRITY_CHECK);
00656 else {
00657 wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
00658 "rxResp=%d respId=%d currentId=%d "
00659 "respMethod=%d currentMethod=%d",
00660 sm->rxResp, sm->respId, sm->currentId,
00661 sm->respMethod, sm->currentMethod);
00662 SM_ENTER(EAP, DISCARD);
00663 }
00664 break;
00665 case EAP_DISCARD:
00666 SM_ENTER(EAP, IDLE);
00667 break;
00668 case EAP_SEND_REQUEST:
00669 SM_ENTER(EAP, IDLE);
00670 break;
00671 case EAP_INTEGRITY_CHECK:
00672 if (sm->ignore)
00673 SM_ENTER(EAP, DISCARD);
00674 else
00675 SM_ENTER(EAP, METHOD_RESPONSE);
00676 break;
00677 case EAP_METHOD_REQUEST:
00678 SM_ENTER(EAP, SEND_REQUEST);
00679 break;
00680 case EAP_METHOD_RESPONSE:
00681
00682
00683
00684
00685
00686
00687 if (sm->methodState == METHOD_END)
00688 SM_ENTER(EAP, SELECT_ACTION);
00689 else if (sm->method_pending == METHOD_PENDING_WAIT) {
00690 wpa_printf(MSG_DEBUG, "EAP: Method has pending "
00691 "processing - wait before proceeding to "
00692 "METHOD_REQUEST state");
00693 } else if (sm->method_pending == METHOD_PENDING_CONT) {
00694 wpa_printf(MSG_DEBUG, "EAP: Method has completed "
00695 "pending processing - reprocess pending "
00696 "EAP message");
00697 sm->method_pending = METHOD_PENDING_NONE;
00698 SM_ENTER(EAP, METHOD_RESPONSE);
00699 } else
00700 SM_ENTER(EAP, METHOD_REQUEST);
00701 break;
00702 case EAP_PROPOSE_METHOD:
00703
00704
00705
00706
00707
00708
00709 if (sm->method_pending == METHOD_PENDING_WAIT) {
00710 wpa_printf(MSG_DEBUG, "EAP: Method has pending "
00711 "processing - wait before proceeding to "
00712 "METHOD_REQUEST state");
00713 if (sm->user_eap_method_index > 0)
00714 sm->user_eap_method_index--;
00715 } else if (sm->method_pending == METHOD_PENDING_CONT) {
00716 wpa_printf(MSG_DEBUG, "EAP: Method has completed "
00717 "pending processing - reprocess pending "
00718 "EAP message");
00719 sm->method_pending = METHOD_PENDING_NONE;
00720 SM_ENTER(EAP, PROPOSE_METHOD);
00721 } else
00722 SM_ENTER(EAP, METHOD_REQUEST);
00723 break;
00724 case EAP_NAK:
00725 SM_ENTER(EAP, SELECT_ACTION);
00726 break;
00727 case EAP_SELECT_ACTION:
00728 if (sm->decision == DECISION_FAILURE)
00729 SM_ENTER(EAP, FAILURE);
00730 else if (sm->decision == DECISION_SUCCESS)
00731 SM_ENTER(EAP, SUCCESS);
00732 else if (sm->decision == DECISION_PASSTHROUGH)
00733 SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
00734 else
00735 SM_ENTER(EAP, PROPOSE_METHOD);
00736 break;
00737 case EAP_TIMEOUT_FAILURE:
00738 break;
00739 case EAP_FAILURE:
00740 break;
00741 case EAP_SUCCESS:
00742 break;
00743
00744 case EAP_INITIALIZE_PASSTHROUGH:
00745 if (sm->currentId == -1)
00746 SM_ENTER(EAP, AAA_IDLE);
00747 else
00748 SM_ENTER(EAP, AAA_REQUEST);
00749 break;
00750 case EAP_IDLE2:
00751 if (sm->eap_if.eapResp)
00752 SM_ENTER(EAP, RECEIVED2);
00753 else if (sm->eap_if.retransWhile == 0)
00754 SM_ENTER(EAP, RETRANSMIT2);
00755 break;
00756 case EAP_RETRANSMIT2:
00757 if (sm->retransCount > sm->MaxRetrans)
00758 SM_ENTER(EAP, TIMEOUT_FAILURE2);
00759 else
00760 SM_ENTER(EAP, IDLE2);
00761 break;
00762 case EAP_RECEIVED2:
00763 if (sm->rxResp && (sm->respId == sm->currentId))
00764 SM_ENTER(EAP, AAA_REQUEST);
00765 else
00766 SM_ENTER(EAP, DISCARD2);
00767 break;
00768 case EAP_DISCARD2:
00769 SM_ENTER(EAP, IDLE2);
00770 break;
00771 case EAP_SEND_REQUEST2:
00772 SM_ENTER(EAP, IDLE2);
00773 break;
00774 case EAP_AAA_REQUEST:
00775 SM_ENTER(EAP, AAA_IDLE);
00776 break;
00777 case EAP_AAA_RESPONSE:
00778 SM_ENTER(EAP, SEND_REQUEST2);
00779 break;
00780 case EAP_AAA_IDLE:
00781 if (sm->eap_if.aaaFail)
00782 SM_ENTER(EAP, FAILURE2);
00783 else if (sm->eap_if.aaaSuccess)
00784 SM_ENTER(EAP, SUCCESS2);
00785 else if (sm->eap_if.aaaEapReq)
00786 SM_ENTER(EAP, AAA_RESPONSE);
00787 else if (sm->eap_if.aaaTimeout)
00788 SM_ENTER(EAP, TIMEOUT_FAILURE2);
00789 break;
00790 case EAP_TIMEOUT_FAILURE2:
00791 break;
00792 case EAP_FAILURE2:
00793 break;
00794 case EAP_SUCCESS2:
00795 break;
00796 }
00797 }
00798
00799
00800 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
00801 int eapSRTT, int eapRTTVAR,
00802 int methodTimeout)
00803 {
00804 int rto, i;
00805
00806 if (methodTimeout) {
00807
00808
00809
00810
00811
00812 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
00813 "(from EAP method hint)", methodTimeout);
00814 return methodTimeout;
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835 rto = 3;
00836 for (i = 0; i < retransCount; i++) {
00837 rto *= 2;
00838 if (rto >= 20) {
00839 rto = 20;
00840 break;
00841 }
00842 }
00843
00844 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
00845 "(from dynamic back off; retransCount=%d)",
00846 rto, retransCount);
00847
00848 return rto;
00849 }
00850
00851
00852 static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
00853 {
00854 const struct eap_hdr *hdr;
00855 size_t plen;
00856
00857
00858 sm->rxResp = FALSE;
00859 sm->respId = -1;
00860 sm->respMethod = EAP_TYPE_NONE;
00861 sm->respVendor = EAP_VENDOR_IETF;
00862 sm->respVendorMethod = EAP_TYPE_NONE;
00863
00864 if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
00865 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
00866 "len=%lu", resp,
00867 resp ? (unsigned long) wpabuf_len(resp) : 0);
00868 return;
00869 }
00870
00871 hdr = wpabuf_head(resp);
00872 plen = be_to_host16(hdr->length);
00873 if (plen > wpabuf_len(resp)) {
00874 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
00875 "(len=%lu plen=%lu)",
00876 (unsigned long) wpabuf_len(resp),
00877 (unsigned long) plen);
00878 return;
00879 }
00880
00881 sm->respId = hdr->identifier;
00882
00883 if (hdr->code == EAP_CODE_RESPONSE)
00884 sm->rxResp = TRUE;
00885
00886 if (plen > sizeof(*hdr)) {
00887 u8 *pos = (u8 *) (hdr + 1);
00888 sm->respMethod = *pos++;
00889 if (sm->respMethod == EAP_TYPE_EXPANDED) {
00890 if (plen < sizeof(*hdr) + 8) {
00891 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
00892 "expanded EAP-Packet (plen=%lu)",
00893 (unsigned long) plen);
00894 return;
00895 }
00896 sm->respVendor = WPA_GET_BE24(pos);
00897 pos += 3;
00898 sm->respVendorMethod = WPA_GET_BE32(pos);
00899 }
00900 }
00901
00902 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
00903 "respMethod=%u respVendor=%u respVendorMethod=%u",
00904 sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
00905 sm->respVendorMethod);
00906 }
00907
00908
00909 static int eap_sm_getId(const struct wpabuf *data)
00910 {
00911 const struct eap_hdr *hdr;
00912
00913 if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
00914 return -1;
00915
00916 hdr = wpabuf_head(data);
00917 wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
00918 return hdr->identifier;
00919 }
00920
00921
00922 static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
00923 {
00924 struct wpabuf *msg;
00925 struct eap_hdr *resp;
00926 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
00927
00928 msg = wpabuf_alloc(sizeof(*resp));
00929 if (msg == NULL)
00930 return NULL;
00931 resp = wpabuf_put(msg, sizeof(*resp));
00932 resp->code = EAP_CODE_SUCCESS;
00933 resp->identifier = id;
00934 resp->length = host_to_be16(sizeof(*resp));
00935
00936 return msg;
00937 }
00938
00939
00940 static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
00941 {
00942 struct wpabuf *msg;
00943 struct eap_hdr *resp;
00944 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
00945
00946 msg = wpabuf_alloc(sizeof(*resp));
00947 if (msg == NULL)
00948 return NULL;
00949 resp = wpabuf_put(msg, sizeof(*resp));
00950 resp->code = EAP_CODE_FAILURE;
00951 resp->identifier = id;
00952 resp->length = host_to_be16(sizeof(*resp));
00953
00954 return msg;
00955 }
00956
00957
00958 static int eap_sm_nextId(struct eap_sm *sm, int id)
00959 {
00960 if (id < 0) {
00961
00962
00963 id = rand() & 0xff;
00964 if (id != sm->lastId)
00965 return id;
00966 }
00967 return (id + 1) & 0xff;
00968 }
00969
00970
00981 void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
00982 {
00983 int i;
00984 size_t j;
00985
00986 if (sm->user == NULL)
00987 return;
00988
00989 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
00990 "index %d)", sm->user_eap_method_index);
00991
00992 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
00993 (u8 *) sm->user->methods,
00994 EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
00995 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
00996 nak_list, len);
00997
00998 i = sm->user_eap_method_index;
00999 while (i < EAP_MAX_METHODS &&
01000 (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
01001 sm->user->methods[i].method != EAP_TYPE_NONE)) {
01002 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
01003 goto not_found;
01004 for (j = 0; j < len; j++) {
01005 if (nak_list[j] == sm->user->methods[i].method) {
01006 break;
01007 }
01008 }
01009
01010 if (j < len) {
01011
01012 i++;
01013 continue;
01014 }
01015
01016 not_found:
01017
01018 os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
01019 (EAP_MAX_METHODS - i - 1) *
01020 sizeof(sm->user->methods[0]));
01021 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
01022 EAP_VENDOR_IETF;
01023 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
01024 }
01025
01026 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
01027 (u8 *) sm->user->methods, EAP_MAX_METHODS *
01028 sizeof(sm->user->methods[0]));
01029 }
01030
01031
01032 static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
01033 size_t len)
01034 {
01035 if (nak_list == NULL || sm == NULL || sm->user == NULL)
01036 return;
01037
01038 if (sm->user->phase2) {
01039 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
01040 " info was selected - reject");
01041 sm->decision = DECISION_FAILURE;
01042 return;
01043 }
01044
01045 eap_sm_process_nak(sm, nak_list, len);
01046 }
01047
01048
01049 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
01050 {
01051 EapType next;
01052 int idx = sm->user_eap_method_index;
01053
01054
01055
01056
01057
01058
01059
01060
01061 if (sm->identity == NULL || sm->currentId == -1) {
01062 *vendor = EAP_VENDOR_IETF;
01063 next = EAP_TYPE_IDENTITY;
01064 sm->update_user = TRUE;
01065 } else if (sm->user && idx < EAP_MAX_METHODS &&
01066 (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
01067 sm->user->methods[idx].method != EAP_TYPE_NONE)) {
01068 *vendor = sm->user->methods[idx].vendor;
01069 next = sm->user->methods[idx].method;
01070 sm->user_eap_method_index++;
01071 } else {
01072 *vendor = EAP_VENDOR_IETF;
01073 next = EAP_TYPE_NONE;
01074 }
01075 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
01076 *vendor, next);
01077 return next;
01078 }
01079
01080
01081 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
01082 {
01083 if (!sm->eap_server && sm->identity && !sm->start_reauth) {
01084 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
01085 return DECISION_PASSTHROUGH;
01086 }
01087
01088 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
01089 sm->m->isSuccess(sm, sm->eap_method_priv)) {
01090 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
01091 "SUCCESS");
01092 sm->update_user = TRUE;
01093 return DECISION_SUCCESS;
01094 }
01095
01096 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
01097 !sm->m->isSuccess(sm, sm->eap_method_priv)) {
01098 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
01099 "FAILURE");
01100 sm->update_user = TRUE;
01101 return DECISION_FAILURE;
01102 }
01103
01104 if ((sm->user == NULL || sm->update_user) && sm->identity &&
01105 !sm->start_reauth) {
01106
01107
01108
01109
01110
01111
01112 int id_req = 0;
01113 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
01114 sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
01115 sm->user->methods[0].method == EAP_TYPE_IDENTITY)
01116 id_req = 1;
01117 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
01118 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
01119 "found from database -> FAILURE");
01120 return DECISION_FAILURE;
01121 }
01122 if (id_req && sm->user &&
01123 sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
01124 sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
01125 wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
01126 "identity request loop -> FAILURE");
01127 sm->update_user = TRUE;
01128 return DECISION_FAILURE;
01129 }
01130 sm->update_user = FALSE;
01131 }
01132 sm->start_reauth = FALSE;
01133
01134 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
01135 (sm->user->methods[sm->user_eap_method_index].vendor !=
01136 EAP_VENDOR_IETF ||
01137 sm->user->methods[sm->user_eap_method_index].method !=
01138 EAP_TYPE_NONE)) {
01139 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
01140 "available -> CONTINUE");
01141 return DECISION_CONTINUE;
01142 }
01143
01144 if (sm->identity == NULL || sm->currentId == -1) {
01145 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
01146 "yet -> CONTINUE");
01147 return DECISION_CONTINUE;
01148 }
01149
01150 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
01151 "FAILURE");
01152 return DECISION_FAILURE;
01153 }
01154
01155
01156 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
01157 {
01158 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
01159 }
01160
01161
01172 int eap_server_sm_step(struct eap_sm *sm)
01173 {
01174 int res = 0;
01175 do {
01176 sm->changed = FALSE;
01177 SM_STEP_RUN(EAP);
01178 if (sm->changed)
01179 res = 1;
01180 } while (sm->changed);
01181 return res;
01182 }
01183
01184
01185 static void eap_user_free(struct eap_user *user)
01186 {
01187 if (user == NULL)
01188 return;
01189 os_free(user->password);
01190 user->password = NULL;
01191 os_free(user);
01192 }
01193
01194
01205 struct eap_sm * eap_server_sm_init(void *eapol_ctx,
01206 struct eapol_callbacks *eapol_cb,
01207 struct eap_config *conf)
01208 {
01209 struct eap_sm *sm;
01210
01211 sm = os_zalloc(sizeof(*sm));
01212 if (sm == NULL)
01213 return NULL;
01214 sm->eapol_ctx = eapol_ctx;
01215 sm->eapol_cb = eapol_cb;
01216 sm->MaxRetrans = 5;
01217 sm->ssl_ctx = conf->ssl_ctx;
01218 sm->eap_sim_db_priv = conf->eap_sim_db_priv;
01219 sm->backend_auth = conf->backend_auth;
01220 sm->eap_server = conf->eap_server;
01221 if (conf->pac_opaque_encr_key) {
01222 sm->pac_opaque_encr_key = os_malloc(16);
01223 if (sm->pac_opaque_encr_key) {
01224 os_memcpy(sm->pac_opaque_encr_key,
01225 conf->pac_opaque_encr_key, 16);
01226 }
01227 }
01228 if (conf->eap_fast_a_id) {
01229 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
01230 if (sm->eap_fast_a_id) {
01231 os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
01232 conf->eap_fast_a_id_len);
01233 sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
01234 }
01235 }
01236 if (conf->eap_fast_a_id_info)
01237 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
01238 sm->eap_fast_prov = conf->eap_fast_prov;
01239 sm->pac_key_lifetime = conf->pac_key_lifetime;
01240 sm->pac_key_refresh_time = conf->pac_key_refresh_time;
01241 sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
01242 sm->tnc = conf->tnc;
01243 sm->wps = conf->wps;
01244 if (conf->assoc_wps_ie)
01245 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
01246 if (conf->peer_addr)
01247 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
01248
01249 wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
01250
01251 return sm;
01252 }
01253
01254
01263 void eap_server_sm_deinit(struct eap_sm *sm)
01264 {
01265 if (sm == NULL)
01266 return;
01267 wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
01268 if (sm->m && sm->eap_method_priv)
01269 sm->m->reset(sm, sm->eap_method_priv);
01270 wpabuf_free(sm->eap_if.eapReqData);
01271 os_free(sm->eap_if.eapKeyData);
01272 os_free(sm->lastReqData);
01273 wpabuf_free(sm->eap_if.eapRespData);
01274 os_free(sm->identity);
01275 os_free(sm->pac_opaque_encr_key);
01276 os_free(sm->eap_fast_a_id);
01277 os_free(sm->eap_fast_a_id_info);
01278 wpabuf_free(sm->eap_if.aaaEapReqData);
01279 wpabuf_free(sm->eap_if.aaaEapRespData);
01280 os_free(sm->eap_if.aaaEapKeyData);
01281 eap_user_free(sm->user);
01282 wpabuf_free(sm->assoc_wps_ie);
01283 os_free(sm);
01284 }
01285
01286
01295 void eap_sm_notify_cached(struct eap_sm *sm)
01296 {
01297 if (sm == NULL)
01298 return;
01299
01300 sm->EAP_state = EAP_SUCCESS;
01301 }
01302
01303
01311 void eap_sm_pending_cb(struct eap_sm *sm)
01312 {
01313 if (sm == NULL)
01314 return;
01315 wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
01316 if (sm->method_pending == METHOD_PENDING_WAIT)
01317 sm->method_pending = METHOD_PENDING_CONT;
01318 }
01319
01320
01327 int eap_sm_method_pending(struct eap_sm *sm)
01328 {
01329 if (sm == NULL)
01330 return 0;
01331 return sm->method_pending == METHOD_PENDING_WAIT;
01332 }
01333
01334
01342 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
01343 {
01344 *len = sm->identity_len;
01345 return sm->identity;
01346 }
01347
01348
01355 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
01356 {
01357 return &sm->eap_if;
01358 }
01359