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