2
* hostapd / EAP Standalone Authenticator state machine (RFC 4137)
3
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
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.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
19
#include "state_machine.h"
21
#define STATE_MACHINE_DATA struct eap_sm
22
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
24
#define EAP_MAX_AUTH_ROUNDS 50
26
static void eap_user_free(struct eap_user *user);
29
/* EAP state machines are described in RFC 4137 */
31
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
32
int eapSRTT, int eapRTTVAR,
34
static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
35
static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
36
static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
37
static int eap_sm_nextId(struct eap_sm *sm, int id);
38
static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
39
static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
40
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
41
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
44
static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
46
return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
50
static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
53
sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
57
static void eapol_set_eapReqData(struct eap_sm *sm,
58
const u8 *eapReqData, size_t eapReqDataLen)
60
wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
61
sm->eapReqData, sm->eapReqDataLen);
62
sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
66
static void eapol_set_eapKeyData(struct eap_sm *sm,
67
const u8 *eapKeyData, size_t eapKeyDataLen)
69
wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
70
sm->eapKeyData, sm->eapKeyDataLen);
71
sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
76
* eap_user_get - Fetch user information from the database
77
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
78
* @identity: Identity (User-Name) of the user
79
* @identity_len: Length of identity in bytes
80
* @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
81
* Returns: 0 on success, or -1 on failure
83
* This function is used to fetch user information for EAP. The user will be
84
* selected based on the specified identity. sm->user and
85
* sm->user_eap_method_index are updated for the new user when a matching user
86
* is found. sm->user can be used to get user information (e.g., password).
88
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
91
struct eap_user *user;
93
if (sm == NULL || sm->eapol_cb == NULL ||
94
sm->eapol_cb->get_eap_user == NULL)
97
eap_user_free(sm->user);
100
user = os_zalloc(sizeof(*user));
104
if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
105
identity_len, phase2, user) != 0) {
111
sm->user_eap_method_index = 0;
117
SM_STATE(EAP, DISABLED)
119
SM_ENTRY(EAP, DISABLED);
124
SM_STATE(EAP, INITIALIZE)
126
SM_ENTRY(EAP, INITIALIZE);
129
eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
130
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
131
eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
132
free(sm->eapKeyData);
133
sm->eapKeyData = NULL;
134
sm->eapKeyDataLen = 0;
135
/* eapKeyAvailable = FALSE */
136
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
139
* This is not defined in RFC 4137, but method state needs to be
140
* reseted here so that it does not remain in success state when
141
* re-authentication starts.
143
if (sm->m && sm->eap_method_priv) {
144
sm->m->reset(sm, sm->eap_method_priv);
145
sm->eap_method_priv = NULL;
148
sm->user_eap_method_index = 0;
150
if (sm->backend_auth) {
151
sm->currentMethod = EAP_TYPE_NONE;
152
/* parse rxResp, respId, respMethod */
153
eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
155
sm->currentId = sm->respId;
159
sm->method_pending = METHOD_PENDING_NONE;
163
SM_STATE(EAP, PICK_UP_METHOD)
165
SM_ENTRY(EAP, PICK_UP_METHOD);
167
if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
168
sm->currentMethod = sm->respMethod;
169
if (sm->m && sm->eap_method_priv) {
170
sm->m->reset(sm, sm->eap_method_priv);
171
sm->eap_method_priv = NULL;
173
sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
175
if (sm->m && sm->m->initPickUp) {
176
sm->eap_method_priv = sm->m->initPickUp(sm);
177
if (sm->eap_method_priv == NULL) {
178
wpa_printf(MSG_DEBUG, "EAP: Failed to "
179
"initialize EAP method %d",
182
sm->currentMethod = EAP_TYPE_NONE;
186
sm->currentMethod = EAP_TYPE_NONE;
196
sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
197
sm->eapSRTT, sm->eapRTTVAR,
202
SM_STATE(EAP, RETRANSMIT)
204
SM_ENTRY(EAP, RETRANSMIT);
206
/* TODO: Is this needed since EAPOL state machines take care of
211
SM_STATE(EAP, RECEIVED)
213
SM_ENTRY(EAP, RECEIVED);
215
/* parse rxResp, respId, respMethod */
216
eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
221
SM_STATE(EAP, DISCARD)
223
SM_ENTRY(EAP, DISCARD);
224
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
225
eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
229
SM_STATE(EAP, SEND_REQUEST)
231
SM_ENTRY(EAP, SEND_REQUEST);
233
sm->retransCount = 0;
234
if (sm->eapReqData) {
235
eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
236
free(sm->lastReqData);
237
sm->lastReqData = sm->eapReqData;
238
sm->lastReqDataLen = sm->eapReqDataLen;
239
sm->eapReqData = NULL;
240
sm->eapReqDataLen = 0;
241
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
242
eapol_set_bool(sm, EAPOL_eapReq, TRUE);
244
wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
245
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
246
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
247
eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
252
SM_STATE(EAP, INTEGRITY_CHECK)
254
SM_ENTRY(EAP, INTEGRITY_CHECK);
257
sm->ignore = sm->m->check(sm, sm->eap_method_priv,
258
sm->eapRespData, sm->eapRespDataLen);
263
SM_STATE(EAP, METHOD_REQUEST)
265
SM_ENTRY(EAP, METHOD_REQUEST);
268
wpa_printf(MSG_DEBUG, "EAP: method not initialized");
272
sm->currentId = eap_sm_nextId(sm, sm->currentId);
273
wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
275
sm->lastId = sm->currentId;
276
free(sm->eapReqData);
277
sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
278
sm->currentId, &sm->eapReqDataLen);
279
if (sm->m->getTimeout)
280
sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
282
sm->methodTimeout = 0;
286
SM_STATE(EAP, METHOD_RESPONSE)
288
SM_ENTRY(EAP, METHOD_RESPONSE);
290
sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
292
if (sm->m->isDone(sm, sm->eap_method_priv)) {
293
eap_sm_Policy_update(sm, NULL, 0);
294
free(sm->eapKeyData);
296
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
299
sm->eapKeyData = NULL;
300
sm->eapKeyDataLen = 0;
302
sm->methodState = METHOD_END;
304
sm->methodState = METHOD_CONTINUE;
309
SM_STATE(EAP, PROPOSE_METHOD)
314
SM_ENTRY(EAP, PROPOSE_METHOD);
316
type = eap_sm_Policy_getNextMethod(sm, &vendor);
317
if (vendor == EAP_VENDOR_IETF)
318
sm->currentMethod = type;
320
sm->currentMethod = EAP_TYPE_EXPANDED;
321
if (sm->m && sm->eap_method_priv) {
322
sm->m->reset(sm, sm->eap_method_priv);
323
sm->eap_method_priv = NULL;
325
sm->m = eap_server_get_eap_method(vendor, type);
327
sm->eap_method_priv = sm->m->init(sm);
328
if (sm->eap_method_priv == NULL) {
329
wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
330
"method %d", sm->currentMethod);
332
sm->currentMethod = EAP_TYPE_NONE;
335
if (sm->currentMethod == EAP_TYPE_IDENTITY ||
336
sm->currentMethod == EAP_TYPE_NOTIFICATION)
337
sm->methodState = METHOD_CONTINUE;
339
sm->methodState = METHOD_PROPOSED;
347
u8 *pos, *nak_list = NULL;
351
if (sm->eap_method_priv) {
352
sm->m->reset(sm, sm->eap_method_priv);
353
sm->eap_method_priv = NULL;
357
nak = (struct eap_hdr *) sm->eapRespData;
358
if (nak && sm->eapRespDataLen > sizeof(*nak)) {
359
len = be_to_host16(nak->length);
360
if (len > sm->eapRespDataLen)
361
len = sm->eapRespDataLen;
362
pos = (u8 *) (nak + 1);
364
if (*pos == EAP_TYPE_NAK) {
370
eap_sm_Policy_update(sm, nak_list, len);
374
SM_STATE(EAP, SELECT_ACTION)
376
SM_ENTRY(EAP, SELECT_ACTION);
378
sm->decision = eap_sm_Policy_getDecision(sm);
382
SM_STATE(EAP, TIMEOUT_FAILURE)
384
SM_ENTRY(EAP, TIMEOUT_FAILURE);
386
eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
390
SM_STATE(EAP, FAILURE)
392
SM_ENTRY(EAP, FAILURE);
394
free(sm->eapReqData);
395
sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
397
if (sm->eapReqData) {
398
eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
399
free(sm->eapReqData);
400
sm->eapReqData = NULL;
401
sm->eapReqDataLen = 0;
403
free(sm->lastReqData);
404
sm->lastReqData = NULL;
405
sm->lastReqDataLen = 0;
406
eapol_set_bool(sm, EAPOL_eapFail, TRUE);
410
SM_STATE(EAP, SUCCESS)
412
SM_ENTRY(EAP, SUCCESS);
414
free(sm->eapReqData);
415
sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
417
if (sm->eapReqData) {
418
eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
419
free(sm->eapReqData);
420
sm->eapReqData = NULL;
421
sm->eapReqDataLen = 0;
423
free(sm->lastReqData);
424
sm->lastReqData = NULL;
425
sm->lastReqDataLen = 0;
426
if (sm->eapKeyData) {
427
eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
429
eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
435
if (eapol_get_bool(sm, EAPOL_eapRestart) &&
436
eapol_get_bool(sm, EAPOL_portEnabled))
437
SM_ENTER_GLOBAL(EAP, INITIALIZE);
438
else if (!eapol_get_bool(sm, EAPOL_portEnabled))
439
SM_ENTER_GLOBAL(EAP, DISABLED);
440
else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
441
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
442
wpa_printf(MSG_DEBUG, "EAP: more than %d "
443
"authentication rounds - abort",
444
EAP_MAX_AUTH_ROUNDS);
446
SM_ENTER_GLOBAL(EAP, FAILURE);
448
} else switch (sm->EAP_state) {
450
if (sm->backend_auth) {
452
SM_ENTER(EAP, SELECT_ACTION);
453
else if (sm->rxResp &&
454
(sm->respMethod == EAP_TYPE_NAK ||
455
(sm->respMethod == EAP_TYPE_EXPANDED &&
456
sm->respVendor == EAP_VENDOR_IETF &&
457
sm->respVendorMethod == EAP_TYPE_NAK)))
460
SM_ENTER(EAP, PICK_UP_METHOD);
462
SM_ENTER(EAP, SELECT_ACTION);
465
case EAP_PICK_UP_METHOD:
466
if (sm->currentMethod == EAP_TYPE_NONE) {
467
SM_ENTER(EAP, SELECT_ACTION);
469
SM_ENTER(EAP, METHOD_RESPONSE);
473
if (eapol_get_bool(sm, EAPOL_portEnabled))
474
SM_ENTER(EAP, INITIALIZE);
477
if (sm->retransWhile == 0)
478
SM_ENTER(EAP, RETRANSMIT);
479
else if (eapol_get_bool(sm, EAPOL_eapResp))
480
SM_ENTER(EAP, RECEIVED);
483
if (sm->retransCount > sm->MaxRetrans)
484
SM_ENTER(EAP, TIMEOUT_FAILURE);
489
if (sm->rxResp && (sm->respId == sm->currentId) &&
490
(sm->respMethod == EAP_TYPE_NAK ||
491
(sm->respMethod == EAP_TYPE_EXPANDED &&
492
sm->respVendor == EAP_VENDOR_IETF &&
493
sm->respVendorMethod == EAP_TYPE_NAK))
494
&& (sm->methodState == METHOD_PROPOSED))
496
else if (sm->rxResp && (sm->respId == sm->currentId) &&
497
((sm->respMethod == sm->currentMethod) ||
498
(sm->respMethod == EAP_TYPE_EXPANDED &&
499
sm->respVendor == EAP_VENDOR_IETF &&
500
sm->respVendorMethod == sm->currentMethod)))
501
SM_ENTER(EAP, INTEGRITY_CHECK);
503
wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
504
"rxResp=%d respId=%d currentId=%d "
505
"respMethod=%d currentMethod=%d",
506
sm->rxResp, sm->respId, sm->currentId,
507
sm->respMethod, sm->currentMethod);
508
SM_ENTER(EAP, DISCARD);
514
case EAP_SEND_REQUEST:
517
case EAP_INTEGRITY_CHECK:
519
SM_ENTER(EAP, DISCARD);
521
SM_ENTER(EAP, METHOD_RESPONSE);
523
case EAP_METHOD_REQUEST:
524
SM_ENTER(EAP, SEND_REQUEST);
526
case EAP_METHOD_RESPONSE:
528
* Note: Mechanism to allow EAP methods to wait while going
529
* through pending processing is an extension to RFC 4137
530
* which only defines the transits to SELECT_ACTION and
531
* METHOD_REQUEST from this METHOD_RESPONSE state.
533
if (sm->methodState == METHOD_END)
534
SM_ENTER(EAP, SELECT_ACTION);
535
else if (sm->method_pending == METHOD_PENDING_WAIT) {
536
wpa_printf(MSG_DEBUG, "EAP: Method has pending "
537
"processing - wait before proceeding to "
538
"METHOD_REQUEST state");
539
} else if (sm->method_pending == METHOD_PENDING_CONT) {
540
wpa_printf(MSG_DEBUG, "EAP: Method has completed "
541
"pending processing - reprocess pending "
543
sm->method_pending = METHOD_PENDING_NONE;
544
SM_ENTER(EAP, METHOD_RESPONSE);
546
SM_ENTER(EAP, METHOD_REQUEST);
548
case EAP_PROPOSE_METHOD:
550
* Note: Mechanism to allow EAP methods to wait while going
551
* through pending processing is an extension to RFC 4137
552
* which only defines the transit to METHOD_REQUEST from this
553
* PROPOSE_METHOD state.
555
if (sm->method_pending == METHOD_PENDING_WAIT) {
556
wpa_printf(MSG_DEBUG, "EAP: Method has pending "
557
"processing - wait before proceeding to "
558
"METHOD_REQUEST state");
559
if (sm->user_eap_method_index > 0)
560
sm->user_eap_method_index--;
561
} else if (sm->method_pending == METHOD_PENDING_CONT) {
562
wpa_printf(MSG_DEBUG, "EAP: Method has completed "
563
"pending processing - reprocess pending "
565
sm->method_pending = METHOD_PENDING_NONE;
566
SM_ENTER(EAP, PROPOSE_METHOD);
568
SM_ENTER(EAP, METHOD_REQUEST);
571
SM_ENTER(EAP, SELECT_ACTION);
573
case EAP_SELECT_ACTION:
574
if (sm->decision == DECISION_FAILURE)
575
SM_ENTER(EAP, FAILURE);
576
else if (sm->decision == DECISION_SUCCESS)
577
SM_ENTER(EAP, SUCCESS);
579
SM_ENTER(EAP, PROPOSE_METHOD);
581
case EAP_TIMEOUT_FAILURE:
591
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
592
int eapSRTT, int eapRTTVAR,
595
/* For now, retransmission is done in EAPOL state machines, so make
596
* sure EAP state machine does not end up trying to retransmit packets.
602
static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
607
/* parse rxResp, respId, respMethod */
610
sm->respMethod = EAP_TYPE_NONE;
611
sm->respVendor = EAP_VENDOR_IETF;
612
sm->respVendorMethod = EAP_TYPE_NONE;
614
if (resp == NULL || len < sizeof(*hdr))
617
hdr = (struct eap_hdr *) resp;
618
plen = be_to_host16(hdr->length);
620
wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
621
"(len=%lu plen=%lu)", (unsigned long) len,
622
(unsigned long) plen);
626
sm->respId = hdr->identifier;
628
if (hdr->code == EAP_CODE_RESPONSE)
631
if (plen > sizeof(*hdr)) {
632
u8 *pos = (u8 *) (hdr + 1);
633
sm->respMethod = *pos++;
634
if (sm->respMethod == EAP_TYPE_EXPANDED) {
635
if (plen < sizeof(*hdr) + 8) {
636
wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
637
"expanded EAP-Packet (plen=%lu)",
638
(unsigned long) plen);
641
sm->respVendor = WPA_GET_BE24(pos);
643
sm->respVendorMethod = WPA_GET_BE32(pos);
647
wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
648
"respMethod=%u respVendor=%u respVendorMethod=%u",
649
sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
650
sm->respVendorMethod);
654
static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
656
struct eap_hdr *resp;
657
wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
659
*len = sizeof(*resp);
663
resp->code = EAP_CODE_SUCCESS;
664
resp->identifier = id;
665
resp->length = host_to_be16(*len);
671
static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
673
struct eap_hdr *resp;
674
wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
676
*len = sizeof(*resp);
680
resp->code = EAP_CODE_FAILURE;
681
resp->identifier = id;
682
resp->length = host_to_be16(*len);
688
static int eap_sm_nextId(struct eap_sm *sm, int id)
691
/* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
694
if (id != sm->lastId)
697
return (id + 1) & 0xff;
702
* eap_sm_process_nak - Process EAP-Response/Nak
703
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
704
* @nak_list: Nak list (allowed methods) from the supplicant
705
* @len: Length of nak_list in bytes
707
* This function is called when EAP-Response/Nak is received from the
708
* supplicant. This can happen for both phase 1 and phase 2 authentications.
710
void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
715
if (sm->user == NULL)
718
wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
719
"index %d)", sm->user_eap_method_index);
721
wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
722
(u8 *) sm->user->methods,
723
EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
724
wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
727
i = sm->user_eap_method_index;
728
while (i < EAP_MAX_METHODS &&
729
(sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
730
sm->user->methods[i].method != EAP_TYPE_NONE)) {
731
if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
733
for (j = 0; j < len; j++) {
734
if (nak_list[j] == sm->user->methods[i].method) {
746
/* not found - remove from the list */
747
memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
748
(EAP_MAX_METHODS - i - 1) *
749
sizeof(sm->user->methods[0]));
750
sm->user->methods[EAP_MAX_METHODS - 1].vendor =
752
sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
755
wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
756
(u8 *) sm->user->methods, EAP_MAX_METHODS *
757
sizeof(sm->user->methods[0]));
761
static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
763
if (nak_list == NULL || sm == NULL || sm->user == NULL)
766
if (sm->user->phase2) {
767
wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
768
" info was selected - reject");
769
sm->decision = DECISION_FAILURE;
773
eap_sm_process_nak(sm, nak_list, len);
777
static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
780
int idx = sm->user_eap_method_index;
782
/* In theory, there should be no problems with starting
783
* re-authentication with something else than EAP-Request/Identity and
784
* this does indeed work with wpa_supplicant. However, at least Funk
785
* Supplicant seemed to ignore re-auth if it skipped
786
* EAP-Request/Identity.
787
* Re-auth sets currentId == -1, so that can be used here to select
788
* whether Identity needs to be requested again. */
789
if (sm->identity == NULL || sm->currentId == -1) {
790
*vendor = EAP_VENDOR_IETF;
791
next = EAP_TYPE_IDENTITY;
792
sm->update_user = TRUE;
793
} else if (sm->user && idx < EAP_MAX_METHODS &&
794
(sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
795
sm->user->methods[idx].method != EAP_TYPE_NONE)) {
796
*vendor = sm->user->methods[idx].vendor;
797
next = sm->user->methods[idx].method;
798
sm->user_eap_method_index++;
800
*vendor = EAP_VENDOR_IETF;
801
next = EAP_TYPE_NONE;
803
wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
809
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
811
if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
812
sm->m->isSuccess(sm, sm->eap_method_priv)) {
813
wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
815
sm->update_user = TRUE;
816
return DECISION_SUCCESS;
819
if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
820
!sm->m->isSuccess(sm, sm->eap_method_priv)) {
821
wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
823
sm->update_user = TRUE;
824
return DECISION_FAILURE;
827
if ((sm->user == NULL || sm->update_user) && sm->identity) {
828
if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
829
wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
830
"found from database -> FAILURE");
831
return DECISION_FAILURE;
833
sm->update_user = FALSE;
836
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
837
(sm->user->methods[sm->user_eap_method_index].vendor !=
839
sm->user->methods[sm->user_eap_method_index].method !=
841
wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
842
"available -> CONTINUE");
843
return DECISION_CONTINUE;
846
if (sm->identity == NULL || sm->currentId == -1) {
847
wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
849
return DECISION_CONTINUE;
852
wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
854
return DECISION_FAILURE;
858
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
860
return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
865
* eap_server_sm_step - Step EAP server state machine
866
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
867
* Returns: 1 if EAP state was changed or 0 if not
869
* This function advances EAP state machine to a new state to match with the
870
* current variables. This should be called whenever variables used by the EAP
871
* state machine have changed.
873
int eap_server_sm_step(struct eap_sm *sm)
881
} while (sm->changed);
887
* eap_set_eapRespData - Set EAP response (eapRespData)
888
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
889
* @eapRespData: EAP-Response payload from the supplicant
890
* @eapRespDataLen: Length of eapRespData in bytes
892
* This function is called when an EAP-Response is received from a supplicant.
894
void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
895
size_t eapRespDataLen)
899
free(sm->eapRespData);
900
sm->eapRespData = malloc(eapRespDataLen);
901
if (sm->eapRespData == NULL)
903
memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
904
sm->eapRespDataLen = eapRespDataLen;
905
wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
906
eapRespData, eapRespDataLen);
910
static void eap_user_free(struct eap_user *user)
914
free(user->password);
915
user->password = NULL;
921
* eap_server_sm_init - Allocate and initialize EAP server state machine
922
* @eapol_ctx: Context data to be used with eapol_cb calls
923
* @eapol_cb: Pointer to EAPOL callback functions
924
* @conf: EAP configuration
925
* Returns: Pointer to the allocated EAP state machine or %NULL on failure
927
* This function allocates and initializes an EAP state machine.
929
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
930
struct eapol_callbacks *eapol_cb,
931
struct eap_config *conf)
935
sm = os_zalloc(sizeof(*sm));
938
sm->eapol_ctx = eapol_ctx;
939
sm->eapol_cb = eapol_cb;
941
sm->ssl_ctx = conf->ssl_ctx;
942
sm->eap_sim_db_priv = conf->eap_sim_db_priv;
943
sm->backend_auth = conf->backend_auth;
945
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
952
* eap_server_sm_deinit - Deinitialize and free an EAP server state machine
953
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
955
* This function deinitializes EAP state machine and frees all allocated
958
void eap_server_sm_deinit(struct eap_sm *sm)
962
wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
963
if (sm->m && sm->eap_method_priv)
964
sm->m->reset(sm, sm->eap_method_priv);
965
free(sm->eapReqData);
966
free(sm->eapKeyData);
967
free(sm->lastReqData);
968
free(sm->eapRespData);
970
eap_user_free(sm->user);
976
* eap_sm_notify_cached - Notify EAP state machine of cached PMK
977
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
979
* This function is called when PMKSA caching is used to skip EAP
982
void eap_sm_notify_cached(struct eap_sm *sm)
987
sm->EAP_state = EAP_SUCCESS;
992
* eap_sm_pending_cb - EAP state machine callback for a pending EAP request
993
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
995
* This function is called when data for a pending EAP-Request is received.
997
void eap_sm_pending_cb(struct eap_sm *sm)
1001
wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
1002
if (sm->method_pending == METHOD_PENDING_WAIT)
1003
sm->method_pending = METHOD_PENDING_CONT;
1008
* eap_sm_method_pending - Query whether EAP method is waiting for pending data
1009
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1010
* Returns: 1 if method is waiting for pending data or 0 if not
1012
int eap_sm_method_pending(struct eap_sm *sm)
1016
return sm->method_pending == METHOD_PENDING_WAIT;