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