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