eapol_auth_sm.c
Go to the documentation of this file.
00001 /*
00002  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
00003  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "eloop.h"
00019 #include "state_machine.h"
00020 #include "common/eapol_common.h"
00021 #include "eap_common/eap_defs.h"
00022 #include "eap_common/eap_common.h"
00023 #include "eap_server/eap.h"
00024 #include "eapol_auth_sm.h"
00025 #include "eapol_auth_sm_i.h"
00026 
00027 #define STATE_MACHINE_DATA struct eapol_state_machine
00028 #define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
00029 #define STATE_MACHINE_ADDR sm->addr
00030 
00031 static struct eapol_callbacks eapol_cb;
00032 
00033 /* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
00034 
00035 #define setPortAuthorized() \
00036 sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
00037 #define setPortUnauthorized() \
00038 sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
00039 
00040 /* procedures */
00041 #define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
00042 #define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
00043 #define txReq() eapol_auth_tx_req(sm)
00044 #define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
00045 #define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
00046 #define processKey() do { } while (0)
00047 
00048 
00049 static void eapol_sm_step_run(struct eapol_state_machine *sm);
00050 static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
00051 static void eapol_auth_initialize(struct eapol_state_machine *sm);
00052 
00053 
00054 static void eapol_auth_logger(struct eapol_authenticator *eapol,
00055                               const u8 *addr, eapol_logger_level level,
00056                               const char *txt)
00057 {
00058         if (eapol->cb.logger == NULL)
00059                 return;
00060         eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
00061 }
00062 
00063 
00064 static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
00065                                const u8 *addr, eapol_logger_level level,
00066                                const char *fmt, ...)
00067 {
00068         char *format;
00069         int maxlen;
00070         va_list ap;
00071 
00072         if (eapol->cb.logger == NULL)
00073                 return;
00074 
00075         maxlen = os_strlen(fmt) + 100;
00076         format = os_malloc(maxlen);
00077         if (!format)
00078                 return;
00079 
00080         va_start(ap, fmt);
00081         vsnprintf(format, maxlen, fmt, ap);
00082         va_end(ap);
00083 
00084         eapol_auth_logger(eapol, addr, level, format);
00085 
00086         os_free(format);
00087 }
00088 
00089 
00090 static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
00091                                      int success)
00092 {
00093         struct eap_hdr eap;
00094 
00095         os_memset(&eap, 0, sizeof(eap));
00096 
00097         eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
00098         eap.identifier = ++sm->last_eap_id;
00099         eap.length = host_to_be16(sizeof(eap));
00100 
00101         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
00102                            "Sending canned EAP packet %s (identifier %d)",
00103                            success ? "SUCCESS" : "FAILURE", eap.identifier);
00104         sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
00105                                  IEEE802_1X_TYPE_EAP_PACKET,
00106                                  (u8 *) &eap, sizeof(eap));
00107         sm->dot1xAuthEapolFramesTx++;
00108 }
00109 
00110 
00111 static void eapol_auth_tx_req(struct eapol_state_machine *sm)
00112 {
00113         if (sm->eap_if->eapReqData == NULL ||
00114             wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
00115                 eapol_auth_logger(sm->eapol, sm->addr,
00116                                   EAPOL_LOGGER_DEBUG,
00117                                   "TxReq called, but there is no EAP request "
00118                                   "from authentication server");
00119                 return;
00120         }
00121 
00122         if (sm->flags & EAPOL_SM_WAIT_START) {
00123                 wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
00124                            " while waiting for EAPOL-Start",
00125                            MAC2STR(sm->addr));
00126                 return;
00127         }
00128 
00129         sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
00130         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
00131                            "Sending EAP Packet (identifier %d)",
00132                            sm->last_eap_id);
00133         sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
00134                                  IEEE802_1X_TYPE_EAP_PACKET,
00135                                  wpabuf_head(sm->eap_if->eapReqData),
00136                                  wpabuf_len(sm->eap_if->eapReqData));
00137         sm->dot1xAuthEapolFramesTx++;
00138         if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
00139                 sm->dot1xAuthEapolReqIdFramesTx++;
00140         else
00141                 sm->dot1xAuthEapolReqFramesTx++;
00142 }
00143 
00144 
00153 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
00154 {
00155         struct eapol_state_machine *state = timeout_ctx;
00156 
00157         if (state->aWhile > 0) {
00158                 state->aWhile--;
00159                 if (state->aWhile == 0) {
00160                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
00161                                    " - aWhile --> 0",
00162                                    MAC2STR(state->addr));
00163                 }
00164         }
00165 
00166         if (state->quietWhile > 0) {
00167                 state->quietWhile--;
00168                 if (state->quietWhile == 0) {
00169                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
00170                                    " - quietWhile --> 0",
00171                                    MAC2STR(state->addr));
00172                 }
00173         }
00174 
00175         if (state->reAuthWhen > 0) {
00176                 state->reAuthWhen--;
00177                 if (state->reAuthWhen == 0) {
00178                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
00179                                    " - reAuthWhen --> 0",
00180                                    MAC2STR(state->addr));
00181                 }
00182         }
00183 
00184         if (state->eap_if->retransWhile > 0) {
00185                 state->eap_if->retransWhile--;
00186                 if (state->eap_if->retransWhile == 0) {
00187                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
00188                                    " - (EAP) retransWhile --> 0",
00189                                    MAC2STR(state->addr));
00190                 }
00191         }
00192 
00193         eapol_sm_step_run(state);
00194 
00195         eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
00196 }
00197 
00198 
00199 
00200 /* Authenticator PAE state machine */
00201 
00202 SM_STATE(AUTH_PAE, INITIALIZE)
00203 {
00204         SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
00205         sm->portMode = Auto;
00206 }
00207 
00208 
00209 SM_STATE(AUTH_PAE, DISCONNECTED)
00210 {
00211         int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
00212 
00213         if (sm->eapolLogoff) {
00214                 if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
00215                         sm->authEapLogoffsWhileConnecting++;
00216                 else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
00217                         sm->authAuthEapLogoffWhileAuthenticated++;
00218         }
00219 
00220         SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
00221 
00222         sm->authPortStatus = Unauthorized;
00223         setPortUnauthorized();
00224         sm->reAuthCount = 0;
00225         sm->eapolLogoff = FALSE;
00226         if (!from_initialize) {
00227                 sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
00228                                        sm->flags & EAPOL_SM_PREAUTH);
00229         }
00230 }
00231 
00232 
00233 SM_STATE(AUTH_PAE, RESTART)
00234 {
00235         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
00236                 if (sm->reAuthenticate)
00237                         sm->authAuthReauthsWhileAuthenticated++;
00238                 if (sm->eapolStart)
00239                         sm->authAuthEapStartsWhileAuthenticated++;
00240                 if (sm->eapolLogoff)
00241                         sm->authAuthEapLogoffWhileAuthenticated++;
00242         }
00243 
00244         SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
00245 
00246         sm->eap_if->eapRestart = TRUE;
00247 }
00248 
00249 
00250 SM_STATE(AUTH_PAE, CONNECTING)
00251 {
00252         if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
00253                 sm->authEntersConnecting++;
00254 
00255         SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
00256 
00257         sm->reAuthenticate = FALSE;
00258         sm->reAuthCount++;
00259 }
00260 
00261 
00262 SM_STATE(AUTH_PAE, HELD)
00263 {
00264         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
00265                 sm->authAuthFailWhileAuthenticating++;
00266 
00267         SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
00268 
00269         sm->authPortStatus = Unauthorized;
00270         setPortUnauthorized();
00271         sm->quietWhile = sm->quietPeriod;
00272         sm->eapolLogoff = FALSE;
00273 
00274         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
00275                            "authentication failed - EAP type: %d (%s)",
00276                            sm->eap_type_authsrv,
00277                            eap_server_get_name(0, sm->eap_type_authsrv));
00278         if (sm->eap_type_authsrv != sm->eap_type_supp) {
00279                 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
00280                                    "Supplicant used different EAP type: "
00281                                    "%d (%s)", sm->eap_type_supp,
00282                                    eap_server_get_name(0, sm->eap_type_supp));
00283         }
00284         sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
00285                                sm->flags & EAPOL_SM_PREAUTH);
00286 }
00287 
00288 
00289 SM_STATE(AUTH_PAE, AUTHENTICATED)
00290 {
00291         char *extra = "";
00292 
00293         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
00294                 sm->authAuthSuccessesWhileAuthenticating++;
00295                                                         
00296         SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
00297 
00298         sm->authPortStatus = Authorized;
00299         setPortAuthorized();
00300         sm->reAuthCount = 0;
00301         if (sm->flags & EAPOL_SM_PREAUTH)
00302                 extra = " (pre-authentication)";
00303         else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
00304                 extra = " (PMKSA cache)";
00305         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
00306                            "authenticated - EAP type: %d (%s)%s",
00307                            sm->eap_type_authsrv,
00308                            eap_server_get_name(0, sm->eap_type_authsrv),
00309                            extra);
00310         sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
00311                                sm->flags & EAPOL_SM_PREAUTH);
00312 }
00313 
00314 
00315 SM_STATE(AUTH_PAE, AUTHENTICATING)
00316 {
00317         SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
00318 
00319         sm->eapolStart = FALSE;
00320         sm->authSuccess = FALSE;
00321         sm->authFail = FALSE;
00322         sm->authTimeout = FALSE;
00323         sm->authStart = TRUE;
00324         sm->keyRun = FALSE;
00325         sm->keyDone = FALSE;
00326 }
00327 
00328 
00329 SM_STATE(AUTH_PAE, ABORTING)
00330 {
00331         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
00332                 if (sm->authTimeout)
00333                         sm->authAuthTimeoutsWhileAuthenticating++;
00334                 if (sm->eapolStart)
00335                         sm->authAuthEapStartsWhileAuthenticating++;
00336                 if (sm->eapolLogoff)
00337                         sm->authAuthEapLogoffWhileAuthenticating++;
00338         }
00339 
00340         SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
00341 
00342         sm->authAbort = TRUE;
00343         sm->keyRun = FALSE;
00344         sm->keyDone = FALSE;
00345 }
00346 
00347 
00348 SM_STATE(AUTH_PAE, FORCE_AUTH)
00349 {
00350         SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
00351 
00352         sm->authPortStatus = Authorized;
00353         setPortAuthorized();
00354         sm->portMode = ForceAuthorized;
00355         sm->eapolStart = FALSE;
00356         txCannedSuccess();
00357 }
00358 
00359 
00360 SM_STATE(AUTH_PAE, FORCE_UNAUTH)
00361 {
00362         SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
00363 
00364         sm->authPortStatus = Unauthorized;
00365         setPortUnauthorized();
00366         sm->portMode = ForceUnauthorized;
00367         sm->eapolStart = FALSE;
00368         txCannedFail();
00369 }
00370 
00371 
00372 SM_STEP(AUTH_PAE)
00373 {
00374         if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
00375             sm->initialize || !sm->eap_if->portEnabled)
00376                 SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
00377         else if (sm->portControl == ForceAuthorized &&
00378                  sm->portMode != sm->portControl &&
00379                  !(sm->initialize || !sm->eap_if->portEnabled))
00380                 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
00381         else if (sm->portControl == ForceUnauthorized &&
00382                  sm->portMode != sm->portControl &&
00383                  !(sm->initialize || !sm->eap_if->portEnabled))
00384                 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
00385         else {
00386                 switch (sm->auth_pae_state) {
00387                 case AUTH_PAE_INITIALIZE:
00388                         SM_ENTER(AUTH_PAE, DISCONNECTED);
00389                         break;
00390                 case AUTH_PAE_DISCONNECTED:
00391                         SM_ENTER(AUTH_PAE, RESTART);
00392                         break;
00393                 case AUTH_PAE_RESTART:
00394                         if (!sm->eap_if->eapRestart)
00395                                 SM_ENTER(AUTH_PAE, CONNECTING);
00396                         break;
00397                 case AUTH_PAE_HELD:
00398                         if (sm->quietWhile == 0)
00399                                 SM_ENTER(AUTH_PAE, RESTART);
00400                         break;
00401                 case AUTH_PAE_CONNECTING:
00402                         if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
00403                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
00404                         else if ((sm->eap_if->eapReq &&
00405                                   sm->reAuthCount <= sm->reAuthMax) ||
00406                                  sm->eap_if->eapSuccess || sm->eap_if->eapFail)
00407                                 SM_ENTER(AUTH_PAE, AUTHENTICATING);
00408                         break;
00409                 case AUTH_PAE_AUTHENTICATED:
00410                         if (sm->eapolStart || sm->reAuthenticate)
00411                                 SM_ENTER(AUTH_PAE, RESTART);
00412                         else if (sm->eapolLogoff || !sm->portValid)
00413                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
00414                         break;
00415                 case AUTH_PAE_AUTHENTICATING:
00416                         if (sm->authSuccess && sm->portValid)
00417                                 SM_ENTER(AUTH_PAE, AUTHENTICATED);
00418                         else if (sm->authFail ||
00419                                  (sm->keyDone && !sm->portValid))
00420                                 SM_ENTER(AUTH_PAE, HELD);
00421                         else if (sm->eapolStart || sm->eapolLogoff ||
00422                                  sm->authTimeout)
00423                                 SM_ENTER(AUTH_PAE, ABORTING);
00424                         break;
00425                 case AUTH_PAE_ABORTING:
00426                         if (sm->eapolLogoff && !sm->authAbort)
00427                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
00428                         else if (!sm->eapolLogoff && !sm->authAbort)
00429                                 SM_ENTER(AUTH_PAE, RESTART);
00430                         break;
00431                 case AUTH_PAE_FORCE_AUTH:
00432                         if (sm->eapolStart)
00433                                 SM_ENTER(AUTH_PAE, FORCE_AUTH);
00434                         break;
00435                 case AUTH_PAE_FORCE_UNAUTH:
00436                         if (sm->eapolStart)
00437                                 SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
00438                         break;
00439                 }
00440         }
00441 }
00442 
00443 
00444 
00445 /* Backend Authentication state machine */
00446 
00447 SM_STATE(BE_AUTH, INITIALIZE)
00448 {
00449         SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
00450 
00451         abortAuth();
00452         sm->eap_if->eapNoReq = FALSE;
00453         sm->authAbort = FALSE;
00454 }
00455 
00456 
00457 SM_STATE(BE_AUTH, REQUEST)
00458 {
00459         SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
00460 
00461         txReq();
00462         sm->eap_if->eapReq = FALSE;
00463         sm->backendOtherRequestsToSupplicant++;
00464 
00465         /*
00466          * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
00467          * it looks like this would be logical thing to do there since the old
00468          * EAP response would not be valid anymore after the new EAP request
00469          * was sent out.
00470          *
00471          * A race condition has been reported, in which hostapd ended up
00472          * sending out EAP-Response/Identity as a response to the first
00473          * EAP-Request from the main EAP method. This can be avoided by
00474          * clearing eapolEap here.
00475          */
00476         sm->eapolEap = FALSE;
00477 }
00478 
00479 
00480 SM_STATE(BE_AUTH, RESPONSE)
00481 {
00482         SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
00483 
00484         sm->authTimeout = FALSE;
00485         sm->eapolEap = FALSE;
00486         sm->eap_if->eapNoReq = FALSE;
00487         sm->aWhile = sm->serverTimeout;
00488         sm->eap_if->eapResp = TRUE;
00489         /* sendRespToServer(); */
00490         sm->backendResponses++;
00491 }
00492 
00493 
00494 SM_STATE(BE_AUTH, SUCCESS)
00495 {
00496         SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
00497 
00498         txReq();
00499         sm->authSuccess = TRUE;
00500         sm->keyRun = TRUE;
00501 }
00502 
00503 
00504 SM_STATE(BE_AUTH, FAIL)
00505 {
00506         SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
00507 
00508         txReq();
00509         sm->authFail = TRUE;
00510 }
00511 
00512 
00513 SM_STATE(BE_AUTH, TIMEOUT)
00514 {
00515         SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
00516 
00517         sm->authTimeout = TRUE;
00518 }
00519 
00520 
00521 SM_STATE(BE_AUTH, IDLE)
00522 {
00523         SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
00524 
00525         sm->authStart = FALSE;
00526 }
00527 
00528 
00529 SM_STATE(BE_AUTH, IGNORE)
00530 {
00531         SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
00532 
00533         sm->eap_if->eapNoReq = FALSE;
00534 }
00535 
00536 
00537 SM_STEP(BE_AUTH)
00538 {
00539         if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
00540                 SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
00541                 return;
00542         }
00543 
00544         switch (sm->be_auth_state) {
00545         case BE_AUTH_INITIALIZE:
00546                 SM_ENTER(BE_AUTH, IDLE);
00547                 break;
00548         case BE_AUTH_REQUEST:
00549                 if (sm->eapolEap)
00550                         SM_ENTER(BE_AUTH, RESPONSE);
00551                 else if (sm->eap_if->eapReq)
00552                         SM_ENTER(BE_AUTH, REQUEST);
00553                 else if (sm->eap_if->eapTimeout)
00554                         SM_ENTER(BE_AUTH, TIMEOUT);
00555                 break;
00556         case BE_AUTH_RESPONSE:
00557                 if (sm->eap_if->eapNoReq)
00558                         SM_ENTER(BE_AUTH, IGNORE);
00559                 if (sm->eap_if->eapReq) {
00560                         sm->backendAccessChallenges++;
00561                         SM_ENTER(BE_AUTH, REQUEST);
00562                 } else if (sm->aWhile == 0)
00563                         SM_ENTER(BE_AUTH, TIMEOUT);
00564                 else if (sm->eap_if->eapFail) {
00565                         sm->backendAuthFails++;
00566                         SM_ENTER(BE_AUTH, FAIL);
00567                 } else if (sm->eap_if->eapSuccess) {
00568                         sm->backendAuthSuccesses++;
00569                         SM_ENTER(BE_AUTH, SUCCESS);
00570                 }
00571                 break;
00572         case BE_AUTH_SUCCESS:
00573                 SM_ENTER(BE_AUTH, IDLE);
00574                 break;
00575         case BE_AUTH_FAIL:
00576                 SM_ENTER(BE_AUTH, IDLE);
00577                 break;
00578         case BE_AUTH_TIMEOUT:
00579                 SM_ENTER(BE_AUTH, IDLE);
00580                 break;
00581         case BE_AUTH_IDLE:
00582                 if (sm->eap_if->eapFail && sm->authStart)
00583                         SM_ENTER(BE_AUTH, FAIL);
00584                 else if (sm->eap_if->eapReq && sm->authStart)
00585                         SM_ENTER(BE_AUTH, REQUEST);
00586                 else if (sm->eap_if->eapSuccess && sm->authStart)
00587                         SM_ENTER(BE_AUTH, SUCCESS);
00588                 break;
00589         case BE_AUTH_IGNORE:
00590                 if (sm->eapolEap)
00591                         SM_ENTER(BE_AUTH, RESPONSE);
00592                 else if (sm->eap_if->eapReq)
00593                         SM_ENTER(BE_AUTH, REQUEST);
00594                 else if (sm->eap_if->eapTimeout)
00595                         SM_ENTER(BE_AUTH, TIMEOUT);
00596                 break;
00597         }
00598 }
00599 
00600 
00601 
00602 /* Reauthentication Timer state machine */
00603 
00604 SM_STATE(REAUTH_TIMER, INITIALIZE)
00605 {
00606         SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
00607 
00608         sm->reAuthWhen = sm->reAuthPeriod;
00609 }
00610 
00611 
00612 SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
00613 {
00614         SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
00615 
00616         sm->reAuthenticate = TRUE;
00617         sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
00618                                   EAPOL_AUTH_REAUTHENTICATE);
00619 }
00620 
00621 
00622 SM_STEP(REAUTH_TIMER)
00623 {
00624         if (sm->portControl != Auto || sm->initialize ||
00625             sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
00626                 SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
00627                 return;
00628         }
00629 
00630         switch (sm->reauth_timer_state) {
00631         case REAUTH_TIMER_INITIALIZE:
00632                 if (sm->reAuthWhen == 0)
00633                         SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
00634                 break;
00635         case REAUTH_TIMER_REAUTHENTICATE:
00636                 SM_ENTER(REAUTH_TIMER, INITIALIZE);
00637                 break;
00638         }
00639 }
00640 
00641 
00642 
00643 /* Authenticator Key Transmit state machine */
00644 
00645 SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
00646 {
00647         SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
00648 }
00649 
00650 
00651 SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
00652 {
00653         SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
00654 
00655         txKey();
00656         sm->eap_if->eapKeyAvailable = FALSE;
00657         sm->keyDone = TRUE;
00658 }
00659 
00660 
00661 SM_STEP(AUTH_KEY_TX)
00662 {
00663         if (sm->initialize || sm->portControl != Auto) {
00664                 SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
00665                 return;
00666         }
00667 
00668         switch (sm->auth_key_tx_state) {
00669         case AUTH_KEY_TX_NO_KEY_TRANSMIT:
00670                 if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
00671                     sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
00672                         SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
00673                 break;
00674         case AUTH_KEY_TX_KEY_TRANSMIT:
00675                 if (!sm->keyTxEnabled || !sm->keyRun)
00676                         SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
00677                 else if (sm->eap_if->eapKeyAvailable)
00678                         SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
00679                 break;
00680         }
00681 }
00682 
00683 
00684 
00685 /* Key Receive state machine */
00686 
00687 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
00688 {
00689         SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
00690 }
00691 
00692 
00693 SM_STATE(KEY_RX, KEY_RECEIVE)
00694 {
00695         SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
00696 
00697         processKey();
00698         sm->rxKey = FALSE;
00699 }
00700 
00701 
00702 SM_STEP(KEY_RX)
00703 {
00704         if (sm->initialize || !sm->eap_if->portEnabled) {
00705                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
00706                 return;
00707         }
00708 
00709         switch (sm->key_rx_state) {
00710         case KEY_RX_NO_KEY_RECEIVE:
00711                 if (sm->rxKey)
00712                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00713                 break;
00714         case KEY_RX_KEY_RECEIVE:
00715                 if (sm->rxKey)
00716                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00717                 break;
00718         }
00719 }
00720 
00721 
00722 
00723 /* Controlled Directions state machine */
00724 
00725 SM_STATE(CTRL_DIR, FORCE_BOTH)
00726 {
00727         SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
00728         sm->operControlledDirections = Both;
00729 }
00730 
00731 
00732 SM_STATE(CTRL_DIR, IN_OR_BOTH)
00733 {
00734         SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
00735         sm->operControlledDirections = sm->adminControlledDirections;
00736 }
00737 
00738 
00739 SM_STEP(CTRL_DIR)
00740 {
00741         if (sm->initialize) {
00742                 SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
00743                 return;
00744         }
00745 
00746         switch (sm->ctrl_dir_state) {
00747         case CTRL_DIR_FORCE_BOTH:
00748                 if (sm->eap_if->portEnabled && sm->operEdge)
00749                         SM_ENTER(CTRL_DIR, IN_OR_BOTH);
00750                 break;
00751         case CTRL_DIR_IN_OR_BOTH:
00752                 if (sm->operControlledDirections !=
00753                     sm->adminControlledDirections)
00754                         SM_ENTER(CTRL_DIR, IN_OR_BOTH);
00755                 if (!sm->eap_if->portEnabled || !sm->operEdge)
00756                         SM_ENTER(CTRL_DIR, FORCE_BOTH);
00757                 break;
00758         }
00759 }
00760 
00761 
00762 
00763 struct eapol_state_machine *
00764 eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
00765                  int flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx)
00766 {
00767         struct eapol_state_machine *sm;
00768         struct eap_config eap_conf;
00769 
00770         if (eapol == NULL)
00771                 return NULL;
00772 
00773         sm = os_zalloc(sizeof(*sm));
00774         if (sm == NULL) {
00775                 wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
00776                            "failed");
00777                 return NULL;
00778         }
00779         sm->radius_identifier = -1;
00780         os_memcpy(sm->addr, addr, ETH_ALEN);
00781         sm->flags = flags;
00782 
00783         sm->eapol = eapol;
00784         sm->sta = sta_ctx;
00785 
00786         /* Set default values for state machine constants */
00787         sm->auth_pae_state = AUTH_PAE_INITIALIZE;
00788         sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
00789         sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
00790 
00791         sm->be_auth_state = BE_AUTH_INITIALIZE;
00792         sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
00793 
00794         sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
00795         sm->reAuthPeriod = eapol->conf.eap_reauth_period;
00796         sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
00797 
00798         sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
00799 
00800         sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
00801 
00802         sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
00803 
00804         sm->portControl = Auto;
00805 
00806         if (!eapol->conf.wpa &&
00807             (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
00808                 sm->keyTxEnabled = TRUE;
00809         else
00810                 sm->keyTxEnabled = FALSE;
00811         if (eapol->conf.wpa)
00812                 sm->portValid = FALSE;
00813         else
00814                 sm->portValid = TRUE;
00815 
00816         os_memset(&eap_conf, 0, sizeof(eap_conf));
00817         eap_conf.eap_server = eapol->conf.eap_server;
00818         eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
00819         eap_conf.msg_ctx = eapol->conf.msg_ctx;
00820         eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
00821         eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
00822         eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
00823         eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
00824         eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
00825         eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
00826         eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
00827         eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
00828         eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
00829         eap_conf.tnc = eapol->conf.tnc;
00830         eap_conf.wps = eapol->conf.wps;
00831         eap_conf.assoc_wps_ie = assoc_wps_ie;
00832         eap_conf.peer_addr = addr;
00833         sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
00834         if (sm->eap == NULL) {
00835                 eapol_auth_free(sm);
00836                 return NULL;
00837         }
00838         sm->eap_if = eap_get_interface(sm->eap);
00839 
00840         eapol_auth_initialize(sm);
00841 
00842         return sm;
00843 }
00844 
00845 
00846 void eapol_auth_free(struct eapol_state_machine *sm)
00847 {
00848         if (sm == NULL)
00849                 return;
00850 
00851         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
00852         eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
00853         if (sm->eap)
00854                 eap_server_sm_deinit(sm->eap);
00855         os_free(sm);
00856 }
00857 
00858 
00859 static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
00860                                     const u8 *addr)
00861 {
00862         return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
00863 }
00864 
00865 
00866 static void eapol_sm_step_run(struct eapol_state_machine *sm)
00867 {
00868         struct eapol_authenticator *eapol = sm->eapol;
00869         u8 addr[ETH_ALEN];
00870         unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
00871                 prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
00872         int max_steps = 100;
00873 
00874         os_memcpy(addr, sm->addr, ETH_ALEN);
00875 
00876         /*
00877          * Allow EAPOL state machines to run as long as there are state
00878          * changes, but exit and return here through event loop if more than
00879          * 100 steps is needed as a precaution against infinite loops inside
00880          * eloop callback.
00881          */
00882 restart:
00883         prev_auth_pae = sm->auth_pae_state;
00884         prev_be_auth = sm->be_auth_state;
00885         prev_reauth_timer = sm->reauth_timer_state;
00886         prev_auth_key_tx = sm->auth_key_tx_state;
00887         prev_key_rx = sm->key_rx_state;
00888         prev_ctrl_dir = sm->ctrl_dir_state;
00889 
00890         SM_STEP_RUN(AUTH_PAE);
00891         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
00892                 SM_STEP_RUN(BE_AUTH);
00893         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
00894                 SM_STEP_RUN(REAUTH_TIMER);
00895         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
00896                 SM_STEP_RUN(AUTH_KEY_TX);
00897         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
00898                 SM_STEP_RUN(KEY_RX);
00899         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
00900                 SM_STEP_RUN(CTRL_DIR);
00901 
00902         if (prev_auth_pae != sm->auth_pae_state ||
00903             prev_be_auth != sm->be_auth_state ||
00904             prev_reauth_timer != sm->reauth_timer_state ||
00905             prev_auth_key_tx != sm->auth_key_tx_state ||
00906             prev_key_rx != sm->key_rx_state ||
00907             prev_ctrl_dir != sm->ctrl_dir_state) {
00908                 if (--max_steps > 0)
00909                         goto restart;
00910                 /* Re-run from eloop timeout */
00911                 eapol_auth_step(sm);
00912                 return;
00913         }
00914 
00915         if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
00916                 if (eap_server_sm_step(sm->eap)) {
00917                         if (--max_steps > 0)
00918                                 goto restart;
00919                         /* Re-run from eloop timeout */
00920                         eapol_auth_step(sm);
00921                         return;
00922                 }
00923 
00924                 /* TODO: find a better location for this */
00925                 if (sm->eap_if->aaaEapResp) {
00926                         sm->eap_if->aaaEapResp = FALSE;
00927                         if (sm->eap_if->aaaEapRespData == NULL) {
00928                                 wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
00929                                            "but no aaaEapRespData available");
00930                                 return;
00931                         }
00932                         sm->eapol->cb.aaa_send(
00933                                 sm->eapol->conf.ctx, sm->sta,
00934                                 wpabuf_head(sm->eap_if->aaaEapRespData),
00935                                 wpabuf_len(sm->eap_if->aaaEapRespData));
00936                 }
00937         }
00938 
00939         if (eapol_sm_sta_entry_alive(eapol, addr))
00940                 sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
00941                                           EAPOL_AUTH_SM_CHANGE);
00942 }
00943 
00944 
00945 static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
00946 {
00947         struct eapol_state_machine *sm = eloop_ctx;
00948         eapol_sm_step_run(sm);
00949 }
00950 
00951 
00959 void eapol_auth_step(struct eapol_state_machine *sm)
00960 {
00961         /*
00962          * Run eapol_sm_step_run from a registered timeout to make sure that
00963          * other possible timeouts/events are processed and to avoid long
00964          * function call chains.
00965          */
00966 
00967         eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
00968 }
00969 
00970 
00971 static void eapol_auth_initialize(struct eapol_state_machine *sm)
00972 {
00973         sm->initializing = TRUE;
00974         /* Initialize the state machines by asserting initialize and then
00975          * deasserting it after one step */
00976         sm->initialize = TRUE;
00977         eapol_sm_step_run(sm);
00978         sm->initialize = FALSE;
00979         eapol_sm_step_run(sm);
00980         sm->initializing = FALSE;
00981 
00982         /* Start one second tick for port timers state machine */
00983         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
00984         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
00985 }
00986 
00987 
00988 static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
00989                                  size_t identity_len, int phase2,
00990                                  struct eap_user *user)
00991 {
00992         struct eapol_state_machine *sm = ctx;
00993         return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
00994                                           identity_len, phase2, user);
00995 }
00996 
00997 
00998 static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
00999 {
01000         struct eapol_state_machine *sm = ctx;
01001         *len = sm->eapol->conf.eap_req_id_text_len;
01002         return sm->eapol->conf.eap_req_id_text;
01003 }
01004 
01005 
01006 static struct eapol_callbacks eapol_cb =
01007 {
01008         eapol_sm_get_eap_user,
01009         eapol_sm_get_eap_req_id_text
01010 };
01011 
01012 
01013 int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
01014 {
01015         if (sm == NULL || ctx != sm->eap)
01016                 return -1;
01017 
01018         eap_sm_pending_cb(sm->eap);
01019         eapol_auth_step(sm);
01020 
01021         return 0;
01022 }
01023 
01024 
01025 static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
01026                                  struct eapol_auth_config *src)
01027 {
01028         dst->ctx = src->ctx;
01029         dst->eap_reauth_period = src->eap_reauth_period;
01030         dst->wpa = src->wpa;
01031         dst->individual_wep_key_len = src->individual_wep_key_len;
01032         dst->eap_server = src->eap_server;
01033         dst->ssl_ctx = src->ssl_ctx;
01034         dst->msg_ctx = src->msg_ctx;
01035         dst->eap_sim_db_priv = src->eap_sim_db_priv;
01036         os_free(dst->eap_req_id_text);
01037         if (src->eap_req_id_text) {
01038                 dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
01039                 if (dst->eap_req_id_text == NULL)
01040                         return -1;
01041                 os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
01042                           src->eap_req_id_text_len);
01043                 dst->eap_req_id_text_len = src->eap_req_id_text_len;
01044         } else {
01045                 dst->eap_req_id_text = NULL;
01046                 dst->eap_req_id_text_len = 0;
01047         }
01048         if (src->pac_opaque_encr_key) {
01049                 dst->pac_opaque_encr_key = os_malloc(16);
01050                 os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
01051                           16);
01052         } else
01053                 dst->pac_opaque_encr_key = NULL;
01054         if (src->eap_fast_a_id) {
01055                 dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
01056                 if (dst->eap_fast_a_id == NULL) {
01057                         os_free(dst->eap_req_id_text);
01058                         return -1;
01059                 }
01060                 os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
01061                           src->eap_fast_a_id_len);
01062                 dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
01063         } else
01064                 dst->eap_fast_a_id = NULL;
01065         if (src->eap_fast_a_id_info) {
01066                 dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
01067                 if (dst->eap_fast_a_id_info == NULL) {
01068                         os_free(dst->eap_req_id_text);
01069                         os_free(dst->eap_fast_a_id);
01070                         return -1;
01071                 }
01072         } else
01073                 dst->eap_fast_a_id_info = NULL;
01074         dst->eap_fast_prov = src->eap_fast_prov;
01075         dst->pac_key_lifetime = src->pac_key_lifetime;
01076         dst->pac_key_refresh_time = src->pac_key_refresh_time;
01077         dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
01078         dst->tnc = src->tnc;
01079         dst->wps = src->wps;
01080         return 0;
01081 }
01082 
01083 
01084 static void eapol_auth_conf_free(struct eapol_auth_config *conf)
01085 {
01086         os_free(conf->eap_req_id_text);
01087         conf->eap_req_id_text = NULL;
01088         os_free(conf->pac_opaque_encr_key);
01089         conf->pac_opaque_encr_key = NULL;
01090         os_free(conf->eap_fast_a_id);
01091         conf->eap_fast_a_id = NULL;
01092         os_free(conf->eap_fast_a_id_info);
01093         conf->eap_fast_a_id_info = NULL;
01094 }
01095 
01096 
01097 struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
01098                                              struct eapol_auth_cb *cb)
01099 {
01100         struct eapol_authenticator *eapol;
01101 
01102         eapol = os_zalloc(sizeof(*eapol));
01103         if (eapol == NULL)
01104                 return NULL;
01105 
01106         if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
01107                 os_free(eapol);
01108                 return NULL;
01109         }
01110 
01111         if (conf->individual_wep_key_len > 0) {
01112                 /* use key0 in individual key and key1 in broadcast key */
01113                 eapol->default_wep_key_idx = 1;
01114         }
01115 
01116         eapol->cb.eapol_send = cb->eapol_send;
01117         eapol->cb.aaa_send = cb->aaa_send;
01118         eapol->cb.finished = cb->finished;
01119         eapol->cb.get_eap_user = cb->get_eap_user;
01120         eapol->cb.sta_entry_alive = cb->sta_entry_alive;
01121         eapol->cb.logger = cb->logger;
01122         eapol->cb.set_port_authorized = cb->set_port_authorized;
01123         eapol->cb.abort_auth = cb->abort_auth;
01124         eapol->cb.tx_key = cb->tx_key;
01125         eapol->cb.eapol_event = cb->eapol_event;
01126 
01127         return eapol;
01128 }
01129 
01130 
01131 void eapol_auth_deinit(struct eapol_authenticator *eapol)
01132 {
01133         if (eapol == NULL)
01134                 return;
01135 
01136         eapol_auth_conf_free(&eapol->conf);
01137         os_free(eapol->default_wep_key);
01138         os_free(eapol);
01139 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35