Branch data Line data Source code
1 : : /*
2 : : * IEEE 802.1X-2004 Authenticator - EAPOL state machine
3 : : * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "eloop.h"
13 : : #include "state_machine.h"
14 : : #include "common/eapol_common.h"
15 : : #include "eap_common/eap_defs.h"
16 : : #include "eap_common/eap_common.h"
17 : : #include "eap_server/eap.h"
18 : : #include "eapol_auth_sm.h"
19 : : #include "eapol_auth_sm_i.h"
20 : :
21 : : #define STATE_MACHINE_DATA struct eapol_state_machine
22 : : #define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
23 : : #define STATE_MACHINE_ADDR sm->addr
24 : :
25 : : static struct eapol_callbacks eapol_cb;
26 : :
27 : : /* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
28 : :
29 : : #define setPortAuthorized() \
30 : : sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
31 : : #define setPortUnauthorized() \
32 : : sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
33 : :
34 : : /* procedures */
35 : : #define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
36 : : #define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
37 : : #define txReq() eapol_auth_tx_req(sm)
38 : : #define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
39 : : #define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
40 : : #define processKey() do { } while (0)
41 : :
42 : :
43 : : static void eapol_sm_step_run(struct eapol_state_machine *sm);
44 : : static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
45 : : static void eapol_auth_initialize(struct eapol_state_machine *sm);
46 : :
47 : :
48 : 2760 : static void eapol_auth_logger(struct eapol_authenticator *eapol,
49 : : const u8 *addr, eapol_logger_level level,
50 : : const char *txt)
51 : : {
52 [ - + ]: 2760 : if (eapol->cb.logger == NULL)
53 : 2760 : return;
54 : 2760 : eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
55 : : }
56 : :
57 : :
58 : 2760 : static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
59 : : const u8 *addr, eapol_logger_level level,
60 : : const char *fmt, ...)
61 : : {
62 : : char *format;
63 : : int maxlen;
64 : : va_list ap;
65 : :
66 [ - + ]: 2760 : if (eapol->cb.logger == NULL)
67 : 0 : return;
68 : :
69 : 2760 : maxlen = os_strlen(fmt) + 100;
70 : 2760 : format = os_malloc(maxlen);
71 [ - + ]: 2760 : if (!format)
72 : 0 : return;
73 : :
74 : 2760 : va_start(ap, fmt);
75 : 2760 : vsnprintf(format, maxlen, fmt, ap);
76 : 2760 : va_end(ap);
77 : :
78 : 2760 : eapol_auth_logger(eapol, addr, level, format);
79 : :
80 : 2760 : os_free(format);
81 : : }
82 : :
83 : :
84 : 0 : static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
85 : : int success)
86 : : {
87 : : struct eap_hdr eap;
88 : :
89 : 0 : os_memset(&eap, 0, sizeof(eap));
90 : :
91 [ # # ]: 0 : eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
92 : 0 : eap.identifier = ++sm->last_eap_id;
93 : 0 : eap.length = host_to_be16(sizeof(eap));
94 : :
95 [ # # ]: 0 : eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
96 : : "Sending canned EAP packet %s (identifier %d)",
97 : 0 : success ? "SUCCESS" : "FAILURE", eap.identifier);
98 : 0 : sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
99 : : IEEE802_1X_TYPE_EAP_PACKET,
100 : : (u8 *) &eap, sizeof(eap));
101 : 0 : sm->dot1xAuthEapolFramesTx++;
102 : 0 : }
103 : :
104 : :
105 : 2260 : static void eapol_auth_tx_req(struct eapol_state_machine *sm)
106 : : {
107 [ + - - + ]: 4520 : if (sm->eap_if->eapReqData == NULL ||
108 : 2260 : wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
109 : 0 : eapol_auth_logger(sm->eapol, sm->addr,
110 : : EAPOL_LOGGER_DEBUG,
111 : : "TxReq called, but there is no EAP request "
112 : : "from authentication server");
113 : 0 : return;
114 : : }
115 : :
116 [ + + ]: 2260 : if (sm->flags & EAPOL_SM_WAIT_START) {
117 : 1 : wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
118 : : " while waiting for EAPOL-Start",
119 : 6 : MAC2STR(sm->addr));
120 : 1 : return;
121 : : }
122 : :
123 : 2259 : sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
124 : 2259 : eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
125 : : "Sending EAP Packet (identifier %d)",
126 : 2259 : sm->last_eap_id);
127 : 4518 : sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
128 : : IEEE802_1X_TYPE_EAP_PACKET,
129 : 2259 : wpabuf_head(sm->eap_if->eapReqData),
130 : 2259 : wpabuf_len(sm->eap_if->eapReqData));
131 : 2259 : sm->dot1xAuthEapolFramesTx++;
132 [ + + ]: 2259 : if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
133 : 351 : sm->dot1xAuthEapolReqIdFramesTx++;
134 : : else
135 : 2260 : sm->dot1xAuthEapolReqFramesTx++;
136 : : }
137 : :
138 : :
139 : : /**
140 : : * eapol_port_timers_tick - Port Timers state machine
141 : : * @eloop_ctx: struct eapol_state_machine *
142 : : * @timeout_ctx: Not used
143 : : *
144 : : * This statemachine is implemented as a function that will be called
145 : : * once a second as a registered event loop timeout.
146 : : */
147 : 29 : static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
148 : : {
149 : 29 : struct eapol_state_machine *state = timeout_ctx;
150 : :
151 [ + + ]: 29 : if (state->aWhile > 0) {
152 : 28 : state->aWhile--;
153 [ - + ]: 28 : if (state->aWhile == 0) {
154 : 0 : wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
155 : : " - aWhile --> 0",
156 : 0 : MAC2STR(state->addr));
157 : : }
158 : : }
159 : :
160 [ - + ]: 29 : if (state->quietWhile > 0) {
161 : 0 : state->quietWhile--;
162 [ # # ]: 0 : if (state->quietWhile == 0) {
163 : 0 : wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
164 : : " - quietWhile --> 0",
165 : 0 : MAC2STR(state->addr));
166 : : }
167 : : }
168 : :
169 [ + - ]: 29 : if (state->reAuthWhen > 0) {
170 : 29 : state->reAuthWhen--;
171 [ - + ]: 29 : if (state->reAuthWhen == 0) {
172 : 0 : wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
173 : : " - reAuthWhen --> 0",
174 : 0 : MAC2STR(state->addr));
175 : : }
176 : : }
177 : :
178 [ + + ]: 29 : if (state->eap_if->retransWhile > 0) {
179 : 20 : state->eap_if->retransWhile--;
180 [ + + ]: 20 : if (state->eap_if->retransWhile == 0) {
181 : 5 : wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
182 : : " - (EAP) retransWhile --> 0",
183 : 30 : MAC2STR(state->addr));
184 : : }
185 : : }
186 : :
187 : 29 : eapol_sm_step_run(state);
188 : :
189 : 29 : eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
190 : 29 : }
191 : :
192 : :
193 : :
194 : : /* Authenticator PAE state machine */
195 : :
196 : 1715 : SM_STATE(AUTH_PAE, INITIALIZE)
197 : : {
198 [ + - ][ + + ]: 1715 : SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
199 : 1715 : sm->portMode = Auto;
200 : 1715 : }
201 : :
202 : :
203 : 326 : SM_STATE(AUTH_PAE, DISCONNECTED)
204 : : {
205 : 326 : int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
206 : :
207 [ + + ]: 326 : if (sm->eapolLogoff) {
208 [ - + ]: 1 : if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
209 : 0 : sm->authEapLogoffsWhileConnecting++;
210 [ + - ]: 1 : else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
211 : 1 : sm->authAuthEapLogoffWhileAuthenticated++;
212 : : }
213 : :
214 [ - + ][ # # ]: 326 : SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
215 : :
216 : 326 : sm->authPortStatus = Unauthorized;
217 : 326 : setPortUnauthorized();
218 : 326 : sm->reAuthCount = 0;
219 : 326 : sm->eapolLogoff = FALSE;
220 [ + + ]: 326 : if (!from_initialize) {
221 : 1 : sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
222 : 1 : sm->flags & EAPOL_SM_PREAUTH,
223 : : sm->remediation);
224 : : }
225 : 326 : }
226 : :
227 : :
228 : 352 : SM_STATE(AUTH_PAE, RESTART)
229 : : {
230 [ + + ]: 352 : if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
231 [ - + ]: 26 : if (sm->reAuthenticate)
232 : 0 : sm->authAuthReauthsWhileAuthenticated++;
233 [ + - ]: 26 : if (sm->eapolStart)
234 : 26 : sm->authAuthEapStartsWhileAuthenticated++;
235 [ - + ]: 26 : if (sm->eapolLogoff)
236 : 0 : sm->authAuthEapLogoffWhileAuthenticated++;
237 : : }
238 : :
239 [ - + ][ # # ]: 352 : SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
240 : :
241 : 352 : sm->eap_if->eapRestart = TRUE;
242 : 352 : }
243 : :
244 : :
245 : 352 : SM_STATE(AUTH_PAE, CONNECTING)
246 : : {
247 [ + - ]: 352 : if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
248 : 352 : sm->authEntersConnecting++;
249 : :
250 [ - + ][ # # ]: 352 : SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
251 : :
252 : 352 : sm->reAuthenticate = FALSE;
253 : 352 : sm->reAuthCount++;
254 : 352 : }
255 : :
256 : :
257 : 169 : SM_STATE(AUTH_PAE, HELD)
258 : : {
259 [ + - ][ + - ]: 169 : if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
260 : 169 : sm->authAuthFailWhileAuthenticating++;
261 : :
262 [ - + ][ # # ]: 169 : SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
263 : :
264 : 169 : sm->authPortStatus = Unauthorized;
265 : 169 : setPortUnauthorized();
266 : 169 : sm->quietWhile = sm->quietPeriod;
267 : 169 : sm->eapolLogoff = FALSE;
268 : :
269 : 169 : eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
270 : : "authentication failed - EAP type: %d (%s)",
271 : 169 : sm->eap_type_authsrv,
272 : 169 : eap_server_get_name(0, sm->eap_type_authsrv));
273 [ + + ]: 169 : if (sm->eap_type_authsrv != sm->eap_type_supp) {
274 : 148 : eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
275 : : "Supplicant used different EAP type: "
276 : 148 : "%d (%s)", sm->eap_type_supp,
277 : 148 : eap_server_get_name(0, sm->eap_type_supp));
278 : : }
279 : 169 : sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
280 : 169 : sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
281 : 169 : }
282 : :
283 : :
284 : 184 : SM_STATE(AUTH_PAE, AUTHENTICATED)
285 : : {
286 : 184 : char *extra = "";
287 : :
288 [ + - ][ + - ]: 184 : if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
289 : 184 : sm->authAuthSuccessesWhileAuthenticating++;
290 : :
291 [ - + ][ # # ]: 184 : SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
292 : :
293 : 184 : sm->authPortStatus = Authorized;
294 : 184 : setPortAuthorized();
295 : 184 : sm->reAuthCount = 0;
296 [ - + ]: 184 : if (sm->flags & EAPOL_SM_PREAUTH)
297 : 0 : extra = " (pre-authentication)";
298 [ + + ]: 184 : else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
299 : 5 : extra = " (PMKSA cache)";
300 : 184 : eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
301 : : "authenticated - EAP type: %d (%s)%s",
302 : 184 : sm->eap_type_authsrv,
303 : 184 : eap_server_get_name(0, sm->eap_type_authsrv),
304 : : extra);
305 : 184 : sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
306 : 184 : sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
307 : 184 : }
308 : :
309 : :
310 : 352 : SM_STATE(AUTH_PAE, AUTHENTICATING)
311 : : {
312 [ - + ][ # # ]: 352 : SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
313 : :
314 : 352 : sm->eapolStart = FALSE;
315 : 352 : sm->authSuccess = FALSE;
316 : 352 : sm->authFail = FALSE;
317 : 352 : sm->authTimeout = FALSE;
318 : 352 : sm->authStart = TRUE;
319 : 352 : sm->keyRun = FALSE;
320 : 352 : sm->keyDone = FALSE;
321 : 352 : }
322 : :
323 : :
324 : 1 : SM_STATE(AUTH_PAE, ABORTING)
325 : : {
326 [ + - ]: 1 : if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
327 [ - + ]: 1 : if (sm->authTimeout)
328 : 0 : sm->authAuthTimeoutsWhileAuthenticating++;
329 [ + - ]: 1 : if (sm->eapolStart)
330 : 1 : sm->authAuthEapStartsWhileAuthenticating++;
331 [ - + ]: 1 : if (sm->eapolLogoff)
332 : 0 : sm->authAuthEapLogoffWhileAuthenticating++;
333 : : }
334 : :
335 [ - + ][ # # ]: 1 : SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
336 : :
337 : 1 : sm->authAbort = TRUE;
338 : 1 : sm->keyRun = FALSE;
339 : 1 : sm->keyDone = FALSE;
340 : 1 : }
341 : :
342 : :
343 : 0 : SM_STATE(AUTH_PAE, FORCE_AUTH)
344 : : {
345 [ # # ][ # # ]: 0 : SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
346 : :
347 : 0 : sm->authPortStatus = Authorized;
348 : 0 : setPortAuthorized();
349 : 0 : sm->portMode = ForceAuthorized;
350 : 0 : sm->eapolStart = FALSE;
351 : 0 : txCannedSuccess();
352 : 0 : }
353 : :
354 : :
355 : 0 : SM_STATE(AUTH_PAE, FORCE_UNAUTH)
356 : : {
357 [ # # ][ # # ]: 0 : SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
358 : :
359 : 0 : sm->authPortStatus = Unauthorized;
360 : 0 : setPortUnauthorized();
361 : 0 : sm->portMode = ForceUnauthorized;
362 : 0 : sm->eapolStart = FALSE;
363 : 0 : txCannedFail();
364 : 0 : }
365 : :
366 : :
367 : 14969 : SM_STEP(AUTH_PAE)
368 : : {
369 [ + - ][ + + ]: 14969 : if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
[ + - ]
370 [ + + ]: 14641 : sm->initialize || !sm->eap_if->portEnabled)
371 : 1715 : SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
372 [ - + ][ # # ]: 13254 : else if (sm->portControl == ForceAuthorized &&
373 [ # # ]: 0 : sm->portMode != sm->portControl &&
374 [ # # ]: 0 : !(sm->initialize || !sm->eap_if->portEnabled))
375 : 0 : SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
376 [ - + ][ # # ]: 13254 : else if (sm->portControl == ForceUnauthorized &&
377 [ # # ]: 0 : sm->portMode != sm->portControl &&
378 [ # # ]: 0 : !(sm->initialize || !sm->eap_if->portEnabled))
379 : 0 : SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
380 : : else {
381 [ + + + - : 13254 : switch (sm->auth_pae_state) {
+ + + + -
- - ]
382 : : case AUTH_PAE_INITIALIZE:
383 : 325 : SM_ENTER(AUTH_PAE, DISCONNECTED);
384 : 325 : break;
385 : : case AUTH_PAE_DISCONNECTED:
386 : 325 : SM_ENTER(AUTH_PAE, RESTART);
387 : 325 : break;
388 : : case AUTH_PAE_RESTART:
389 [ + + ]: 704 : if (!sm->eap_if->eapRestart)
390 : 352 : SM_ENTER(AUTH_PAE, CONNECTING);
391 : 704 : break;
392 : : case AUTH_PAE_HELD:
393 [ # # ]: 0 : if (sm->quietWhile == 0)
394 : 0 : SM_ENTER(AUTH_PAE, RESTART);
395 : 0 : break;
396 : : case AUTH_PAE_CONNECTING:
397 [ + - ][ - + ]: 352 : if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
398 : 0 : SM_ENTER(AUTH_PAE, DISCONNECTED);
399 [ + - ][ - + ]: 352 : else if ((sm->eap_if->eapReq &&
400 [ # # ]: 0 : sm->reAuthCount <= sm->reAuthMax) ||
401 [ # # ]: 0 : sm->eap_if->eapSuccess || sm->eap_if->eapFail)
402 : 352 : SM_ENTER(AUTH_PAE, AUTHENTICATING);
403 : 352 : break;
404 : : case AUTH_PAE_AUTHENTICATED:
405 [ + + ][ - + ]: 253 : if (sm->eapolStart || sm->reAuthenticate)
406 : 26 : SM_ENTER(AUTH_PAE, RESTART);
407 [ + + ][ - + ]: 227 : else if (sm->eapolLogoff || !sm->portValid)
408 : 1 : SM_ENTER(AUTH_PAE, DISCONNECTED);
409 : 253 : break;
410 : : case AUTH_PAE_AUTHENTICATING:
411 [ + + ][ + + ]: 11294 : if (sm->authSuccess && sm->portValid)
412 : 184 : SM_ENTER(AUTH_PAE, AUTHENTICATED);
413 [ + + ][ - + ]: 11110 : else if (sm->authFail ||
414 [ # # ]: 0 : (sm->keyDone && !sm->portValid))
415 : 169 : SM_ENTER(AUTH_PAE, HELD);
416 [ + + ][ + - ]: 10941 : else if (sm->eapolStart || sm->eapolLogoff ||
[ - + ]
417 : 10940 : sm->authTimeout)
418 : 1 : SM_ENTER(AUTH_PAE, ABORTING);
419 : 11294 : break;
420 : : case AUTH_PAE_ABORTING:
421 [ - + ][ # # ]: 1 : if (sm->eapolLogoff && !sm->authAbort)
422 : 0 : SM_ENTER(AUTH_PAE, DISCONNECTED);
423 [ + - ][ + - ]: 1 : else if (!sm->eapolLogoff && !sm->authAbort)
424 : 1 : SM_ENTER(AUTH_PAE, RESTART);
425 : 1 : break;
426 : : case AUTH_PAE_FORCE_AUTH:
427 [ # # ]: 0 : if (sm->eapolStart)
428 : 0 : SM_ENTER(AUTH_PAE, FORCE_AUTH);
429 : 0 : break;
430 : : case AUTH_PAE_FORCE_UNAUTH:
431 [ # # ]: 0 : if (sm->eapolStart)
432 : 0 : SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
433 : 0 : break;
434 : : }
435 : : }
436 : 14969 : }
437 : :
438 : :
439 : :
440 : : /* Backend Authentication state machine */
441 : :
442 : 329 : SM_STATE(BE_AUTH, INITIALIZE)
443 : : {
444 [ + - ][ + + ]: 329 : SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
445 : :
446 : 329 : abortAuth();
447 : 329 : sm->eap_if->eapNoReq = FALSE;
448 : 329 : sm->authAbort = FALSE;
449 : 329 : }
450 : :
451 : :
452 : 1912 : SM_STATE(BE_AUTH, REQUEST)
453 : : {
454 [ - + ][ # # ]: 1912 : SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
455 : :
456 : 1912 : txReq();
457 : 1912 : sm->eap_if->eapReq = FALSE;
458 : 1912 : sm->backendOtherRequestsToSupplicant++;
459 : :
460 : : /*
461 : : * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
462 : : * it looks like this would be logical thing to do there since the old
463 : : * EAP response would not be valid anymore after the new EAP request
464 : : * was sent out.
465 : : *
466 : : * A race condition has been reported, in which hostapd ended up
467 : : * sending out EAP-Response/Identity as a response to the first
468 : : * EAP-Request from the main EAP method. This can be avoided by
469 : : * clearing eapolEap here.
470 : : */
471 : 1912 : sm->eapolEap = FALSE;
472 : 1912 : }
473 : :
474 : :
475 : 1909 : SM_STATE(BE_AUTH, RESPONSE)
476 : : {
477 [ - + ][ # # ]: 1909 : SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
478 : :
479 : 1909 : sm->authTimeout = FALSE;
480 : 1909 : sm->eapolEap = FALSE;
481 : 1909 : sm->eap_if->eapNoReq = FALSE;
482 : 1909 : sm->aWhile = sm->serverTimeout;
483 : 1909 : sm->eap_if->eapResp = TRUE;
484 : : /* sendRespToServer(); */
485 : 1909 : sm->backendResponses++;
486 : 1909 : }
487 : :
488 : :
489 : 179 : SM_STATE(BE_AUTH, SUCCESS)
490 : : {
491 [ - + ][ # # ]: 179 : SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
492 : :
493 : 179 : txReq();
494 : 179 : sm->authSuccess = TRUE;
495 : 179 : sm->keyRun = TRUE;
496 : 179 : }
497 : :
498 : :
499 : 169 : SM_STATE(BE_AUTH, FAIL)
500 : : {
501 [ - + ][ # # ]: 169 : SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
502 : :
503 : 169 : txReq();
504 : 169 : sm->authFail = TRUE;
505 : 169 : }
506 : :
507 : :
508 : 0 : SM_STATE(BE_AUTH, TIMEOUT)
509 : : {
510 [ # # ][ # # ]: 0 : SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
511 : :
512 : 0 : sm->authTimeout = TRUE;
513 : 0 : }
514 : :
515 : :
516 : 684 : SM_STATE(BE_AUTH, IDLE)
517 : : {
518 [ - + ][ # # ]: 684 : SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
519 : :
520 : 684 : sm->authStart = FALSE;
521 : 684 : }
522 : :
523 : :
524 : 0 : SM_STATE(BE_AUTH, IGNORE)
525 : : {
526 [ # # ][ # # ]: 0 : SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
527 : :
528 : 0 : sm->eap_if->eapNoReq = FALSE;
529 : 0 : }
530 : :
531 : :
532 : 14969 : SM_STEP(BE_AUTH)
533 : : {
534 [ + - ][ + + ]: 14969 : if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
[ + + ]
535 : 329 : SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
536 : 14969 : return;
537 : : }
538 : :
539 [ + + + + : 14640 : switch (sm->be_auth_state) {
+ - + -
- ]
540 : : case BE_AUTH_INITIALIZE:
541 : 329 : SM_ENTER(BE_AUTH, IDLE);
542 : 329 : break;
543 : : case BE_AUTH_REQUEST:
544 [ + + ]: 4649 : if (sm->eapolEap)
545 : 1909 : SM_ENTER(BE_AUTH, RESPONSE);
546 [ - + ]: 2740 : else if (sm->eap_if->eapReq)
547 : 0 : SM_ENTER(BE_AUTH, REQUEST);
548 [ - + ]: 2740 : else if (sm->eap_if->eapTimeout)
549 : 0 : SM_ENTER(BE_AUTH, TIMEOUT);
550 : 4649 : break;
551 : : case BE_AUTH_RESPONSE:
552 [ - + ]: 5973 : if (sm->eap_if->eapNoReq)
553 : 0 : SM_ENTER(BE_AUTH, IGNORE);
554 [ + + ]: 5973 : if (sm->eap_if->eapReq) {
555 : 1560 : sm->backendAccessChallenges++;
556 : 1560 : SM_ENTER(BE_AUTH, REQUEST);
557 [ - + ]: 4413 : } else if (sm->aWhile == 0)
558 : 0 : SM_ENTER(BE_AUTH, TIMEOUT);
559 [ + + ]: 4413 : else if (sm->eap_if->eapFail) {
560 : 169 : sm->backendAuthFails++;
561 : 169 : SM_ENTER(BE_AUTH, FAIL);
562 [ + + ]: 4244 : } else if (sm->eap_if->eapSuccess) {
563 : 179 : sm->backendAuthSuccesses++;
564 : 179 : SM_ENTER(BE_AUTH, SUCCESS);
565 : : }
566 : 5973 : break;
567 : : case BE_AUTH_SUCCESS:
568 : 186 : SM_ENTER(BE_AUTH, IDLE);
569 : 186 : break;
570 : : case BE_AUTH_FAIL:
571 : 169 : SM_ENTER(BE_AUTH, IDLE);
572 : 169 : break;
573 : : case BE_AUTH_TIMEOUT:
574 : 0 : SM_ENTER(BE_AUTH, IDLE);
575 : 0 : break;
576 : : case BE_AUTH_IDLE:
577 [ + + ][ - + ]: 3334 : if (sm->eap_if->eapFail && sm->authStart)
578 : 0 : SM_ENTER(BE_AUTH, FAIL);
579 [ + + ][ + + ]: 3334 : else if (sm->eap_if->eapReq && sm->authStart)
580 : 352 : SM_ENTER(BE_AUTH, REQUEST);
581 [ + + ][ - + ]: 2982 : else if (sm->eap_if->eapSuccess && sm->authStart)
582 : 0 : SM_ENTER(BE_AUTH, SUCCESS);
583 : 3334 : break;
584 : : case BE_AUTH_IGNORE:
585 [ # # ]: 0 : if (sm->eapolEap)
586 : 0 : SM_ENTER(BE_AUTH, RESPONSE);
587 [ # # ]: 0 : else if (sm->eap_if->eapReq)
588 : 0 : SM_ENTER(BE_AUTH, REQUEST);
589 [ # # ]: 0 : else if (sm->eap_if->eapTimeout)
590 : 0 : SM_ENTER(BE_AUTH, TIMEOUT);
591 : 0 : break;
592 : : }
593 : : }
594 : :
595 : :
596 : :
597 : : /* Reauthentication Timer state machine */
598 : :
599 : 12927 : SM_STATE(REAUTH_TIMER, INITIALIZE)
600 : : {
601 [ + - ][ - + ]: 12927 : SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
602 : :
603 : 12927 : sm->reAuthWhen = sm->reAuthPeriod;
604 : 12927 : }
605 : :
606 : :
607 : 0 : SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
608 : : {
609 [ # # ][ # # ]: 0 : SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
610 : :
611 : 0 : sm->reAuthenticate = TRUE;
612 : 0 : sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
613 : : EAPOL_AUTH_REAUTHENTICATE);
614 : 0 : }
615 : :
616 : :
617 : 14969 : SM_STEP(REAUTH_TIMER)
618 : : {
619 [ + - ][ + + ]: 14969 : if (sm->portControl != Auto || sm->initialize ||
[ + + ]
620 [ - + ]: 2042 : sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
621 : 12927 : SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
622 : 14969 : return;
623 : : }
624 : :
625 [ + - - ]: 2042 : switch (sm->reauth_timer_state) {
626 : : case REAUTH_TIMER_INITIALIZE:
627 [ - + ]: 2042 : if (sm->reAuthWhen == 0)
628 : 0 : SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
629 : 2042 : break;
630 : : case REAUTH_TIMER_REAUTHENTICATE:
631 : 0 : SM_ENTER(REAUTH_TIMER, INITIALIZE);
632 : 0 : break;
633 : : }
634 : : }
635 : :
636 : :
637 : :
638 : : /* Authenticator Key Transmit state machine */
639 : :
640 : 328 : SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
641 : : {
642 [ + - ][ - + ]: 328 : SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
643 : 328 : }
644 : :
645 : :
646 : 2 : SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
647 : : {
648 [ - + ][ # # ]: 2 : SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
649 : :
650 : 2 : txKey();
651 : 2 : sm->eap_if->eapKeyAvailable = FALSE;
652 : 2 : sm->keyDone = TRUE;
653 : 2 : }
654 : :
655 : :
656 : 14969 : SM_STEP(AUTH_KEY_TX)
657 : : {
658 [ + + ][ - + ]: 14969 : if (sm->initialize || sm->portControl != Auto) {
659 : 328 : SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
660 : 14969 : return;
661 : : }
662 : :
663 [ + + - ]: 14641 : switch (sm->auth_key_tx_state) {
664 : : case AUTH_KEY_TX_NO_KEY_TRANSMIT:
665 [ + + ][ + + ]: 14637 : if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
[ + - ]
666 [ + - ]: 2 : sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
667 : 2 : SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
668 : 14637 : break;
669 : : case AUTH_KEY_TX_KEY_TRANSMIT:
670 [ + - ][ - + ]: 4 : if (!sm->keyTxEnabled || !sm->keyRun)
671 : 0 : SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
672 [ - + ]: 4 : else if (sm->eap_if->eapKeyAvailable)
673 : 0 : SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
674 : 4 : break;
675 : : }
676 : : }
677 : :
678 : :
679 : :
680 : : /* Key Receive state machine */
681 : :
682 : 1885 : SM_STATE(KEY_RX, NO_KEY_RECEIVE)
683 : : {
684 [ + - ][ - + ]: 1885 : SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
685 : 1885 : }
686 : :
687 : :
688 : 0 : SM_STATE(KEY_RX, KEY_RECEIVE)
689 : : {
690 [ # # ][ # # ]: 0 : SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
691 : :
692 : : processKey();
693 : 0 : sm->rxKey = FALSE;
694 : 0 : }
695 : :
696 : :
697 : 14969 : SM_STEP(KEY_RX)
698 : : {
699 [ + + ][ + + ]: 14969 : if (sm->initialize || !sm->eap_if->portEnabled) {
700 : 1885 : SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
701 : 14969 : return;
702 : : }
703 : :
704 [ + - - ]: 13084 : switch (sm->key_rx_state) {
705 : : case KEY_RX_NO_KEY_RECEIVE:
706 [ - + ]: 13084 : if (sm->rxKey)
707 : 0 : SM_ENTER(KEY_RX, KEY_RECEIVE);
708 : 13084 : break;
709 : : case KEY_RX_KEY_RECEIVE:
710 [ # # ]: 0 : if (sm->rxKey)
711 : 0 : SM_ENTER(KEY_RX, KEY_RECEIVE);
712 : 0 : break;
713 : : }
714 : : }
715 : :
716 : :
717 : :
718 : : /* Controlled Directions state machine */
719 : :
720 : 328 : SM_STATE(CTRL_DIR, FORCE_BOTH)
721 : : {
722 [ - + ][ # # ]: 328 : SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
723 : 328 : sm->operControlledDirections = Both;
724 : 328 : }
725 : :
726 : :
727 : 328 : SM_STATE(CTRL_DIR, IN_OR_BOTH)
728 : : {
729 [ + - ][ - + ]: 328 : SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
730 : 328 : sm->operControlledDirections = sm->adminControlledDirections;
731 : 328 : }
732 : :
733 : :
734 : 14969 : SM_STEP(CTRL_DIR)
735 : : {
736 [ + + ]: 14969 : if (sm->initialize) {
737 : 328 : SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
738 : 14969 : return;
739 : : }
740 : :
741 [ + + - ]: 14641 : switch (sm->ctrl_dir_state) {
742 : : case CTRL_DIR_FORCE_BOTH:
743 [ + + ][ - + ]: 14313 : if (sm->eap_if->portEnabled && sm->operEdge)
744 : 0 : SM_ENTER(CTRL_DIR, IN_OR_BOTH);
745 : 14313 : break;
746 : : case CTRL_DIR_IN_OR_BOTH:
747 [ - + ]: 328 : if (sm->operControlledDirections !=
748 : 328 : sm->adminControlledDirections)
749 : 0 : SM_ENTER(CTRL_DIR, IN_OR_BOTH);
750 [ - + ][ # # ]: 328 : if (!sm->eap_if->portEnabled || !sm->operEdge)
751 : 328 : SM_ENTER(CTRL_DIR, FORCE_BOTH);
752 : 328 : break;
753 : : }
754 : : }
755 : :
756 : :
757 : :
758 : : struct eapol_state_machine *
759 : 328 : eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
760 : : int flags, const struct wpabuf *assoc_wps_ie,
761 : : const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
762 : : const char *identity, const char *radius_cui)
763 : : {
764 : : struct eapol_state_machine *sm;
765 : : struct eap_config eap_conf;
766 : :
767 [ - + ]: 328 : if (eapol == NULL)
768 : 0 : return NULL;
769 : :
770 : 328 : sm = os_zalloc(sizeof(*sm));
771 [ - + ]: 328 : if (sm == NULL) {
772 : 0 : wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
773 : : "failed");
774 : 0 : return NULL;
775 : : }
776 : 328 : sm->radius_identifier = -1;
777 : 328 : os_memcpy(sm->addr, addr, ETH_ALEN);
778 : 328 : sm->flags = flags;
779 : :
780 : 328 : sm->eapol = eapol;
781 : 328 : sm->sta = sta_ctx;
782 : :
783 : : /* Set default values for state machine constants */
784 : 328 : sm->auth_pae_state = AUTH_PAE_INITIALIZE;
785 : 328 : sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
786 : 328 : sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
787 : :
788 : 328 : sm->be_auth_state = BE_AUTH_INITIALIZE;
789 : 328 : sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
790 : :
791 : 328 : sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
792 : 328 : sm->reAuthPeriod = eapol->conf.eap_reauth_period;
793 : 328 : sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
794 : :
795 : 328 : sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
796 : :
797 : 328 : sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
798 : :
799 : 328 : sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
800 : :
801 : 328 : sm->portControl = Auto;
802 : :
803 [ + + ][ + + ]: 328 : if (!eapol->conf.wpa &&
804 [ - + ]: 14 : (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
805 : 2 : sm->keyTxEnabled = TRUE;
806 : : else
807 : 326 : sm->keyTxEnabled = FALSE;
808 [ + + ]: 328 : if (eapol->conf.wpa)
809 : 312 : sm->portValid = FALSE;
810 : : else
811 : 16 : sm->portValid = TRUE;
812 : :
813 : 328 : os_memset(&eap_conf, 0, sizeof(eap_conf));
814 : 328 : eap_conf.eap_server = eapol->conf.eap_server;
815 : 328 : eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
816 : 328 : eap_conf.msg_ctx = eapol->conf.msg_ctx;
817 : 328 : eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
818 : 328 : eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
819 : 328 : eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
820 : 328 : eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
821 : 328 : eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
822 : 328 : eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
823 : 328 : eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
824 : 328 : eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
825 : 328 : eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
826 : 328 : eap_conf.tnc = eapol->conf.tnc;
827 : 328 : eap_conf.wps = eapol->conf.wps;
828 : 328 : eap_conf.assoc_wps_ie = assoc_wps_ie;
829 : 328 : eap_conf.assoc_p2p_ie = assoc_p2p_ie;
830 : 328 : eap_conf.peer_addr = addr;
831 : 328 : eap_conf.fragment_size = eapol->conf.fragment_size;
832 : 328 : eap_conf.pwd_group = eapol->conf.pwd_group;
833 : 328 : eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
834 : 328 : eap_conf.server_id = eapol->conf.server_id;
835 : 328 : eap_conf.server_id_len = eapol->conf.server_id_len;
836 : 328 : sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
837 [ - + ]: 328 : if (sm->eap == NULL) {
838 : 0 : eapol_auth_free(sm);
839 : 0 : return NULL;
840 : : }
841 : 328 : sm->eap_if = eap_get_interface(sm->eap);
842 : :
843 : 328 : eapol_auth_initialize(sm);
844 : :
845 [ - + ]: 328 : if (identity) {
846 : 0 : sm->identity = (u8 *) os_strdup(identity);
847 [ # # ]: 0 : if (sm->identity)
848 : 0 : sm->identity_len = os_strlen(identity);
849 : : }
850 [ - + ]: 328 : if (radius_cui)
851 : 0 : sm->radius_cui = wpabuf_alloc_copy(radius_cui,
852 : : os_strlen(radius_cui));
853 : :
854 : 328 : return sm;
855 : : }
856 : :
857 : :
858 : 328 : void eapol_auth_free(struct eapol_state_machine *sm)
859 : : {
860 [ - + ]: 328 : if (sm == NULL)
861 : 328 : return;
862 : :
863 : 328 : eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
864 : 328 : eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
865 [ + - ]: 328 : if (sm->eap)
866 : 328 : eap_server_sm_deinit(sm->eap);
867 : 328 : os_free(sm);
868 : : }
869 : :
870 : :
871 : 83945 : static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
872 : : const u8 *addr)
873 : : {
874 : 83945 : return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
875 : : }
876 : :
877 : :
878 : 5258 : static void eapol_sm_step_run(struct eapol_state_machine *sm)
879 : : {
880 : 5258 : struct eapol_authenticator *eapol = sm->eapol;
881 : : u8 addr[ETH_ALEN];
882 : : unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
883 : : prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
884 : 5258 : int max_steps = 100;
885 : :
886 : 5258 : os_memcpy(addr, sm->addr, ETH_ALEN);
887 : :
888 : : /*
889 : : * Allow EAPOL state machines to run as long as there are state
890 : : * changes, but exit and return here through event loop if more than
891 : : * 100 steps is needed as a precaution against infinite loops inside
892 : : * eloop callback.
893 : : */
894 : : restart:
895 : 14969 : prev_auth_pae = sm->auth_pae_state;
896 : 14969 : prev_be_auth = sm->be_auth_state;
897 : 14969 : prev_reauth_timer = sm->reauth_timer_state;
898 : 14969 : prev_auth_key_tx = sm->auth_key_tx_state;
899 : 14969 : prev_key_rx = sm->key_rx_state;
900 : 14969 : prev_ctrl_dir = sm->ctrl_dir_state;
901 : :
902 : 14969 : SM_STEP_RUN(AUTH_PAE);
903 [ + - ][ + + ]: 14969 : if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
904 : 14969 : SM_STEP_RUN(BE_AUTH);
905 [ + + ][ + - ]: 14969 : if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
906 : 14969 : SM_STEP_RUN(REAUTH_TIMER);
907 [ + + ][ + - ]: 14969 : if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
908 : 14969 : SM_STEP_RUN(AUTH_KEY_TX);
909 [ + + ][ + - ]: 14969 : if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
910 : 14969 : SM_STEP_RUN(KEY_RX);
911 [ + + ][ + - ]: 14969 : if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
912 : 14969 : SM_STEP_RUN(CTRL_DIR);
913 : :
914 [ + + ][ + + ]: 14969 : if (prev_auth_pae != sm->auth_pae_state ||
915 [ + - ]: 8762 : prev_be_auth != sm->be_auth_state ||
916 [ + - ]: 8762 : prev_reauth_timer != sm->reauth_timer_state ||
917 [ + - ]: 8762 : prev_auth_key_tx != sm->auth_key_tx_state ||
918 [ - + ]: 8762 : prev_key_rx != sm->key_rx_state ||
919 : 8762 : prev_ctrl_dir != sm->ctrl_dir_state) {
920 [ + - ]: 6207 : if (--max_steps > 0)
921 : 6207 : goto restart;
922 : : /* Re-run from eloop timeout */
923 : 0 : eapol_auth_step(sm);
924 : 0 : return;
925 : : }
926 : :
927 [ + + ][ + - ]: 8762 : if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
928 [ + + ]: 8106 : if (eap_server_sm_step(sm->eap)) {
929 [ + - ]: 3504 : if (--max_steps > 0)
930 : 3504 : goto restart;
931 : : /* Re-run from eloop timeout */
932 : 0 : eapol_auth_step(sm);
933 : 0 : return;
934 : : }
935 : :
936 : : /* TODO: find a better location for this */
937 [ + + ]: 4602 : if (sm->eap_if->aaaEapResp) {
938 : 1050 : sm->eap_if->aaaEapResp = FALSE;
939 [ - + ]: 1050 : if (sm->eap_if->aaaEapRespData == NULL) {
940 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
941 : : "but no aaaEapRespData available");
942 : 0 : return;
943 : : }
944 : 2100 : sm->eapol->cb.aaa_send(
945 : 1050 : sm->eapol->conf.ctx, sm->sta,
946 : 1050 : wpabuf_head(sm->eap_if->aaaEapRespData),
947 : 1050 : wpabuf_len(sm->eap_if->aaaEapRespData));
948 : : }
949 : : }
950 : :
951 [ + + ]: 5258 : if (eapol_sm_sta_entry_alive(eapol, addr))
952 : 5258 : sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
953 : : EAPOL_AUTH_SM_CHANGE);
954 : : }
955 : :
956 : :
957 : 4573 : static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
958 : : {
959 : 4573 : struct eapol_state_machine *sm = eloop_ctx;
960 : 4573 : eapol_sm_step_run(sm);
961 : 4573 : }
962 : :
963 : :
964 : : /**
965 : : * eapol_auth_step - Advance EAPOL state machines
966 : : * @sm: EAPOL state machine
967 : : *
968 : : * This function is called to advance EAPOL state machines after any change
969 : : * that could affect their state.
970 : : */
971 : 5183 : void eapol_auth_step(struct eapol_state_machine *sm)
972 : : {
973 : : /*
974 : : * Run eapol_sm_step_run from a registered timeout to make sure that
975 : : * other possible timeouts/events are processed and to avoid long
976 : : * function call chains.
977 : : */
978 : :
979 : 5183 : eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
980 : 5183 : }
981 : :
982 : :
983 : 328 : static void eapol_auth_initialize(struct eapol_state_machine *sm)
984 : : {
985 : 328 : sm->initializing = TRUE;
986 : : /* Initialize the state machines by asserting initialize and then
987 : : * deasserting it after one step */
988 : 328 : sm->initialize = TRUE;
989 : 328 : eapol_sm_step_run(sm);
990 : 328 : sm->initialize = FALSE;
991 : 328 : eapol_sm_step_run(sm);
992 : 328 : sm->initializing = FALSE;
993 : :
994 : : /* Start one second tick for port timers state machine */
995 : 328 : eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
996 : 328 : eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
997 : 328 : }
998 : :
999 : :
1000 : 159 : static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
1001 : : size_t identity_len, int phase2,
1002 : : struct eap_user *user)
1003 : : {
1004 : 159 : struct eapol_state_machine *sm = ctx;
1005 : : int ret;
1006 : :
1007 : 159 : ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
1008 : : identity_len, phase2, user);
1009 [ - + ]: 159 : if (user->remediation)
1010 : 0 : sm->remediation = 1;
1011 : 159 : return ret;
1012 : : }
1013 : :
1014 : :
1015 : 352 : static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
1016 : : {
1017 : 352 : struct eapol_state_machine *sm = ctx;
1018 : 352 : *len = sm->eapol->conf.eap_req_id_text_len;
1019 : 352 : return sm->eapol->conf.eap_req_id_text;
1020 : : }
1021 : :
1022 : :
1023 : : static struct eapol_callbacks eapol_cb =
1024 : : {
1025 : : eapol_sm_get_eap_user,
1026 : : eapol_sm_get_eap_req_id_text
1027 : : };
1028 : :
1029 : :
1030 : 23 : int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
1031 : : {
1032 [ + - ][ + - ]: 23 : if (sm == NULL || ctx == NULL || ctx != sm->eap)
[ - + ]
1033 : 0 : return -1;
1034 : :
1035 : 23 : eap_sm_pending_cb(sm->eap);
1036 : 23 : eapol_auth_step(sm);
1037 : :
1038 : 23 : return 0;
1039 : : }
1040 : :
1041 : :
1042 : 429 : static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
1043 : : struct eapol_auth_config *src)
1044 : : {
1045 : 429 : dst->ctx = src->ctx;
1046 : 429 : dst->eap_reauth_period = src->eap_reauth_period;
1047 : 429 : dst->wpa = src->wpa;
1048 : 429 : dst->individual_wep_key_len = src->individual_wep_key_len;
1049 : 429 : dst->eap_server = src->eap_server;
1050 : 429 : dst->ssl_ctx = src->ssl_ctx;
1051 : 429 : dst->msg_ctx = src->msg_ctx;
1052 : 429 : dst->eap_sim_db_priv = src->eap_sim_db_priv;
1053 : 429 : os_free(dst->eap_req_id_text);
1054 : 429 : dst->pwd_group = src->pwd_group;
1055 : 429 : dst->pbc_in_m1 = src->pbc_in_m1;
1056 : 429 : dst->server_id = src->server_id;
1057 : 429 : dst->server_id_len = src->server_id_len;
1058 [ - + ]: 429 : if (src->eap_req_id_text) {
1059 : 0 : dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
1060 [ # # ]: 0 : if (dst->eap_req_id_text == NULL)
1061 : 0 : return -1;
1062 : 0 : os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
1063 : : src->eap_req_id_text_len);
1064 : 0 : dst->eap_req_id_text_len = src->eap_req_id_text_len;
1065 : : } else {
1066 : 429 : dst->eap_req_id_text = NULL;
1067 : 429 : dst->eap_req_id_text_len = 0;
1068 : : }
1069 [ + + ]: 429 : if (src->pac_opaque_encr_key) {
1070 : 1 : dst->pac_opaque_encr_key = os_malloc(16);
1071 [ - + ]: 1 : if (dst->pac_opaque_encr_key == NULL) {
1072 : 0 : os_free(dst->eap_req_id_text);
1073 : 0 : return -1;
1074 : : }
1075 : 1 : os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
1076 : : 16);
1077 : : } else
1078 : 428 : dst->pac_opaque_encr_key = NULL;
1079 [ + + ]: 429 : if (src->eap_fast_a_id) {
1080 : 1 : dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
1081 [ - + ]: 1 : if (dst->eap_fast_a_id == NULL) {
1082 : 0 : os_free(dst->eap_req_id_text);
1083 : 0 : os_free(dst->pac_opaque_encr_key);
1084 : 0 : return -1;
1085 : : }
1086 : 1 : os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
1087 : : src->eap_fast_a_id_len);
1088 : 1 : dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
1089 : : } else
1090 : 428 : dst->eap_fast_a_id = NULL;
1091 [ + + ]: 429 : if (src->eap_fast_a_id_info) {
1092 : 1 : dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
1093 [ - + ]: 1 : if (dst->eap_fast_a_id_info == NULL) {
1094 : 0 : os_free(dst->eap_req_id_text);
1095 : 0 : os_free(dst->pac_opaque_encr_key);
1096 : 0 : os_free(dst->eap_fast_a_id);
1097 : 0 : return -1;
1098 : : }
1099 : : } else
1100 : 428 : dst->eap_fast_a_id_info = NULL;
1101 : 429 : dst->eap_fast_prov = src->eap_fast_prov;
1102 : 429 : dst->pac_key_lifetime = src->pac_key_lifetime;
1103 : 429 : dst->pac_key_refresh_time = src->pac_key_refresh_time;
1104 : 429 : dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
1105 : 429 : dst->tnc = src->tnc;
1106 : 429 : dst->wps = src->wps;
1107 : 429 : dst->fragment_size = src->fragment_size;
1108 : 429 : return 0;
1109 : : }
1110 : :
1111 : :
1112 : 429 : static void eapol_auth_conf_free(struct eapol_auth_config *conf)
1113 : : {
1114 : 429 : os_free(conf->eap_req_id_text);
1115 : 429 : conf->eap_req_id_text = NULL;
1116 : 429 : os_free(conf->pac_opaque_encr_key);
1117 : 429 : conf->pac_opaque_encr_key = NULL;
1118 : 429 : os_free(conf->eap_fast_a_id);
1119 : 429 : conf->eap_fast_a_id = NULL;
1120 : 429 : os_free(conf->eap_fast_a_id_info);
1121 : 429 : conf->eap_fast_a_id_info = NULL;
1122 : 429 : }
1123 : :
1124 : :
1125 : 429 : struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
1126 : : struct eapol_auth_cb *cb)
1127 : : {
1128 : : struct eapol_authenticator *eapol;
1129 : :
1130 : 429 : eapol = os_zalloc(sizeof(*eapol));
1131 [ - + ]: 429 : if (eapol == NULL)
1132 : 0 : return NULL;
1133 : :
1134 [ - + ]: 429 : if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
1135 : 0 : os_free(eapol);
1136 : 0 : return NULL;
1137 : : }
1138 : :
1139 [ + + ]: 429 : if (conf->individual_wep_key_len > 0) {
1140 : : /* use key0 in individual key and key1 in broadcast key */
1141 : 2 : eapol->default_wep_key_idx = 1;
1142 : : }
1143 : :
1144 : 429 : eapol->cb.eapol_send = cb->eapol_send;
1145 : 429 : eapol->cb.aaa_send = cb->aaa_send;
1146 : 429 : eapol->cb.finished = cb->finished;
1147 : 429 : eapol->cb.get_eap_user = cb->get_eap_user;
1148 : 429 : eapol->cb.sta_entry_alive = cb->sta_entry_alive;
1149 : 429 : eapol->cb.logger = cb->logger;
1150 : 429 : eapol->cb.set_port_authorized = cb->set_port_authorized;
1151 : 429 : eapol->cb.abort_auth = cb->abort_auth;
1152 : 429 : eapol->cb.tx_key = cb->tx_key;
1153 : 429 : eapol->cb.eapol_event = cb->eapol_event;
1154 : :
1155 : 429 : return eapol;
1156 : : }
1157 : :
1158 : :
1159 : 429 : void eapol_auth_deinit(struct eapol_authenticator *eapol)
1160 : : {
1161 [ - + ]: 429 : if (eapol == NULL)
1162 : 429 : return;
1163 : :
1164 : 429 : eapol_auth_conf_free(&eapol->conf);
1165 : 429 : os_free(eapol->default_wep_key);
1166 : 429 : os_free(eapol);
1167 : : }
|