eap.c

Go to the documentation of this file.
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 /* Definitions for clarifying state machine implementation */
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  * This state initializes state machine variables when the machine is
00226  * activated (portEnabled = TRUE). This is also used when re-starting
00227  * authentication (eapRestart == TRUE).
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; /* new session - make sure this does not match with
00252                           * the first EAP-Packet */
00253         /*
00254          * RFC 4137 does not reset eapResp and eapNoResp here. However, this
00255          * seemed to be able to trigger cases where both were set and if EAPOL
00256          * state machine uses eapNoResp first, it may end up not sending a real
00257          * reply correctly. This occurred when the workaround in FAIL state set
00258          * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
00259          * something else(?)
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  * This state is reached whenever service from the lower layer is interrupted
00269  * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
00270  * occurs when the port becomes enabled.
00271  */
00272 SM_STATE(EAP, DISABLED)
00273 {
00274         SM_ENTRY(EAP, DISABLED);
00275         sm->num_rounds = 0;
00276 }
00277 
00278 
00279 /*
00280  * The state machine spends most of its time here, waiting for something to
00281  * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
00282  * SEND_RESPONSE states.
00283  */
00284 SM_STATE(EAP, IDLE)
00285 {
00286         SM_ENTRY(EAP, IDLE);
00287 }
00288 
00289 
00290 /*
00291  * This state is entered when an EAP packet is received (eapReq == TRUE) to
00292  * parse the packet header.
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         /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
00302         eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
00303         sm->num_rounds++;
00304 }
00305 
00306 
00307 /*
00308  * This state is entered when a request for a new type comes in. Either the
00309  * correct method is started, or a Nak response is built.
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                  * RFC 4137 does not define specific operation for fast
00318                  * re-authentication (session resumption). The design here is
00319                  * to allow the previously used method data to be maintained
00320                  * for re-authentication if the method support session
00321                  * resumption. Otherwise, the previously used method data is
00322                  * freed and a new method is allocated here.
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                                          * Return without generating Nak in
00360                                          * order to allow entering of PIN code
00361                                          * or passphrase to retry the current
00362                                          * EAP packet.
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  * The method processing happens here. The request from the authenticator is
00387  * processed, and an appropriate response packet is built.
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          * Get ignore, methodState, decision, allowNotifications, and
00405          * eapRespData. RFC 4137 uses three separate method procedure (check,
00406          * process, and buildResp) in this state. These have been combined into
00407          * a single function call to m->process() in order to optimize EAP
00408          * method implementation interface a bit. These procedures are only
00409          * used from within this METHOD state, so there is no need to keep
00410          * these as separate C functions.
00411          *
00412          * The RFC 4137 procedures return values as follows:
00413          * ignore = m.check(eapReqData)
00414          * (methodState, decision, allowNotifications) = m.process(eapReqData)
00415          * eapRespData = m.buildResp(reqId)
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  * This state signals the lower layer that a response packet is ready to be
00450  * sent.
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  * This state signals the lower layer that the request was discarded, and no
00476  * response packet will be sent at this time.
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  * Handles requests for Identity method and builds a response.
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  * Handles requests for Notification method and builds a response.
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  * This state retransmits the previous response packet.
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  * This state is entered in case of a successful completion of authentication
00541  * and state machine waits here until port is disabled or EAP authentication is
00542  * restarted.
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          * RFC 4137 does not clear eapReq here, but this seems to be required
00553          * to avoid processing the same request twice when state machine is
00554          * initialized.
00555          */
00556         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00557 
00558         /*
00559          * RFC 4137 does not set eapNoResp here, but this seems to be required
00560          * to get EAPOL Supplicant backend state machine into SUCCESS state. In
00561          * addition, either eapResp or eapNoResp is required to be set after
00562          * processing the received EAP frame.
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  * This state is entered in case of a failure and state machine waits here
00573  * until port is disabled or EAP authentication is restarted.
00574  */
00575 SM_STATE(EAP, FAILURE)
00576 {
00577         SM_ENTRY(EAP, FAILURE);
00578         eapol_set_bool(sm, EAPOL_eapFail, TRUE);
00579 
00580         /*
00581          * RFC 4137 does not clear eapReq here, but this seems to be required
00582          * to avoid processing the same request twice when state machine is
00583          * initialized.
00584          */
00585         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00586 
00587         /*
00588          * RFC 4137 does not set eapNoResp here. However, either eapResp or
00589          * eapNoResp is required to be set after processing the received EAP
00590          * frame.
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          * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
00603          * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
00604          * RFC 4137 require that reqId == lastId. In addition, it looks like
00605          * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
00606          *
00607          * Accept this kind of Id if EAP workarounds are enabled. These are
00608          * unauthenticated plaintext messages, so this should have minimal
00609          * security implications (bit easier to fake EAP-Success/Failure).
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  * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
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                 /* RFC 4137 does not place any limit on number of EAP messages
00639                  * in an authentication session. However, some error cases have
00640                  * ended up in a state were EAP messages were sent between the
00641                  * peer and server in a loop (e.g., TLS ACK frame in both
00642                  * direction). Since this is quite undesired outcome, limit the
00643                  * total number of EAP round-trips and abort authentication if
00644                  * this limit is exceeded.
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                  * The first three transitions are from RFC 4137. The last two
00665                  * are local additions to handle special cases with LEAP and
00666                  * PEAP server not sending EAP-Success in some cases.
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                          * RFC 4137 uses (reqId == lastId) as the only
00697                          * verification for duplicate EAP requests. However,
00698                          * this misses cases where the AS is incorrectly using
00699                          * the same id again; and unfortunately, such
00700                          * implementations exist. Use MD5 hash as an extra
00701                          * verification for the packets being duplicate to
00702                          * workaround these issues.
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                  * Two special cases below for LEAP are local additions to work
00713                  * around odd LEAP behavior (EAP-Success in the middle of
00714                  * authentication and then swapped roles). Other transitions
00715                  * are based on RFC 4137.
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          * RFC 3748 - 5.1: Identity
00858          * Data field may contain a displayable message in UTF-8. If this
00859          * includes NUL-character, only the data before that should be
00860          * displayed. Some EAP implementasitons may piggy-back additional
00861          * options after the NUL.
00862          */
00863         /* TODO: could save displayable message so that it can be shown to the
00864          * user in case of interaction is required */
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                  * Make sure the same PIN is not tried again in order to avoid
00913                  * blocking SIM.
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                          * LEAP differs from RFC 4137 by using reversed roles
01094                          * for mutual authentication and because of this, we
01095                          * need to accept EAP-Response frames if LEAP is used.
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         /* Re-send any pending requests for user data since a new control
01567          * interface was added. This handles cases where the EAP authentication
01568          * starts immediately after system startup when the user interface is
01569          * not yet running. */
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 

Generated on Sat May 6 21:13:34 2006 for wpa_supplicant by  doxygen 1.4.2