00001
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029
00030 #include "common.h"
00031 #include "eap_i.h"
00032 #include "wpa_supplicant.h"
00033 #include "config_ssid.h"
00034 #include "tls.h"
00035 #include "crypto.h"
00036 #include "pcsc_funcs.h"
00037 #include "wpa_ctrl.h"
00038
00039
00040 #define EAP_MAX_AUTH_ROUNDS 50
00041
00042
00043 #ifdef EAP_MD5
00044 extern const struct eap_method eap_method_md5;
00045 #endif
00046 #ifdef EAP_TLS
00047 extern const struct eap_method eap_method_tls;
00048 #endif
00049 #ifdef EAP_MSCHAPv2
00050 extern const struct eap_method eap_method_mschapv2;
00051 #endif
00052 #ifdef EAP_PEAP
00053 extern const struct eap_method eap_method_peap;
00054 #endif
00055 #ifdef EAP_TTLS
00056 extern const struct eap_method eap_method_ttls;
00057 #endif
00058 #ifdef EAP_GTC
00059 extern const struct eap_method eap_method_gtc;
00060 #endif
00061 #ifdef EAP_OTP
00062 extern const struct eap_method eap_method_otp;
00063 #endif
00064 #ifdef EAP_SIM
00065 extern const struct eap_method eap_method_sim;
00066 #endif
00067 #ifdef EAP_LEAP
00068 extern const struct eap_method eap_method_leap;
00069 #endif
00070 #ifdef EAP_PSK
00071 extern const struct eap_method eap_method_psk;
00072 #endif
00073 #ifdef EAP_AKA
00074 extern const struct eap_method eap_method_aka;
00075 #endif
00076 #ifdef EAP_FAST
00077 extern const struct eap_method eap_method_fast;
00078 #endif
00079 #ifdef EAP_PAX
00080 extern const struct eap_method eap_method_pax;
00081 #endif
00082
00083 static const struct eap_method *eap_methods[] =
00084 {
00085 #ifdef EAP_MD5
00086 &eap_method_md5,
00087 #endif
00088 #ifdef EAP_TLS
00089 &eap_method_tls,
00090 #endif
00091 #ifdef EAP_MSCHAPv2
00092 &eap_method_mschapv2,
00093 #endif
00094 #ifdef EAP_PEAP
00095 &eap_method_peap,
00096 #endif
00097 #ifdef EAP_TTLS
00098 &eap_method_ttls,
00099 #endif
00100 #ifdef EAP_GTC
00101 &eap_method_gtc,
00102 #endif
00103 #ifdef EAP_OTP
00104 &eap_method_otp,
00105 #endif
00106 #ifdef EAP_SIM
00107 &eap_method_sim,
00108 #endif
00109 #ifdef EAP_LEAP
00110 &eap_method_leap,
00111 #endif
00112 #ifdef EAP_PSK
00113 &eap_method_psk,
00114 #endif
00115 #ifdef EAP_AKA
00116 &eap_method_aka,
00117 #endif
00118 #ifdef EAP_FAST
00119 &eap_method_fast,
00120 #endif
00121 #ifdef EAP_PAX
00122 &eap_method_pax,
00123 #endif
00124 };
00125 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
00126
00127
00134 const struct eap_method * eap_sm_get_eap_methods(int method)
00135 {
00136 int i;
00137 for (i = 0; i < NUM_EAP_METHODS; i++) {
00138 if (eap_methods[i]->method == method)
00139 return eap_methods[i];
00140 }
00141 return NULL;
00142 }
00143
00144
00145 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
00146 static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
00147 static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
00148 size_t len);
00149 static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len);
00150 static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
00151 static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len);
00152 static const char * eap_sm_method_state_txt(EapMethodState state);
00153 static const char * eap_sm_decision_txt(EapDecision decision);
00154
00155
00156
00157 #define SM_STATE(machine, state) \
00158 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
00159 int global)
00160
00161 #define SM_ENTRY(machine, state) \
00162 if (!global || sm->machine ## _state != machine ## _ ## state) { \
00163 sm->changed = TRUE; \
00164 wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
00165 } \
00166 sm->machine ## _state = machine ## _ ## state;
00167
00168 #define SM_ENTER(machine, state) \
00169 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
00170 #define SM_ENTER_GLOBAL(machine, state) \
00171 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
00172
00173 #define SM_STEP(machine) \
00174 static void sm_ ## machine ## _Step(struct eap_sm *sm)
00175
00176 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
00177
00178
00179 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
00180 {
00181 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
00182 }
00183
00184
00185 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
00186 Boolean value)
00187 {
00188 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
00189 }
00190
00191
00192 static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
00193 {
00194 return sm->eapol_cb->get_int(sm->eapol_ctx, var);
00195 }
00196
00197
00198 static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
00199 unsigned int value)
00200 {
00201 sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
00202 }
00203
00204
00205 static u8 * eapol_get_eapReqData(struct eap_sm *sm, size_t *len)
00206 {
00207 return sm->eapol_cb->get_eapReqData(sm->eapol_ctx, len);
00208 }
00209
00210
00211 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
00212 {
00213 if (sm->m == NULL || sm->eap_method_priv == NULL)
00214 return;
00215
00216 wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
00217 "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
00218 sm->m->deinit(sm, sm->eap_method_priv);
00219 sm->eap_method_priv = NULL;
00220 sm->m = NULL;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 SM_STATE(EAP, INITIALIZE)
00230 {
00231 SM_ENTRY(EAP, INITIALIZE);
00232 if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
00233 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
00234 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
00235 "fast reauthentication");
00236 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
00237 } else {
00238 eap_deinit_prev_method(sm, "INITIALIZE");
00239 }
00240 sm->selectedMethod = EAP_TYPE_NONE;
00241 sm->methodState = METHOD_NONE;
00242 sm->allowNotifications = TRUE;
00243 sm->decision = DECISION_FAIL;
00244 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00245 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
00246 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
00247 free(sm->eapKeyData);
00248 sm->eapKeyData = NULL;
00249 sm->eapKeyAvailable = FALSE;
00250 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
00251 sm->lastId = -1;
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
00262 eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
00263 sm->num_rounds = 0;
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 SM_STATE(EAP, DISABLED)
00273 {
00274 SM_ENTRY(EAP, DISABLED);
00275 sm->num_rounds = 0;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284 SM_STATE(EAP, IDLE)
00285 {
00286 SM_ENTRY(EAP, IDLE);
00287 }
00288
00289
00290
00291
00292
00293
00294 SM_STATE(EAP, RECEIVED)
00295 {
00296 const u8 *eapReqData;
00297 size_t eapReqDataLen;
00298
00299 SM_ENTRY(EAP, RECEIVED);
00300 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
00301
00302 eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
00303 sm->num_rounds++;
00304 }
00305
00306
00307
00308
00309
00310
00311 SM_STATE(EAP, GET_METHOD)
00312 {
00313 SM_ENTRY(EAP, GET_METHOD);
00314 if (eap_sm_allowMethod(sm, sm->reqMethod)) {
00315 int reinit = 0;
00316
00317
00318
00319
00320
00321
00322
00323
00324 if (sm->fast_reauth &&
00325 sm->m && sm->m->method == sm->reqMethod &&
00326 sm->m->has_reauth_data &&
00327 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
00328 wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
00329 " for fast re-authentication");
00330 reinit = 1;
00331 } else
00332 eap_deinit_prev_method(sm, "GET_METHOD");
00333 sm->selectedMethod = sm->reqMethod;
00334 if (sm->m == NULL)
00335 sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
00336 if (sm->m) {
00337 wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP "
00338 "method (%d, %s)",
00339 sm->selectedMethod, sm->m->name);
00340 if (reinit)
00341 sm->eap_method_priv = sm->m->init_for_reauth(
00342 sm, sm->eap_method_priv);
00343 else
00344 sm->eap_method_priv = sm->m->init(sm);
00345 if (sm->eap_method_priv == NULL) {
00346 struct wpa_ssid *config = eap_get_config(sm);
00347 wpa_msg(sm->msg_ctx, MSG_INFO,
00348 "EAP: Failed to initialize EAP method "
00349 "%d (%s)",
00350 sm->selectedMethod, sm->m->name);
00351 sm->m = NULL;
00352 sm->methodState = METHOD_NONE;
00353 sm->selectedMethod = EAP_TYPE_NONE;
00354 if (sm->reqMethod == EAP_TYPE_TLS &&
00355 config &&
00356 (config->pending_req_pin ||
00357 config->pending_req_passphrase)) {
00358
00359
00360
00361
00362
00363
00364 wpa_printf(MSG_DEBUG, "EAP: Pending "
00365 "PIN/passphrase request - "
00366 "skip Nak");
00367 return;
00368 }
00369 } else {
00370 sm->methodState = METHOD_INIT;
00371 wpa_msg(sm->msg_ctx, MSG_INFO,
00372 WPA_EVENT_EAP_METHOD
00373 "EAP method %d (%s) selected",
00374 sm->selectedMethod, sm->m->name);
00375 return;
00376 }
00377 }
00378 }
00379
00380 free(sm->eapRespData);
00381 sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
00382 }
00383
00384
00385
00386
00387
00388
00389 SM_STATE(EAP, METHOD)
00390 {
00391 u8 *eapReqData;
00392 size_t eapReqDataLen;
00393 struct eap_method_ret ret;
00394
00395 SM_ENTRY(EAP, METHOD);
00396 if (sm->m == NULL) {
00397 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
00398 return;
00399 }
00400
00401 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 memset(&ret, 0, sizeof(ret));
00418 ret.ignore = sm->ignore;
00419 ret.methodState = sm->methodState;
00420 ret.decision = sm->decision;
00421 ret.allowNotifications = sm->allowNotifications;
00422 free(sm->eapRespData);
00423 sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
00424 eapReqData, eapReqDataLen,
00425 &sm->eapRespDataLen);
00426 wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
00427 "methodState=%s decision=%s",
00428 ret.ignore ? "TRUE" : "FALSE",
00429 eap_sm_method_state_txt(ret.methodState),
00430 eap_sm_decision_txt(ret.decision));
00431
00432 sm->ignore = ret.ignore;
00433 if (sm->ignore)
00434 return;
00435 sm->methodState = ret.methodState;
00436 sm->decision = ret.decision;
00437 sm->allowNotifications = ret.allowNotifications;
00438
00439 if (sm->m->isKeyAvailable && sm->m->getKey &&
00440 sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
00441 free(sm->eapKeyData);
00442 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
00443 &sm->eapKeyDataLen);
00444 }
00445 }
00446
00447
00448
00449
00450
00451
00452 SM_STATE(EAP, SEND_RESPONSE)
00453 {
00454 SM_ENTRY(EAP, SEND_RESPONSE);
00455 free(sm->lastRespData);
00456 if (sm->eapRespData) {
00457 if (sm->workaround)
00458 memcpy(sm->last_md5, sm->req_md5, 16);
00459 sm->lastId = sm->reqId;
00460 sm->lastRespData = malloc(sm->eapRespDataLen);
00461 if (sm->lastRespData) {
00462 memcpy(sm->lastRespData, sm->eapRespData,
00463 sm->eapRespDataLen);
00464 sm->lastRespDataLen = sm->eapRespDataLen;
00465 }
00466 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
00467 } else
00468 sm->lastRespData = NULL;
00469 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00470 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00471 }
00472
00473
00474
00475
00476
00477
00478 SM_STATE(EAP, DISCARD)
00479 {
00480 SM_ENTRY(EAP, DISCARD);
00481 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00482 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00483 }
00484
00485
00486
00487
00488
00489 SM_STATE(EAP, IDENTITY)
00490 {
00491 const u8 *eapReqData;
00492 size_t eapReqDataLen;
00493
00494 SM_ENTRY(EAP, IDENTITY);
00495 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
00496 eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
00497 free(sm->eapRespData);
00498 sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
00499 &sm->eapRespDataLen, 0);
00500 }
00501
00502
00503
00504
00505
00506 SM_STATE(EAP, NOTIFICATION)
00507 {
00508 const u8 *eapReqData;
00509 size_t eapReqDataLen;
00510
00511 SM_ENTRY(EAP, NOTIFICATION);
00512 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
00513 eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
00514 free(sm->eapRespData);
00515 sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
00516 &sm->eapRespDataLen);
00517 }
00518
00519
00520
00521
00522
00523 SM_STATE(EAP, RETRANSMIT)
00524 {
00525 SM_ENTRY(EAP, RETRANSMIT);
00526 free(sm->eapRespData);
00527 if (sm->lastRespData) {
00528 sm->eapRespData = malloc(sm->lastRespDataLen);
00529 if (sm->eapRespData) {
00530 memcpy(sm->eapRespData, sm->lastRespData,
00531 sm->lastRespDataLen);
00532 sm->eapRespDataLen = sm->lastRespDataLen;
00533 }
00534 } else
00535 sm->eapRespData = NULL;
00536 }
00537
00538
00539
00540
00541
00542
00543
00544 SM_STATE(EAP, SUCCESS)
00545 {
00546 SM_ENTRY(EAP, SUCCESS);
00547 if (sm->eapKeyData != NULL)
00548 sm->eapKeyAvailable = TRUE;
00549 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
00550
00551
00552
00553
00554
00555
00556 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00557
00558
00559
00560
00561
00562
00563
00564 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00565
00566 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
00567 "EAP authentication completed successfully");
00568 }
00569
00570
00571
00572
00573
00574
00575 SM_STATE(EAP, FAILURE)
00576 {
00577 SM_ENTRY(EAP, FAILURE);
00578 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
00579
00580
00581
00582
00583
00584
00585 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00586
00587
00588
00589
00590
00591
00592 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00593
00594 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
00595 "EAP authentication failed");
00596 }
00597
00598
00599 static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
00600 {
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
00612 reqId == ((lastId + 2) & 0xff))) {
00613 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
00614 "identifier field in EAP Success: "
00615 "reqId=%d lastId=%d (these are supposed to be "
00616 "same)", reqId, lastId);
00617 return 1;
00618 }
00619 wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
00620 "lastId=%d", reqId, lastId);
00621 return 0;
00622 }
00623
00624
00625
00626
00627
00628 SM_STEP(EAP)
00629 {
00630 int duplicate;
00631
00632 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
00633 eapol_get_bool(sm, EAPOL_portEnabled))
00634 SM_ENTER_GLOBAL(EAP, INITIALIZE);
00635 else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
00636 SM_ENTER_GLOBAL(EAP, DISABLED);
00637 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
00638
00639
00640
00641
00642
00643
00644
00645
00646 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
00647 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
00648 "authentication rounds - abort",
00649 EAP_MAX_AUTH_ROUNDS);
00650 sm->num_rounds++;
00651 SM_ENTER_GLOBAL(EAP, FAILURE);
00652 }
00653 } else switch (sm->EAP_state) {
00654 case EAP_INITIALIZE:
00655 SM_ENTER(EAP, IDLE);
00656 break;
00657 case EAP_DISABLED:
00658 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
00659 !sm->force_disabled)
00660 SM_ENTER(EAP, INITIALIZE);
00661 break;
00662 case EAP_IDLE:
00663
00664
00665
00666
00667
00668 if (eapol_get_bool(sm, EAPOL_eapReq))
00669 SM_ENTER(EAP, RECEIVED);
00670 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
00671 sm->decision != DECISION_FAIL) ||
00672 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00673 sm->decision == DECISION_UNCOND_SUCC))
00674 SM_ENTER(EAP, SUCCESS);
00675 else if (eapol_get_bool(sm, EAPOL_altReject) ||
00676 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00677 sm->decision != DECISION_UNCOND_SUCC) ||
00678 (eapol_get_bool(sm, EAPOL_altAccept) &&
00679 sm->methodState != METHOD_CONT &&
00680 sm->decision == DECISION_FAIL))
00681 SM_ENTER(EAP, FAILURE);
00682 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00683 sm->leap_done && sm->decision != DECISION_FAIL &&
00684 sm->methodState == METHOD_DONE)
00685 SM_ENTER(EAP, SUCCESS);
00686 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
00687 sm->peap_done && sm->decision != DECISION_FAIL &&
00688 sm->methodState == METHOD_DONE)
00689 SM_ENTER(EAP, SUCCESS);
00690 break;
00691 case EAP_RECEIVED:
00692 duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
00693 if (sm->workaround && duplicate &&
00694 memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
00705 " but EAP packets were not identical");
00706 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
00707 "is not a duplicate packet");
00708 duplicate = 0;
00709 }
00710
00711
00712
00713
00714
00715
00716
00717 if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
00718 (sm->reqId == sm->lastId ||
00719 eap_success_workaround(sm, sm->reqId, sm->lastId)))
00720 SM_ENTER(EAP, SUCCESS);
00721 else if (sm->methodState != METHOD_CONT &&
00722 ((sm->rxFailure &&
00723 sm->decision != DECISION_UNCOND_SUCC) ||
00724 (sm->rxSuccess && sm->decision == DECISION_FAIL &&
00725 (sm->selectedMethod != EAP_TYPE_LEAP ||
00726 sm->methodState != METHOD_MAY_CONT))) &&
00727 (sm->reqId == sm->lastId ||
00728 eap_success_workaround(sm, sm->reqId, sm->lastId)))
00729 SM_ENTER(EAP, FAILURE);
00730 else if (sm->rxReq && duplicate)
00731 SM_ENTER(EAP, RETRANSMIT);
00732 else if (sm->rxReq && !duplicate &&
00733 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
00734 sm->allowNotifications)
00735 SM_ENTER(EAP, NOTIFICATION);
00736 else if (sm->rxReq && !duplicate &&
00737 sm->selectedMethod == EAP_TYPE_NONE &&
00738 sm->reqMethod == EAP_TYPE_IDENTITY)
00739 SM_ENTER(EAP, IDENTITY);
00740 else if (sm->rxReq && !duplicate &&
00741 sm->selectedMethod == EAP_TYPE_NONE &&
00742 sm->reqMethod != EAP_TYPE_IDENTITY &&
00743 sm->reqMethod != EAP_TYPE_NOTIFICATION)
00744 SM_ENTER(EAP, GET_METHOD);
00745 else if (sm->rxReq && !duplicate &&
00746 sm->reqMethod == sm->selectedMethod &&
00747 sm->methodState != METHOD_DONE)
00748 SM_ENTER(EAP, METHOD);
00749 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00750 (sm->rxSuccess || sm->rxResp))
00751 SM_ENTER(EAP, METHOD);
00752 else
00753 SM_ENTER(EAP, DISCARD);
00754 break;
00755 case EAP_GET_METHOD:
00756 if (sm->selectedMethod == sm->reqMethod)
00757 SM_ENTER(EAP, METHOD);
00758 else
00759 SM_ENTER(EAP, SEND_RESPONSE);
00760 break;
00761 case EAP_METHOD:
00762 if (sm->ignore)
00763 SM_ENTER(EAP, DISCARD);
00764 else
00765 SM_ENTER(EAP, SEND_RESPONSE);
00766 break;
00767 case EAP_SEND_RESPONSE:
00768 SM_ENTER(EAP, IDLE);
00769 break;
00770 case EAP_DISCARD:
00771 SM_ENTER(EAP, IDLE);
00772 break;
00773 case EAP_IDENTITY:
00774 SM_ENTER(EAP, SEND_RESPONSE);
00775 break;
00776 case EAP_NOTIFICATION:
00777 SM_ENTER(EAP, SEND_RESPONSE);
00778 break;
00779 case EAP_RETRANSMIT:
00780 SM_ENTER(EAP, SEND_RESPONSE);
00781 break;
00782 case EAP_SUCCESS:
00783 break;
00784 case EAP_FAILURE:
00785 break;
00786 }
00787 }
00788
00789
00790 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
00791 {
00792 struct wpa_ssid *config = eap_get_config(sm);
00793 int i;
00794
00795 if (!wpa_config_allowed_eap_method(config, method))
00796 return FALSE;
00797 for (i = 0; i < NUM_EAP_METHODS; i++) {
00798 if (eap_methods[i]->method == method)
00799 return TRUE;
00800 }
00801 return FALSE;
00802 }
00803
00804
00805 static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
00806 {
00807 struct wpa_ssid *config = eap_get_config(sm);
00808 struct eap_hdr *resp;
00809 u8 *pos;
00810 int i, found = 0;
00811
00812 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
00813 "allowed)", sm->reqMethod);
00814 *len = sizeof(struct eap_hdr) + 1;
00815 resp = malloc(*len + NUM_EAP_METHODS);
00816 if (resp == NULL)
00817 return NULL;
00818
00819 resp->code = EAP_CODE_RESPONSE;
00820 resp->identifier = id;
00821 pos = (u8 *) (resp + 1);
00822 *pos++ = EAP_TYPE_NAK;
00823
00824 for (i = 0; i < NUM_EAP_METHODS; i++) {
00825 if (eap_methods[i]->method != sm->reqMethod &&
00826 wpa_config_allowed_eap_method(config,
00827 eap_methods[i]->method)) {
00828 *pos++ = eap_methods[i]->method;
00829 (*len)++;
00830 found++;
00831 }
00832 }
00833 if (!found) {
00834 *pos = EAP_TYPE_NONE;
00835 (*len)++;
00836 }
00837 wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",
00838 ((u8 *) (resp + 1)) + 1, found);
00839
00840 resp->length = host_to_be16(*len);
00841
00842 return (u8 *) resp;
00843 }
00844
00845
00846 static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
00847 size_t len)
00848 {
00849 const struct eap_hdr *hdr = (const struct eap_hdr *) req;
00850 const u8 *pos = (const u8 *) (hdr + 1);
00851 pos++;
00852
00853 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
00854 "EAP authentication started");
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
00866 pos, be_to_host16(hdr->length) - 5);
00867 }
00868
00869
00870 static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
00871 {
00872 int aka = 0;
00873 char imsi[100];
00874 size_t imsi_len;
00875 u8 *pos = ssid->eap_methods;
00876
00877 imsi_len = sizeof(imsi);
00878 if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
00879 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
00880 return -1;
00881 }
00882
00883 wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
00884
00885 while (pos && *pos != EAP_TYPE_NONE) {
00886 if (*pos == EAP_TYPE_AKA) {
00887 aka = 1;
00888 break;
00889 }
00890 pos++;
00891 }
00892
00893 free(ssid->identity);
00894 ssid->identity = malloc(1 + imsi_len);
00895 if (ssid->identity == NULL) {
00896 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
00897 "IMSI-based identity");
00898 return -1;
00899 }
00900
00901 ssid->identity[0] = aka ? '0' : '1';
00902 memcpy(ssid->identity + 1, imsi, imsi_len);
00903 ssid->identity_len = 1 + imsi_len;
00904 return 0;
00905 }
00906
00907
00908 static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
00909 {
00910 if (scard_set_pin(sm->scard_ctx, ssid->pin)) {
00911
00912
00913
00914
00915 free(ssid->pin);
00916 ssid->pin = NULL;
00917
00918 wpa_printf(MSG_WARNING, "PIN validation failed");
00919 eap_sm_request_pin(sm, ssid);
00920 return -1;
00921 }
00922
00923 return eap_sm_imsi_identity(sm, ssid);
00924 }
00925
00926
00940 u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
00941 int encrypted)
00942 {
00943 struct wpa_ssid *config = eap_get_config(sm);
00944 struct eap_hdr *resp;
00945 u8 *pos;
00946 const u8 *identity;
00947 size_t identity_len;
00948
00949 if (config == NULL) {
00950 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
00951 "was not available");
00952 return NULL;
00953 }
00954
00955 if (sm->m && sm->m->get_identity &&
00956 (identity = sm->m->get_identity(sm, sm->eap_method_priv,
00957 &identity_len)) != NULL) {
00958 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
00959 "identity", identity, identity_len);
00960 } else if (!encrypted && config->anonymous_identity) {
00961 identity = config->anonymous_identity;
00962 identity_len = config->anonymous_identity_len;
00963 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
00964 identity, identity_len);
00965 } else {
00966 identity = config->identity;
00967 identity_len = config->identity_len;
00968 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
00969 identity, identity_len);
00970 }
00971
00972 if (identity == NULL) {
00973 wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
00974 "configuration was not available");
00975 if (config->pcsc) {
00976 if (eap_sm_get_scard_identity(sm, config) < 0)
00977 return NULL;
00978 identity = config->identity;
00979 identity_len = config->identity_len;
00980 wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
00981 "IMSI", identity, identity_len);
00982 } else {
00983 eap_sm_request_identity(sm, config);
00984 return NULL;
00985 }
00986 }
00987
00988 *len = sizeof(struct eap_hdr) + 1 + identity_len;
00989 resp = malloc(*len);
00990 if (resp == NULL)
00991 return NULL;
00992
00993 resp->code = EAP_CODE_RESPONSE;
00994 resp->identifier = id;
00995 resp->length = host_to_be16(*len);
00996 pos = (u8 *) (resp + 1);
00997 *pos++ = EAP_TYPE_IDENTITY;
00998 memcpy(pos, identity, identity_len);
00999
01000 return (u8 *) resp;
01001 }
01002
01003
01004 static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
01005 {
01006 const struct eap_hdr *hdr = (const struct eap_hdr *) req;
01007 const u8 *pos;
01008 char *msg;
01009 size_t msg_len;
01010 int i;
01011
01012 pos = (const u8 *) (hdr + 1);
01013 pos++;
01014
01015 msg_len = be_to_host16(hdr->length);
01016 if (msg_len < 5)
01017 return;
01018 msg_len -= 5;
01019 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
01020 pos, msg_len);
01021
01022 msg = malloc(msg_len + 1);
01023 if (msg == NULL)
01024 return;
01025 for (i = 0; i < msg_len; i++)
01026 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
01027 msg[msg_len] = '\0';
01028 wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
01029 WPA_EVENT_EAP_NOTIFICATION, msg);
01030 free(msg);
01031 }
01032
01033
01034 static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
01035 {
01036 struct eap_hdr *resp;
01037 u8 *pos;
01038
01039 wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
01040 *len = sizeof(struct eap_hdr) + 1;
01041 resp = malloc(*len);
01042 if (resp == NULL)
01043 return NULL;
01044
01045 resp->code = EAP_CODE_RESPONSE;
01046 resp->identifier = id;
01047 resp->length = host_to_be16(*len);
01048 pos = (u8 *) (resp + 1);
01049 *pos = EAP_TYPE_NOTIFICATION;
01050
01051 return (u8 *) resp;
01052 }
01053
01054
01055 static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
01056 {
01057 const struct eap_hdr *hdr;
01058 size_t plen;
01059
01060 sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
01061 sm->reqId = 0;
01062 sm->reqMethod = EAP_TYPE_NONE;
01063
01064 if (req == NULL || len < sizeof(*hdr))
01065 return;
01066
01067 hdr = (const struct eap_hdr *) req;
01068 plen = be_to_host16(hdr->length);
01069 if (plen > len) {
01070 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
01071 "(len=%lu plen=%lu)",
01072 (unsigned long) len, (unsigned long) plen);
01073 return;
01074 }
01075
01076 sm->reqId = hdr->identifier;
01077
01078 if (sm->workaround) {
01079 md5_vector(1, (const u8 **) &req, &len, sm->req_md5);
01080 }
01081
01082 switch (hdr->code) {
01083 case EAP_CODE_REQUEST:
01084 sm->rxReq = TRUE;
01085 if (plen > sizeof(*hdr))
01086 sm->reqMethod = *((u8 *) (hdr + 1));
01087 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
01088 "id=%d", sm->reqMethod, sm->reqId);
01089 break;
01090 case EAP_CODE_RESPONSE:
01091 if (sm->selectedMethod == EAP_TYPE_LEAP) {
01092
01093
01094
01095
01096
01097 sm->rxResp = TRUE;
01098 if (plen > sizeof(*hdr))
01099 sm->reqMethod = *((u8 *) (hdr + 1));
01100 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
01101 "LEAP method=%d id=%d",
01102 sm->reqMethod, sm->reqId);
01103 break;
01104 }
01105 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
01106 break;
01107 case EAP_CODE_SUCCESS:
01108 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
01109 sm->rxSuccess = TRUE;
01110 break;
01111 case EAP_CODE_FAILURE:
01112 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
01113 sm->rxFailure = TRUE;
01114 break;
01115 default:
01116 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
01117 "code %d", hdr->code);
01118 break;
01119 }
01120 }
01121
01122
01138 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
01139 void *msg_ctx, struct eap_config *conf)
01140 {
01141 struct eap_sm *sm;
01142 struct tls_config tlsconf;
01143
01144 sm = malloc(sizeof(*sm));
01145 if (sm == NULL)
01146 return NULL;
01147 memset(sm, 0, sizeof(*sm));
01148 sm->eapol_ctx = eapol_ctx;
01149 sm->eapol_cb = eapol_cb;
01150 sm->msg_ctx = msg_ctx;
01151 sm->ClientTimeout = 60;
01152
01153 memset(&tlsconf, 0, sizeof(tlsconf));
01154 tlsconf.opensc_engine_path = conf->opensc_engine_path;
01155 tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
01156 tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
01157 sm->ssl_ctx = tls_init(&tlsconf);
01158 if (sm->ssl_ctx == NULL) {
01159 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
01160 "context.");
01161 free(sm);
01162 return NULL;
01163 }
01164
01165 return sm;
01166 }
01167
01168
01177 void eap_sm_deinit(struct eap_sm *sm)
01178 {
01179 if (sm == NULL)
01180 return;
01181 eap_deinit_prev_method(sm, "EAP deinit");
01182 eap_sm_abort(sm);
01183 tls_deinit(sm->ssl_ctx);
01184 free(sm);
01185 }
01186
01187
01198 int eap_sm_step(struct eap_sm *sm)
01199 {
01200 int res = 0;
01201 do {
01202 sm->changed = FALSE;
01203 SM_STEP_RUN(EAP);
01204 if (sm->changed)
01205 res = 1;
01206 } while (sm->changed);
01207 return res;
01208 }
01209
01210
01219 void eap_sm_abort(struct eap_sm *sm)
01220 {
01221 free(sm->lastRespData);
01222 sm->lastRespData = NULL;
01223 free(sm->eapRespData);
01224 sm->eapRespData = NULL;
01225 free(sm->eapKeyData);
01226 sm->eapKeyData = NULL;
01227 }
01228
01229
01230 static const char * eap_sm_state_txt(int state)
01231 {
01232 switch (state) {
01233 case EAP_INITIALIZE:
01234 return "INITIALIZE";
01235 case EAP_DISABLED:
01236 return "DISABLED";
01237 case EAP_IDLE:
01238 return "IDLE";
01239 case EAP_RECEIVED:
01240 return "RECEIVED";
01241 case EAP_GET_METHOD:
01242 return "GET_METHOD";
01243 case EAP_METHOD:
01244 return "METHOD";
01245 case EAP_SEND_RESPONSE:
01246 return "SEND_RESPONSE";
01247 case EAP_DISCARD:
01248 return "DISCARD";
01249 case EAP_IDENTITY:
01250 return "IDENTITY";
01251 case EAP_NOTIFICATION:
01252 return "NOTIFICATION";
01253 case EAP_RETRANSMIT:
01254 return "RETRANSMIT";
01255 case EAP_SUCCESS:
01256 return "SUCCESS";
01257 case EAP_FAILURE:
01258 return "FAILURE";
01259 default:
01260 return "UNKNOWN";
01261 }
01262 }
01263
01264
01265 static const char * eap_sm_method_state_txt(EapMethodState state)
01266 {
01267 switch (state) {
01268 case METHOD_NONE:
01269 return "NONE";
01270 case METHOD_INIT:
01271 return "INIT";
01272 case METHOD_CONT:
01273 return "CONT";
01274 case METHOD_MAY_CONT:
01275 return "MAY_CONT";
01276 case METHOD_DONE:
01277 return "DONE";
01278 default:
01279 return "UNKNOWN";
01280 }
01281 }
01282
01283
01284 static const char * eap_sm_decision_txt(EapDecision decision)
01285 {
01286 switch (decision) {
01287 case DECISION_FAIL:
01288 return "FAIL";
01289 case DECISION_COND_SUCC:
01290 return "COND_SUCC";
01291 case DECISION_UNCOND_SUCC:
01292 return "UNCOND_SUCC";
01293 default:
01294 return "UNKNOWN";
01295 }
01296 }
01297
01298
01313 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
01314 {
01315 int len;
01316
01317 if (sm == NULL)
01318 return 0;
01319
01320 len = snprintf(buf, buflen,
01321 "EAP state=%s\n",
01322 eap_sm_state_txt(sm->EAP_state));
01323
01324 if (sm->selectedMethod != EAP_TYPE_NONE) {
01325 const char *name;
01326 if (sm->m) {
01327 name = sm->m->name;
01328 } else {
01329 const struct eap_method *m =
01330 eap_sm_get_eap_methods(sm->selectedMethod);
01331 if (m)
01332 name = m->name;
01333 else
01334 name = "?";
01335 }
01336 len += snprintf(buf + len, buflen - len,
01337 "selectedMethod=%d (EAP-%s)\n",
01338 sm->selectedMethod, name);
01339
01340 if (sm->m && sm->m->get_status) {
01341 len += sm->m->get_status(sm, sm->eap_method_priv,
01342 buf + len, buflen - len,
01343 verbose);
01344 }
01345 }
01346
01347 if (verbose) {
01348 len += snprintf(buf + len, buflen - len,
01349 "reqMethod=%d\n"
01350 "methodState=%s\n"
01351 "decision=%s\n"
01352 "ClientTimeout=%d\n",
01353 sm->reqMethod,
01354 eap_sm_method_state_txt(sm->methodState),
01355 eap_sm_decision_txt(sm->decision),
01356 sm->ClientTimeout);
01357 }
01358
01359 return len;
01360 }
01361
01362
01363 typedef enum {
01364 TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
01365 TYPE_PASSPHRASE
01366 } eap_ctrl_req_type;
01367
01368 static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
01369 eap_ctrl_req_type type, const char *msg,
01370 size_t msglen)
01371 {
01372 char *buf;
01373 size_t buflen;
01374 int len;
01375 char *field;
01376 char *txt, *tmp;
01377
01378 if (config == NULL || sm == NULL)
01379 return;
01380
01381 switch (type) {
01382 case TYPE_IDENTITY:
01383 field = "IDENTITY";
01384 txt = "Identity";
01385 config->pending_req_identity++;
01386 break;
01387 case TYPE_PASSWORD:
01388 field = "PASSWORD";
01389 txt = "Password";
01390 config->pending_req_password++;
01391 break;
01392 case TYPE_NEW_PASSWORD:
01393 field = "NEW_PASSWORD";
01394 txt = "New Password";
01395 config->pending_req_new_password++;
01396 break;
01397 case TYPE_PIN:
01398 field = "PIN";
01399 txt = "PIN";
01400 config->pending_req_pin++;
01401 break;
01402 case TYPE_OTP:
01403 field = "OTP";
01404 if (msg) {
01405 tmp = malloc(msglen + 3);
01406 if (tmp == NULL)
01407 return;
01408 tmp[0] = '[';
01409 memcpy(tmp + 1, msg, msglen);
01410 tmp[msglen + 1] = ']';
01411 tmp[msglen + 2] = '\0';
01412 txt = tmp;
01413 free(config->pending_req_otp);
01414 config->pending_req_otp = tmp;
01415 config->pending_req_otp_len = msglen + 3;
01416 } else {
01417 if (config->pending_req_otp == NULL)
01418 return;
01419 txt = config->pending_req_otp;
01420 }
01421 break;
01422 case TYPE_PASSPHRASE:
01423 field = "PASSPHRASE";
01424 txt = "Private key passphrase";
01425 config->pending_req_passphrase++;
01426 break;
01427 default:
01428 return;
01429 }
01430
01431 buflen = 100 + strlen(txt) + config->ssid_len;
01432 buf = malloc(buflen);
01433 if (buf == NULL)
01434 return;
01435 len = snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
01436 field, config->id, txt);
01437 if (config->ssid && buflen > len + config->ssid_len) {
01438 memcpy(buf + len, config->ssid, config->ssid_len);
01439 len += config->ssid_len;
01440 buf[len] = '\0';
01441 }
01442 wpa_msg(sm->msg_ctx, MSG_INFO, "%s", buf);
01443 free(buf);
01444 }
01445
01446
01458 void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
01459 {
01460 eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
01461 }
01462
01463
01475 void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
01476 {
01477 eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
01478 }
01479
01480
01492 void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config)
01493 {
01494 eap_sm_request(sm, config, TYPE_NEW_PASSWORD, NULL, 0);
01495 }
01496
01497
01509 void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config)
01510 {
01511 eap_sm_request(sm, config, TYPE_PIN, NULL, 0);
01512 }
01513
01514
01527 void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
01528 const char *msg, size_t msg_len)
01529 {
01530 eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
01531 }
01532
01533
01545 void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config)
01546 {
01547 eap_sm_request(sm, config, TYPE_PASSPHRASE, NULL, 0);
01548 }
01549
01550
01559 void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
01560 {
01561 struct wpa_ssid *config = eap_get_config(sm);
01562
01563 if (config == NULL)
01564 return;
01565
01566
01567
01568
01569
01570 if (config->pending_req_identity)
01571 eap_sm_request_identity(sm, config);
01572 if (config->pending_req_password)
01573 eap_sm_request_password(sm, config);
01574 if (config->pending_req_new_password)
01575 eap_sm_request_new_password(sm, config);
01576 if (config->pending_req_otp)
01577 eap_sm_request_otp(sm, config, NULL, 0);
01578 if (config->pending_req_pin)
01579 eap_sm_request_pin(sm, config);
01580 if (config->pending_req_passphrase)
01581 eap_sm_request_passphrase(sm, config);
01582 }
01583
01584
01594 u8 eap_get_type(const char *name)
01595 {
01596 int i;
01597 for (i = 0; i < NUM_EAP_METHODS; i++) {
01598 if (strcmp(eap_methods[i]->name, name) == 0)
01599 return eap_methods[i]->method;
01600 }
01601 return EAP_TYPE_NONE;
01602 }
01603
01604
01614 const char * eap_get_name(EapType type)
01615 {
01616 int i;
01617 for (i = 0; i < NUM_EAP_METHODS; i++) {
01618 if (eap_methods[i]->method == type)
01619 return eap_methods[i]->name;
01620 }
01621 return NULL;
01622 }
01623
01624
01633 size_t eap_get_names(char *buf, size_t buflen)
01634 {
01635 char *pos, *end;
01636 int i;
01637
01638 pos = buf;
01639 end = pos + buflen;
01640
01641 for (i = 0; i < NUM_EAP_METHODS; i++) {
01642 pos += snprintf(pos, end - pos, "%s%s",
01643 i == 0 ? "" : " ", eap_methods[i]->name);
01644 }
01645
01646 return pos - buf;
01647 }
01648
01649
01650 static int eap_allowed_phase2_type(int type)
01651 {
01652 return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
01653 type != EAP_TYPE_FAST;
01654 }
01655
01656
01667 u8 eap_get_phase2_type(const char *name)
01668 {
01669 u8 type = eap_get_type(name);
01670 if (eap_allowed_phase2_type(type))
01671 return type;
01672 return EAP_TYPE_NONE;
01673 }
01674
01675
01686 u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
01687 {
01688 u8 *buf, method;
01689 int i;
01690
01691 *count = 0;
01692 buf = malloc(NUM_EAP_METHODS);
01693 if (buf == NULL)
01694 return NULL;
01695
01696 for (i = 0; i < NUM_EAP_METHODS; i++) {
01697 method = eap_methods[i]->method;
01698 if (eap_allowed_phase2_type(method)) {
01699 if (method == EAP_TYPE_TLS && config &&
01700 config->private_key2 == NULL)
01701 continue;
01702 buf[*count] = method;
01703 (*count)++;
01704 }
01705 }
01706
01707 return buf;
01708 }
01709
01710
01717 void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
01718 {
01719 sm->fast_reauth = enabled;
01720 }
01721
01722
01729 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
01730 {
01731 sm->workaround = workaround;
01732 }
01733
01734
01741 struct wpa_ssid * eap_get_config(struct eap_sm *sm)
01742 {
01743 return sm->eapol_cb->get_config(sm->eapol_ctx);
01744 }
01745
01746
01753 int eap_key_available(struct eap_sm *sm)
01754 {
01755 return sm ? sm->eapKeyAvailable : 0;
01756 }
01757
01758
01769 void eap_notify_success(struct eap_sm *sm)
01770 {
01771 if (sm) {
01772 sm->decision = DECISION_COND_SUCC;
01773 sm->EAP_state = EAP_SUCCESS;
01774 }
01775 }
01776
01777
01786 void eap_notify_lower_layer_success(struct eap_sm *sm)
01787 {
01788 if (sm == NULL)
01789 return;
01790
01791 if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
01792 sm->decision == DECISION_FAIL ||
01793 (sm->methodState != METHOD_MAY_CONT &&
01794 sm->methodState != METHOD_DONE))
01795 return;
01796
01797 if (sm->eapKeyData != NULL)
01798 sm->eapKeyAvailable = TRUE;
01799 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
01800 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
01801 "EAP authentication completed successfully (based on lower "
01802 "layer success)");
01803 }
01804
01805
01818 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
01819 {
01820 if (sm == NULL || sm->eapKeyData == NULL) {
01821 *len = 0;
01822 return NULL;
01823 }
01824
01825 *len = sm->eapKeyDataLen;
01826 return sm->eapKeyData;
01827 }
01828
01829
01842 u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
01843 {
01844 u8 *resp;
01845
01846 if (sm == NULL || sm->eapRespData == NULL) {
01847 *len = 0;
01848 return NULL;
01849 }
01850
01851 resp = sm->eapRespData;
01852 *len = sm->eapRespDataLen;
01853 sm->eapRespData = NULL;
01854 sm->eapRespDataLen = 0;
01855
01856 return resp;
01857 }
01858
01859
01869 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
01870 {
01871 if (sm)
01872 sm->scard_ctx = ctx;
01873 }
01874
01875
01889 const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
01890 size_t *plen)
01891 {
01892 const struct eap_hdr *hdr;
01893 const u8 *pos;
01894 size_t len;
01895
01896 hdr = (const struct eap_hdr *) msg;
01897 pos = (const u8 *) (hdr + 1);
01898 if (msglen < sizeof(*hdr) + 1 || *pos != eap_type) {
01899 wpa_printf(MSG_INFO, "EAP: Invalid frame type");
01900 return NULL;
01901 }
01902 len = be_to_host16(hdr->length);
01903 if (len < sizeof(*hdr) + 1 || len > msglen) {
01904 wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
01905 return NULL;
01906 }
01907 *plen = len - sizeof(*hdr) - 1;
01908 return pos + 1;
01909 }
01910
01911
01921 void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
01922 {
01923 sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
01924 }
01925
01926
01934 const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
01935 const char *name)
01936 {
01937 return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
01938 }
01939
01940
01950 void eap_set_force_disabled(struct eap_sm *sm, int disabled)
01951 {
01952 sm->force_disabled = disabled;
01953 }
01954