~cyphermox/ubuntu/lucid/wpasupplicant/dbus-pkcs11-eapol

« back to all changes in this revision

Viewing changes to eap.c

  • Committer: Bazaar Package Importer
  • Author(s): Kyle McMartin
  • Date: 2005-02-15 00:51:28 UTC
  • Revision ID: james.westby@ubuntu.com-20050215005128-xr4m8owiunur2008
Tags: upstream-0.3.8
ImportĀ upstreamĀ versionĀ 0.3.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant / EAP state machines
 
3
 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
 
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 <stdlib.h>
 
16
#include <stdio.h>
 
17
#include <string.h>
 
18
 
 
19
#include "common.h"
 
20
#include "eap_i.h"
 
21
#include "wpa_supplicant.h"
 
22
#include "config_ssid.h"
 
23
#include "tls.h"
 
24
#include "md5.h"
 
25
 
 
26
 
 
27
#define EAP_MAX_AUTH_ROUNDS 50
 
28
 
 
29
 
 
30
#ifdef EAP_MD5
 
31
extern const struct eap_method eap_method_md5;
 
32
#endif
 
33
#ifdef EAP_TLS
 
34
extern const struct eap_method eap_method_tls;
 
35
#endif
 
36
#ifdef EAP_MSCHAPv2
 
37
extern const struct eap_method eap_method_mschapv2;
 
38
#endif
 
39
#ifdef EAP_PEAP
 
40
extern const struct eap_method eap_method_peap;
 
41
#endif
 
42
#ifdef EAP_TTLS
 
43
extern const struct eap_method eap_method_ttls;
 
44
#endif
 
45
#ifdef EAP_GTC
 
46
extern const struct eap_method eap_method_gtc;
 
47
#endif
 
48
#ifdef EAP_OTP
 
49
extern const struct eap_method eap_method_otp;
 
50
#endif
 
51
#ifdef EAP_SIM
 
52
extern const struct eap_method eap_method_sim;
 
53
#endif
 
54
#ifdef EAP_LEAP
 
55
extern const struct eap_method eap_method_leap;
 
56
#endif
 
57
#ifdef EAP_PSK
 
58
extern const struct eap_method eap_method_psk;
 
59
#endif
 
60
#ifdef EAP_AKA
 
61
extern const struct eap_method eap_method_aka;
 
62
#endif
 
63
#ifdef EAP_FAST
 
64
extern const struct eap_method eap_method_fast;
 
65
#endif
 
66
 
 
67
static const struct eap_method *eap_methods[] =
 
68
{
 
69
#ifdef EAP_MD5
 
70
        &eap_method_md5,
 
71
#endif
 
72
#ifdef EAP_TLS
 
73
        &eap_method_tls,
 
74
#endif
 
75
#ifdef EAP_MSCHAPv2
 
76
        &eap_method_mschapv2,
 
77
#endif
 
78
#ifdef EAP_PEAP
 
79
        &eap_method_peap,
 
80
#endif
 
81
#ifdef EAP_TTLS
 
82
        &eap_method_ttls,
 
83
#endif
 
84
#ifdef EAP_GTC
 
85
        &eap_method_gtc,
 
86
#endif
 
87
#ifdef EAP_OTP
 
88
        &eap_method_otp,
 
89
#endif
 
90
#ifdef EAP_SIM
 
91
        &eap_method_sim,
 
92
#endif
 
93
#ifdef EAP_LEAP
 
94
        &eap_method_leap,
 
95
#endif
 
96
#ifdef EAP_PSK
 
97
        &eap_method_psk,
 
98
#endif
 
99
#ifdef EAP_AKA
 
100
        &eap_method_aka,
 
101
#endif
 
102
#ifdef EAP_FAST
 
103
        &eap_method_fast,
 
104
#endif
 
105
};
 
106
#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
 
107
 
 
108
 
 
109
const struct eap_method * eap_sm_get_eap_methods(int method)
 
110
{
 
111
        int i;
 
112
        for (i = 0; i < NUM_EAP_METHODS; i++) {
 
113
                if (eap_methods[i]->method == method)
 
114
                        return eap_methods[i];
 
115
        }
 
116
        return NULL;
 
117
}
 
118
 
 
119
 
 
120
static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
 
121
static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
 
122
static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len);
 
123
static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len);
 
124
static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
 
125
static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len);
 
126
static const char * eap_sm_method_state_txt(int state);
 
127
static const char * eap_sm_decision_txt(int decision);
 
128
 
 
129
 
 
130
/* Definitions for clarifying state machine implementation */
 
131
#define SM_STATE(machine, state) \
 
132
static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
 
133
        int global)
 
134
 
 
135
#define SM_ENTRY(machine, state) \
 
136
if (!global || sm->machine ## _state != machine ## _ ## state) { \
 
137
        sm->changed = TRUE; \
 
138
        wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
 
139
} \
 
140
sm->machine ## _state = machine ## _ ## state;
 
141
 
 
142
#define SM_ENTER(machine, state) \
 
143
sm_ ## machine ## _ ## state ## _Enter(sm, 0)
 
144
#define SM_ENTER_GLOBAL(machine, state) \
 
145
sm_ ## machine ## _ ## state ## _Enter(sm, 1)
 
146
 
 
147
#define SM_STEP(machine) \
 
148
static void sm_ ## machine ## _Step(struct eap_sm *sm)
 
149
 
 
150
#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
 
151
 
 
152
 
 
153
static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
 
154
{
 
155
        return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
 
156
}
 
157
 
 
158
 
 
159
static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
 
160
                           Boolean value)
 
161
{
 
162
        sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
 
163
}
 
164
 
 
165
 
 
166
static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
 
167
{
 
168
        return sm->eapol_cb->get_int(sm->eapol_ctx, var);
 
169
}
 
170
 
 
171
 
 
172
static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
 
173
                          unsigned int value)
 
174
{
 
175
        sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
 
176
}
 
177
 
 
178
 
 
179
static u8 * eapol_get_eapReqData(struct eap_sm *sm, size_t *len)
 
180
{
 
181
        return sm->eapol_cb->get_eapReqData(sm->eapol_ctx, len);
 
182
}
 
183
 
 
184
 
 
185
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
 
186
{
 
187
        if (sm->m == NULL || sm->eap_method_priv == NULL)
 
188
                return;
 
189
 
 
190
        wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
 
191
                   "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
 
192
        sm->m->deinit(sm, sm->eap_method_priv);
 
193
        sm->eap_method_priv = NULL;
 
194
        sm->m = NULL;
 
195
}
 
196
 
 
197
 
 
198
SM_STATE(EAP, INITIALIZE)
 
199
{
 
200
        SM_ENTRY(EAP, INITIALIZE);
 
201
        if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
 
202
            sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
 
203
                wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
 
204
                           "fast reauthentication");
 
205
                sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
 
206
        } else {
 
207
                eap_deinit_prev_method(sm, "INITIALIZE");
 
208
        }
 
209
        sm->selectedMethod = EAP_TYPE_NONE;
 
210
        sm->methodState = METHOD_NONE;
 
211
        sm->allowNotifications = TRUE;
 
212
        sm->decision = DECISION_FAIL;
 
213
        eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
 
214
        eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
 
215
        eapol_set_bool(sm, EAPOL_eapFail, FALSE);
 
216
        free(sm->eapKeyData);
 
217
        sm->eapKeyData = NULL;
 
218
        sm->eapKeyAvailable = FALSE;
 
219
        eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
 
220
        sm->lastId = -1; /* new session - make sure this does not match with
 
221
                          * the first EAP-Packet */
 
222
        /* draft-ietf-eap-statemachine-02.pdf does not reset eapResp and
 
223
         * eapNoResp here. However, this seemed to be able to trigger cases
 
224
         * where both were set and if EAPOL state machine uses eapNoResp first,
 
225
         * it may end up not sending a real reply correctly. This occurred
 
226
         * when the workaround in FAIL state set eapNoResp = TRUE.. Maybe that
 
227
         * workaround needs to be fixed to do something else(?) */
 
228
        eapol_set_bool(sm, EAPOL_eapResp, FALSE);
 
229
        eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
 
230
        sm->num_rounds = 0;
 
231
}
 
232
 
 
233
 
 
234
SM_STATE(EAP, DISABLED)
 
235
{
 
236
        SM_ENTRY(EAP, DISABLED);
 
237
        sm->num_rounds = 0;
 
238
}
 
239
 
 
240
 
 
241
SM_STATE(EAP, IDLE)
 
242
{
 
243
        SM_ENTRY(EAP, IDLE);
 
244
}
 
245
 
 
246
 
 
247
SM_STATE(EAP, RECEIVED)
 
248
{
 
249
        u8 *eapReqData;
 
250
        size_t eapReqDataLen;
 
251
 
 
252
        SM_ENTRY(EAP, RECEIVED);
 
253
        eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
 
254
        /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
 
255
        eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
 
256
        sm->num_rounds++;
 
257
}
 
258
 
 
259
 
 
260
SM_STATE(EAP, GET_METHOD)
 
261
{
 
262
        SM_ENTRY(EAP, GET_METHOD);
 
263
        if (eap_sm_allowMethod(sm, sm->reqMethod)) {
 
264
                int reinit = 0;
 
265
                if (sm->fast_reauth &&
 
266
                    sm->m && sm->m->method == sm->reqMethod &&
 
267
                    sm->m->has_reauth_data &&
 
268
                    sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
 
269
                        wpa_printf(MSG_DEBUG, "EAP: using previous method data"
 
270
                                   " for fast re-authentication");
 
271
                        reinit = 1;
 
272
                } else
 
273
                        eap_deinit_prev_method(sm, "GET_METHOD");
 
274
                sm->selectedMethod = sm->reqMethod;
 
275
                if (sm->m == NULL)
 
276
                        sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
 
277
                if (sm->m) {
 
278
                        wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP "
 
279
                                   "method (%d, %s)",
 
280
                                   sm->selectedMethod, sm->m->name);
 
281
                        if (reinit)
 
282
                                sm->eap_method_priv = sm->m->init_for_reauth(
 
283
                                        sm, sm->eap_method_priv);
 
284
                        else
 
285
                                sm->eap_method_priv = sm->m->init(sm);
 
286
                        if (sm->eap_method_priv == NULL) {
 
287
                                wpa_printf(MSG_DEBUG, "EAP: Failed to "
 
288
                                           "initialize EAP method %d",
 
289
                                           sm->selectedMethod);
 
290
                                sm->m = NULL;
 
291
                                sm->methodState = METHOD_NONE;
 
292
                                sm->selectedMethod = EAP_TYPE_NONE;
 
293
                        } else {
 
294
                                sm->methodState = METHOD_INIT;
 
295
                                return;
 
296
                        }
 
297
                }
 
298
        }
 
299
 
 
300
        free(sm->eapRespData);
 
301
        sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
 
302
}
 
303
 
 
304
 
 
305
SM_STATE(EAP, METHOD)
 
306
{
 
307
        u8 *eapReqData;
 
308
        size_t eapReqDataLen;
 
309
        struct eap_method_ret ret;
 
310
 
 
311
        SM_ENTRY(EAP, METHOD);
 
312
        if (sm->m == NULL) {
 
313
                wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
 
314
                return;
 
315
        }
 
316
 
 
317
        eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
 
318
 
 
319
        /* Get ignore, methodState, decision, allowNotifications, and
 
320
         * eapRespData. */
 
321
        memset(&ret, 0, sizeof(ret));
 
322
        ret.ignore = sm->ignore;
 
323
        ret.methodState = sm->methodState;
 
324
        ret.decision = sm->decision;
 
325
        ret.allowNotifications = sm->allowNotifications;
 
326
        free(sm->eapRespData);
 
327
        sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
 
328
                                         eapReqData, eapReqDataLen,
 
329
                                         &sm->eapRespDataLen);
 
330
        wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
 
331
                   "methodState=%s decision=%s",
 
332
                   ret.ignore ? "TRUE" : "FALSE",
 
333
                   eap_sm_method_state_txt(ret.methodState),
 
334
                   eap_sm_decision_txt(ret.decision));
 
335
 
 
336
        sm->ignore = ret.ignore;
 
337
        if (sm->ignore)
 
338
                return;
 
339
        sm->methodState = ret.methodState;
 
340
        sm->decision = ret.decision;
 
341
        sm->allowNotifications = ret.allowNotifications;
 
342
 
 
343
        if (sm->m->isKeyAvailable && sm->m->getKey &&
 
344
            sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
 
345
                free(sm->eapKeyData);
 
346
                sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
 
347
                                               &sm->eapKeyDataLen);
 
348
        }
 
349
}
 
350
 
 
351
 
 
352
SM_STATE(EAP, SEND_RESPONSE)
 
353
{
 
354
        SM_ENTRY(EAP, SEND_RESPONSE);
 
355
        free(sm->lastRespData);
 
356
        if (sm->eapRespData) {
 
357
                if (sm->workaround)
 
358
                        memcpy(sm->last_md5, sm->req_md5, 16);
 
359
                sm->lastId = sm->reqId;
 
360
                sm->lastRespData = malloc(sm->eapRespDataLen);
 
361
                if (sm->lastRespData) {
 
362
                        memcpy(sm->lastRespData, sm->eapRespData,
 
363
                               sm->eapRespDataLen);
 
364
                        sm->lastRespDataLen = sm->eapRespDataLen;
 
365
                }
 
366
                eapol_set_bool(sm, EAPOL_eapResp, TRUE);
 
367
        } else
 
368
                sm->lastRespData = NULL;
 
369
        eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 
370
        eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
 
371
}
 
372
 
 
373
 
 
374
SM_STATE(EAP, DISCARD)
 
375
{
 
376
        SM_ENTRY(EAP, DISCARD);
 
377
        eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 
378
        eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
 
379
}
 
380
 
 
381
 
 
382
SM_STATE(EAP, IDENTITY)
 
383
{
 
384
        u8 *eapReqData;
 
385
        size_t eapReqDataLen;
 
386
 
 
387
        SM_ENTRY(EAP, IDENTITY);
 
388
        eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
 
389
        eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
 
390
        free(sm->eapRespData);
 
391
        sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
 
392
                                               &sm->eapRespDataLen, 0);
 
393
}
 
394
 
 
395
 
 
396
SM_STATE(EAP, NOTIFICATION)
 
397
{
 
398
        u8 *eapReqData;
 
399
        size_t eapReqDataLen;
 
400
 
 
401
        SM_ENTRY(EAP, NOTIFICATION);
 
402
        eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
 
403
        eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
 
404
        free(sm->eapRespData);
 
405
        sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
 
406
                                             &sm->eapRespDataLen);
 
407
}
 
408
 
 
409
 
 
410
SM_STATE(EAP, RETRANSMIT)
 
411
{
 
412
        SM_ENTRY(EAP, RETRANSMIT);
 
413
        free(sm->eapRespData);
 
414
        if (sm->lastRespData) {
 
415
                sm->eapRespData = malloc(sm->lastRespDataLen);
 
416
                if (sm->eapRespData) {
 
417
                        memcpy(sm->eapRespData, sm->lastRespData,
 
418
                               sm->lastRespDataLen);
 
419
                        sm->eapRespDataLen = sm->lastRespDataLen;
 
420
                }
 
421
        } else
 
422
                sm->eapRespData = NULL;
 
423
}
 
424
 
 
425
 
 
426
SM_STATE(EAP, SUCCESS)
 
427
{
 
428
        SM_ENTRY(EAP, SUCCESS);
 
429
        if (sm->eapKeyData != NULL)
 
430
                sm->eapKeyAvailable = TRUE;
 
431
        eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
 
432
        /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
 
433
         * this seems to be required to avoid processing the same request
 
434
         * twice when state machine is initialized. */
 
435
        eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 
436
        /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here, but
 
437
         * this seems to be required to get EAPOL Supplicant backend state
 
438
         * machine into SUCCESS state. In addition, either eapResp or eapNoResp
 
439
         * is required to be set after processing the received EAP frame. */
 
440
        eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
 
441
}
 
442
 
 
443
 
 
444
SM_STATE(EAP, FAILURE)
 
445
{
 
446
        SM_ENTRY(EAP, FAILURE);
 
447
        eapol_set_bool(sm, EAPOL_eapFail, TRUE);
 
448
        /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
 
449
         * this seems to be required to avoid processing the same request
 
450
         * twice when state machine is initialized. */
 
451
        eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 
452
        /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here.
 
453
         * However, either eapResp or eapNoResp is required to be set after
 
454
         * processing the received EAP frame. */
 
455
        eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
 
456
}
 
457
 
 
458
 
 
459
static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
 
460
{
 
461
        /* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
 
462
         * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
 
463
         * draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
 
464
         * Accept this kind of Id if EAP workarounds are enabled. These are
 
465
         * unauthenticated plaintext messages, so this should have minimal
 
466
         * security implications (bit easier to fake EAP-Success/Failure). */
 
467
        if (sm->workaround && reqId == ((lastId + 1) & 0xff)) {
 
468
                wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
 
469
                           "identifier field in EAP Success: "
 
470
                           "reqId=%d lastId=%d (these are supposed to be "
 
471
                           "same)", reqId, lastId);
 
472
                return 1;
 
473
        }
 
474
        return 0;
 
475
}
 
476
 
 
477
 
 
478
SM_STEP(EAP)
 
479
{
 
480
        int duplicate;
 
481
 
 
482
        if (eapol_get_bool(sm, EAPOL_eapRestart) &&
 
483
            eapol_get_bool(sm, EAPOL_portEnabled))
 
484
                SM_ENTER_GLOBAL(EAP, INITIALIZE);
 
485
        else if (!eapol_get_bool(sm, EAPOL_portEnabled))
 
486
                SM_ENTER_GLOBAL(EAP, DISABLED);
 
487
        else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
 
488
                if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
 
489
                        wpa_printf(MSG_DEBUG, "EAP: more than %d "
 
490
                                   "authentication rounds - abort",
 
491
                                   EAP_MAX_AUTH_ROUNDS);
 
492
                        sm->num_rounds++;
 
493
                        SM_ENTER_GLOBAL(EAP, FAILURE);
 
494
                }
 
495
        } else switch (sm->EAP_state) {
 
496
        case EAP_INITIALIZE:
 
497
                SM_ENTER(EAP, IDLE);
 
498
                break;
 
499
        case EAP_DISABLED:
 
500
                if (eapol_get_bool(sm, EAPOL_portEnabled))
 
501
                        SM_ENTER(EAP, INITIALIZE);
 
502
                break;
 
503
        case EAP_IDLE:
 
504
                if (eapol_get_bool(sm, EAPOL_eapReq))
 
505
                        SM_ENTER(EAP, RECEIVED);
 
506
                else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
 
507
                          sm->decision != DECISION_FAIL) ||
 
508
                         (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
 
509
                          sm->decision == DECISION_UNCOND_SUCC))
 
510
                        SM_ENTER(EAP, SUCCESS);
 
511
                else if (eapol_get_bool(sm, EAPOL_altReject) ||
 
512
                         (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
 
513
                          sm->decision != DECISION_UNCOND_SUCC) ||
 
514
                         (eapol_get_bool(sm, EAPOL_altAccept) &&
 
515
                          sm->methodState != METHOD_CONT &&
 
516
                          sm->decision == DECISION_FAIL))
 
517
                        SM_ENTER(EAP, FAILURE);
 
518
                else if (sm->selectedMethod == EAP_TYPE_LEAP &&
 
519
                         sm->leap_done && sm->decision != DECISION_FAIL &&
 
520
                         sm->methodState == METHOD_DONE)
 
521
                        SM_ENTER(EAP, SUCCESS);
 
522
                else if (sm->selectedMethod == EAP_TYPE_PEAP &&
 
523
                         sm->peap_done && sm->decision != DECISION_FAIL &&
 
524
                         sm->methodState == METHOD_DONE)
 
525
                        SM_ENTER(EAP, SUCCESS);
 
526
                break;
 
527
        case EAP_RECEIVED:
 
528
                duplicate = sm->reqId == sm->lastId;
 
529
                if (sm->workaround && duplicate &&
 
530
                    memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
 
531
                        /* draft-ietf-eap-statemachine-05.txt uses
 
532
                         * (reqId == lastId) as the only verification for
 
533
                         * duplicate EAP requests. However, this misses cases
 
534
                         * where the AS is incorrectly using the same id again;
 
535
                         * and unfortunately, such implementations exist. Use
 
536
                         * MD5 hash as an extra verification for the packets
 
537
                         * being duplicate to workaround these issues. */
 
538
                        wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
 
539
                                   " but EAP packets were not identical");
 
540
                        wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
 
541
                                   "is not a duplicate packet");
 
542
                        duplicate = 0;
 
543
                }
 
544
 
 
545
                if (sm->rxSuccess &&
 
546
                    (sm->reqId == sm->lastId ||
 
547
                     eap_success_workaround(sm, sm->reqId, sm->lastId)) &&
 
548
                    sm->decision != DECISION_FAIL)
 
549
                        SM_ENTER(EAP, SUCCESS);
 
550
                else if (sm->methodState != METHOD_CONT &&
 
551
                         ((sm->rxFailure &&
 
552
                           sm->decision != DECISION_UNCOND_SUCC) ||
 
553
                          (sm->rxSuccess && sm->decision == DECISION_FAIL)) &&
 
554
                         (sm->reqId == sm->lastId ||
 
555
                          eap_success_workaround(sm, sm->reqId, sm->lastId)))
 
556
                        SM_ENTER(EAP, FAILURE);
 
557
                else if (sm->rxReq && duplicate)
 
558
                        SM_ENTER(EAP, RETRANSMIT);
 
559
                else if (sm->rxReq && !duplicate &&
 
560
                         sm->reqMethod == EAP_TYPE_NOTIFICATION &&
 
561
                         sm->allowNotifications)
 
562
                        SM_ENTER(EAP, NOTIFICATION);
 
563
                else if (sm->rxReq && !duplicate &&
 
564
                         sm->selectedMethod == EAP_TYPE_NONE &&
 
565
                         sm->reqMethod == EAP_TYPE_IDENTITY)
 
566
                        SM_ENTER(EAP, IDENTITY);
 
567
                else if (sm->rxReq && !duplicate &&
 
568
                         sm->selectedMethod == EAP_TYPE_NONE &&
 
569
                         sm->reqMethod != EAP_TYPE_IDENTITY &&
 
570
                         sm->reqMethod != EAP_TYPE_NOTIFICATION)
 
571
                        SM_ENTER(EAP, GET_METHOD);
 
572
                else if (sm->rxReq && !duplicate &&
 
573
                         sm->reqMethod == sm->selectedMethod &&
 
574
                         sm->methodState != METHOD_DONE)
 
575
                        SM_ENTER(EAP, METHOD);
 
576
                else if (sm->selectedMethod == EAP_TYPE_LEAP &&
 
577
                         (sm->rxSuccess || sm->rxResp))
 
578
                        SM_ENTER(EAP, METHOD);
 
579
                else
 
580
                        SM_ENTER(EAP, DISCARD);
 
581
                break;
 
582
        case EAP_GET_METHOD:
 
583
                if (sm->selectedMethod == sm->reqMethod)
 
584
                        SM_ENTER(EAP, METHOD);
 
585
                else
 
586
                        SM_ENTER(EAP, SEND_RESPONSE);
 
587
                break;
 
588
        case EAP_METHOD:
 
589
                if (sm->ignore)
 
590
                        SM_ENTER(EAP, DISCARD);
 
591
                else
 
592
                        SM_ENTER(EAP, SEND_RESPONSE);
 
593
                break;
 
594
        case EAP_SEND_RESPONSE:
 
595
                SM_ENTER(EAP, IDLE);
 
596
                break;
 
597
        case EAP_DISCARD:
 
598
                SM_ENTER(EAP, IDLE);
 
599
                break;
 
600
        case EAP_IDENTITY:
 
601
                SM_ENTER(EAP, SEND_RESPONSE);
 
602
                break;
 
603
        case EAP_NOTIFICATION:
 
604
                SM_ENTER(EAP, SEND_RESPONSE);
 
605
                break;
 
606
        case EAP_RETRANSMIT:
 
607
                SM_ENTER(EAP, SEND_RESPONSE);
 
608
                break;
 
609
        case EAP_SUCCESS:
 
610
                break;
 
611
        case EAP_FAILURE:
 
612
                break;
 
613
        }
 
614
}
 
615
 
 
616
 
 
617
static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
 
618
{
 
619
        struct wpa_ssid *config = eap_get_config(sm);
 
620
        int i;
 
621
 
 
622
        if (!wpa_config_allowed_eap_method(config, method))
 
623
                return FALSE;
 
624
        for (i = 0; i < NUM_EAP_METHODS; i++) {
 
625
                if (eap_methods[i]->method == method)
 
626
                        return TRUE;
 
627
        }
 
628
        return FALSE;
 
629
}
 
630
 
 
631
 
 
632
static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
 
633
{
 
634
        struct wpa_ssid *config = eap_get_config(sm);
 
635
        struct eap_hdr *resp;
 
636
        u8 *pos;
 
637
        int i, found = 0;
 
638
 
 
639
        wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
 
640
                   "allowed)", sm->reqMethod);
 
641
        *len = sizeof(struct eap_hdr) + 1;
 
642
        resp = malloc(*len + NUM_EAP_METHODS);
 
643
        if (resp == NULL)
 
644
                return NULL;
 
645
 
 
646
        resp->code = EAP_CODE_RESPONSE;
 
647
        resp->identifier = id;
 
648
        pos = (u8 *) (resp + 1);
 
649
        *pos++ = EAP_TYPE_NAK;
 
650
 
 
651
        for (i = 0; i < NUM_EAP_METHODS; i++) {
 
652
                if (wpa_config_allowed_eap_method(config,
 
653
                                                  eap_methods[i]->method)) {
 
654
                        *pos++ = eap_methods[i]->method;
 
655
                        (*len)++;
 
656
                        found++;
 
657
                }
 
658
        }
 
659
        if (!found) {
 
660
                *pos = EAP_TYPE_NONE;
 
661
                (*len)++;
 
662
        }
 
663
        wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",
 
664
                    ((u8 *) (resp + 1)) + 1, found);
 
665
 
 
666
        resp->length = host_to_be16(*len);
 
667
 
 
668
        return (u8 *) resp;
 
669
}
 
670
 
 
671
 
 
672
static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
 
673
{
 
674
        struct eap_hdr *hdr = (struct eap_hdr *) req;
 
675
        u8 *pos = (u8 *) (hdr + 1);
 
676
        pos++;
 
677
        /* TODO: could save displayable message so that it can be shown to the
 
678
         * user in case of interaction is required */
 
679
        wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
 
680
                          pos, be_to_host16(hdr->length) - 5);
 
681
}
 
682
 
 
683
 
 
684
u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
 
685
                         int encrypted)
 
686
{
 
687
        struct wpa_ssid *config = eap_get_config(sm);
 
688
        struct eap_hdr *resp;
 
689
        u8 *pos;
 
690
        const u8 *identity;
 
691
        size_t identity_len;
 
692
 
 
693
        if (config == NULL) {
 
694
                wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
 
695
                           "was not available");
 
696
                return NULL;
 
697
        }
 
698
 
 
699
        if (sm->m && sm->m->get_identity &&
 
700
            (identity = sm->m->get_identity(sm, sm->eap_method_priv,
 
701
                                            &identity_len)) != NULL) {
 
702
                wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
 
703
                                  "identity", identity, identity_len);
 
704
        } else if (!encrypted && config->anonymous_identity) {
 
705
                identity = config->anonymous_identity;
 
706
                identity_len = config->anonymous_identity_len;
 
707
                wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
 
708
                                  identity, identity_len);
 
709
        } else {
 
710
                identity = config->identity;
 
711
                identity_len = config->identity_len;
 
712
                wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
 
713
                                  identity, identity_len);
 
714
        }
 
715
 
 
716
        if (identity == NULL) {
 
717
                wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
 
718
                           "configuration was not available");
 
719
                eap_sm_request_identity(sm, config);
 
720
                return NULL;
 
721
        }
 
722
 
 
723
 
 
724
        *len = sizeof(struct eap_hdr) + 1 + identity_len;
 
725
        resp = malloc(*len);
 
726
        if (resp == NULL)
 
727
                return NULL;
 
728
 
 
729
        resp->code = EAP_CODE_RESPONSE;
 
730
        resp->identifier = id;
 
731
        resp->length = host_to_be16(*len);
 
732
        pos = (u8 *) (resp + 1);
 
733
        *pos++ = EAP_TYPE_IDENTITY;
 
734
        memcpy(pos, identity, identity_len);
 
735
 
 
736
        return (u8 *) resp;
 
737
}
 
738
 
 
739
 
 
740
static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
 
741
{
 
742
        struct eap_hdr *hdr = (struct eap_hdr *) req;
 
743
        u8 *pos = (u8 *) (hdr + 1);
 
744
        pos++;
 
745
        /* TODO: log the Notification Request and make it available for UI */
 
746
        wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
 
747
                          pos, be_to_host16(hdr->length) - 5);
 
748
}
 
749
 
 
750
 
 
751
static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
 
752
{
 
753
        struct eap_hdr *resp;
 
754
        u8 *pos;
 
755
 
 
756
        wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
 
757
        *len = sizeof(struct eap_hdr) + 1;
 
758
        resp = malloc(*len);
 
759
        if (resp == NULL)
 
760
                return NULL;
 
761
 
 
762
        resp->code = EAP_CODE_RESPONSE;
 
763
        resp->identifier = id;
 
764
        resp->length = host_to_be16(*len);
 
765
        pos = (u8 *) (resp + 1);
 
766
        *pos = EAP_TYPE_NOTIFICATION;
 
767
 
 
768
        return (u8 *) resp;
 
769
}
 
770
 
 
771
 
 
772
static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
 
773
{
 
774
        struct eap_hdr *hdr;
 
775
        size_t plen;
 
776
        MD5_CTX context;
 
777
 
 
778
        sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
 
779
        sm->reqId = 0;
 
780
        sm->reqMethod = EAP_TYPE_NONE;
 
781
 
 
782
        if (req == NULL || len < sizeof(*hdr))
 
783
                return;
 
784
 
 
785
        hdr = (struct eap_hdr *) req;
 
786
        plen = be_to_host16(hdr->length);
 
787
        if (plen > len) {
 
788
                wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
 
789
                           "(len=%lu plen=%lu)",
 
790
                           (unsigned long) len, (unsigned long) plen);
 
791
                return;
 
792
        }
 
793
 
 
794
        sm->reqId = hdr->identifier;
 
795
 
 
796
        if (sm->workaround) {
 
797
                MD5Init(&context);
 
798
                MD5Update(&context, req, len);
 
799
                MD5Final(sm->req_md5, &context);
 
800
        }
 
801
 
 
802
        switch (hdr->code) {
 
803
        case EAP_CODE_REQUEST:
 
804
                sm->rxReq = TRUE;
 
805
                if (plen > sizeof(*hdr))
 
806
                        sm->reqMethod = *((u8 *) (hdr + 1));
 
807
                wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
 
808
                           "id=%d", sm->reqMethod, sm->reqId);
 
809
                break;
 
810
        case EAP_CODE_RESPONSE:
 
811
                if (sm->selectedMethod == EAP_TYPE_LEAP) {
 
812
                        sm->rxResp = TRUE;
 
813
                        if (plen > sizeof(*hdr))
 
814
                                sm->reqMethod = *((u8 *) (hdr + 1));
 
815
                        wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
 
816
                                   "LEAP method=%d id=%d",
 
817
                                   sm->reqMethod, sm->reqId);
 
818
                        break;
 
819
                }
 
820
                wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
 
821
                break;
 
822
        case EAP_CODE_SUCCESS:
 
823
                wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
 
824
                sm->rxSuccess = TRUE;
 
825
                break;
 
826
        case EAP_CODE_FAILURE:
 
827
                wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
 
828
                sm->rxFailure = TRUE;
 
829
                break;
 
830
        default:
 
831
                wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
 
832
                           "code %d", hdr->code);
 
833
                break;
 
834
        }
 
835
}
 
836
 
 
837
 
 
838
struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
 
839
                           void *msg_ctx)
 
840
{
 
841
        struct eap_sm *sm;
 
842
 
 
843
        sm = malloc(sizeof(*sm));
 
844
        if (sm == NULL)
 
845
                return NULL;
 
846
        memset(sm, 0, sizeof(*sm));
 
847
        sm->eapol_ctx = eapol_ctx;
 
848
        sm->eapol_cb = eapol_cb;
 
849
        sm->msg_ctx = msg_ctx;
 
850
        sm->ClientTimeout = 60;
 
851
 
 
852
        sm->ssl_ctx = tls_init();
 
853
        if (sm->ssl_ctx == NULL) {
 
854
                wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
 
855
                           "context.");
 
856
                free(sm);
 
857
                return NULL;
 
858
        }
 
859
 
 
860
        return sm;
 
861
}
 
862
 
 
863
 
 
864
void eap_sm_deinit(struct eap_sm *sm)
 
865
{
 
866
        if (sm == NULL)
 
867
                return;
 
868
        eap_deinit_prev_method(sm, "EAP deinit");
 
869
        free(sm->lastRespData);
 
870
        free(sm->eapRespData);
 
871
        free(sm->eapKeyData);
 
872
        tls_deinit(sm->ssl_ctx);
 
873
        free(sm);
 
874
}
 
875
 
 
876
 
 
877
int eap_sm_step(struct eap_sm *sm)
 
878
{
 
879
        int res = 0;
 
880
        do {
 
881
                sm->changed = FALSE;
 
882
                SM_STEP_RUN(EAP);
 
883
                if (sm->changed)
 
884
                        res = 1;
 
885
        } while (sm->changed);
 
886
        return res;
 
887
}
 
888
 
 
889
 
 
890
void eap_sm_abort(struct eap_sm *sm)
 
891
{
 
892
        /* release system resources that may have been allocated for the
 
893
         * authentication session */
 
894
        free(sm->eapRespData);
 
895
        sm->eapRespData = NULL;
 
896
        free(sm->eapKeyData);
 
897
        sm->eapKeyData = NULL;
 
898
}
 
899
 
 
900
 
 
901
static const char * eap_sm_state_txt(int state)
 
902
{
 
903
        switch (state) {
 
904
        case EAP_INITIALIZE:
 
905
                return "INITIALIZE";
 
906
        case EAP_DISABLED:
 
907
                return "DISABLED";
 
908
        case EAP_IDLE:
 
909
                return "IDLE";
 
910
        case EAP_RECEIVED:
 
911
                return "RECEIVED";
 
912
        case EAP_GET_METHOD:
 
913
                return "GET_METHOD";
 
914
        case EAP_METHOD:
 
915
                return "METHOD";
 
916
        case EAP_SEND_RESPONSE:
 
917
                return "SEND_RESPONSE";
 
918
        case EAP_DISCARD:
 
919
                return "DISCARD";
 
920
        case EAP_IDENTITY:
 
921
                return "IDENTITY";
 
922
        case EAP_NOTIFICATION:
 
923
                return "NOTIFICATION";
 
924
        case EAP_RETRANSMIT:
 
925
                return "RETRANSMIT";
 
926
        case EAP_SUCCESS:
 
927
                return "SUCCESS";
 
928
        case EAP_FAILURE:
 
929
                return "FAILURE";
 
930
        default:
 
931
                return "UNKNOWN";
 
932
        }
 
933
}
 
934
 
 
935
 
 
936
static const char * eap_sm_method_state_txt(int state)
 
937
{
 
938
        switch (state) {
 
939
        case METHOD_NONE:
 
940
                return "NONE";
 
941
        case METHOD_INIT:
 
942
                return "INIT";
 
943
        case METHOD_CONT:
 
944
                return "CONT";
 
945
        case METHOD_MAY_CONT:
 
946
                return "MAY_CONT";
 
947
        case METHOD_DONE:
 
948
                return "DONE";
 
949
        default:
 
950
                return "UNKNOWN";
 
951
        }
 
952
}
 
953
 
 
954
 
 
955
static const char * eap_sm_decision_txt(int decision)
 
956
{
 
957
        switch (decision) {
 
958
        case DECISION_FAIL:
 
959
                return "FAIL";
 
960
        case DECISION_COND_SUCC:
 
961
                return "COND_SUCC";
 
962
        case DECISION_UNCOND_SUCC:
 
963
                return "UNCOND_SUCC";
 
964
        default:
 
965
                return "UNKNOWN";
 
966
        }
 
967
}
 
968
 
 
969
 
 
970
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
 
971
{
 
972
        int len;
 
973
 
 
974
        if (sm == NULL)
 
975
                return 0;
 
976
 
 
977
        len = snprintf(buf, buflen,
 
978
                       "EAP state=%s\n",
 
979
                       eap_sm_state_txt(sm->EAP_state));
 
980
 
 
981
        if (sm->selectedMethod != EAP_TYPE_NONE) {
 
982
                const char *name;
 
983
                if (sm->m) {
 
984
                        name = sm->m->name;
 
985
                } else {
 
986
                        const struct eap_method *m =
 
987
                                eap_sm_get_eap_methods(sm->selectedMethod);
 
988
                        if (m)
 
989
                                name = m->name;
 
990
                        else
 
991
                                name = "?";
 
992
                }
 
993
                len += snprintf(buf + len, buflen - len,
 
994
                                "selectedMethod=%d (EAP-%s)\n",
 
995
                                sm->selectedMethod, name);
 
996
 
 
997
                if (sm->m && sm->m->get_status) {
 
998
                        len += sm->m->get_status(sm, sm->eap_method_priv,
 
999
                                                 buf + len, buflen - len,
 
1000
                                                 verbose);
 
1001
                }
 
1002
        }
 
1003
 
 
1004
        if (verbose) {
 
1005
                len += snprintf(buf + len, buflen - len,
 
1006
                                "reqMethod=%d\n"
 
1007
                                "methodState=%s\n"
 
1008
                                "decision=%s\n"
 
1009
                                "ClientTimeout=%d\n",
 
1010
                                sm->reqMethod,
 
1011
                                eap_sm_method_state_txt(sm->methodState),
 
1012
                                eap_sm_decision_txt(sm->decision),
 
1013
                                sm->ClientTimeout);
 
1014
        }
 
1015
 
 
1016
        return len;
 
1017
}
 
1018
 
 
1019
 
 
1020
typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP } eap_ctrl_req_type;
 
1021
 
 
1022
static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
 
1023
                           eap_ctrl_req_type type, char *msg, size_t msglen)
 
1024
{
 
1025
        char *buf;
 
1026
        size_t buflen;
 
1027
        int len;
 
1028
        char *field;
 
1029
        char *txt, *tmp;
 
1030
 
 
1031
        if (config == NULL || sm == NULL)
 
1032
                return;
 
1033
 
 
1034
        switch (type) {
 
1035
        case TYPE_IDENTITY:
 
1036
                field = "IDENTITY";
 
1037
                txt = "Identity";
 
1038
                config->pending_req_identity++;
 
1039
                break;
 
1040
        case TYPE_PASSWORD:
 
1041
                field = "PASSWORD";
 
1042
                txt = "Password";
 
1043
                config->pending_req_password++;
 
1044
                break;
 
1045
        case TYPE_OTP:
 
1046
                field = "OTP";
 
1047
                if (msg) {
 
1048
                        tmp = malloc(msglen + 3);
 
1049
                        if (tmp == NULL)
 
1050
                                return;
 
1051
                        tmp[0] = '[';
 
1052
                        memcpy(tmp + 1, msg, msglen);
 
1053
                        tmp[msglen + 1] = ']';
 
1054
                        tmp[msglen + 2] = '\0';
 
1055
                        txt = tmp;
 
1056
                        free(config->pending_req_otp);
 
1057
                        config->pending_req_otp = tmp;
 
1058
                        config->pending_req_otp_len = msglen + 3;
 
1059
                } else {
 
1060
                        if (config->pending_req_otp == NULL)
 
1061
                                return;
 
1062
                        txt = config->pending_req_otp;
 
1063
                }
 
1064
                break;
 
1065
        default:
 
1066
                return;
 
1067
        }
 
1068
 
 
1069
        buflen = 100 + strlen(txt) + config->ssid_len;
 
1070
        buf = malloc(buflen);
 
1071
        if (buf == NULL)
 
1072
                return;
 
1073
        len = snprintf(buf, buflen, "CTRL-REQ-%s-%d:%s needed for SSID ",
 
1074
                       field, config->id, txt);
 
1075
        if (config->ssid && buflen > len + config->ssid_len) {
 
1076
                memcpy(buf + len, config->ssid, config->ssid_len);
 
1077
                len += config->ssid_len;
 
1078
                buf[len] = '\0';
 
1079
        }
 
1080
        wpa_msg(sm->msg_ctx, MSG_INFO, buf);
 
1081
        free(buf);
 
1082
}
 
1083
 
 
1084
 
 
1085
void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
 
1086
{
 
1087
        eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
 
1088
}
 
1089
 
 
1090
 
 
1091
void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
 
1092
{
 
1093
        eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
 
1094
}
 
1095
 
 
1096
 
 
1097
void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
 
1098
                        char *msg, size_t msg_len)
 
1099
{
 
1100
        eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
 
1101
}
 
1102
 
 
1103
 
 
1104
void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
 
1105
{
 
1106
        struct wpa_ssid *config = eap_get_config(sm);
 
1107
 
 
1108
        if (config == NULL)
 
1109
                return;
 
1110
 
 
1111
        /* Re-send any pending requests for user data since a new control
 
1112
         * interface was added. This handles cases where the EAP authentication
 
1113
         * starts immediately after system startup when the user interface is
 
1114
         * not yet running. */
 
1115
        if (config->pending_req_identity)
 
1116
                eap_sm_request_identity(sm, config);
 
1117
        if (config->pending_req_password)
 
1118
                eap_sm_request_password(sm, config);
 
1119
        if (config->pending_req_otp)
 
1120
                eap_sm_request_otp(sm, config, NULL, 0);
 
1121
}
 
1122
 
 
1123
 
 
1124
u8 eap_get_type(const char *name)
 
1125
{
 
1126
        int i;
 
1127
        for (i = 0; i < NUM_EAP_METHODS; i++) {
 
1128
                if (strcmp(eap_methods[i]->name, name) == 0)
 
1129
                        return eap_methods[i]->method;
 
1130
        }
 
1131
        return EAP_TYPE_NONE;
 
1132
}
 
1133
 
 
1134
 
 
1135
static int eap_allowed_phase2_type(int type)
 
1136
{
 
1137
        return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
 
1138
                type != EAP_TYPE_FAST;
 
1139
}
 
1140
 
 
1141
 
 
1142
u8 eap_get_phase2_type(const char *name)
 
1143
{
 
1144
        u8 type = eap_get_type(name);
 
1145
        if (eap_allowed_phase2_type(type))
 
1146
                return type;
 
1147
        return EAP_TYPE_NONE;
 
1148
}
 
1149
 
 
1150
 
 
1151
u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
 
1152
{
 
1153
        u8 *buf, method;
 
1154
        int i;
 
1155
 
 
1156
        *count = 0;
 
1157
        buf = malloc(NUM_EAP_METHODS);
 
1158
        if (buf == NULL)
 
1159
                return NULL;
 
1160
 
 
1161
        for (i = 0; i < NUM_EAP_METHODS; i++) {
 
1162
                method = eap_methods[i]->method;
 
1163
                if (eap_allowed_phase2_type(method)) {
 
1164
                        if (method == EAP_TYPE_TLS && config &&
 
1165
                            config->private_key2 == NULL)
 
1166
                                continue;
 
1167
                        buf[*count] = method;
 
1168
                        (*count)++;
 
1169
                }
 
1170
        }
 
1171
 
 
1172
        return buf;
 
1173
}
 
1174
 
 
1175
 
 
1176
void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
 
1177
{
 
1178
        sm->fast_reauth = enabled;
 
1179
}
 
1180
 
 
1181
 
 
1182
void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
 
1183
{
 
1184
        sm->workaround = workaround;
 
1185
}
 
1186
 
 
1187
 
 
1188
struct wpa_ssid * eap_get_config(struct eap_sm *sm)
 
1189
{
 
1190
        return sm->eapol_cb->get_config(sm->eapol_ctx);
 
1191
}
 
1192
 
 
1193
 
 
1194
int eap_key_available(struct eap_sm *sm)
 
1195
{
 
1196
        return sm ? sm->eapKeyAvailable : 0;
 
1197
}
 
1198
 
 
1199
 
 
1200
void eap_notify_success(struct eap_sm *sm)
 
1201
{
 
1202
        if (sm) {
 
1203
                sm->decision = DECISION_COND_SUCC;
 
1204
                sm->EAP_state = EAP_SUCCESS;
 
1205
        }
 
1206
}
 
1207
 
 
1208
 
 
1209
u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
 
1210
{
 
1211
        if (sm == NULL || sm->eapKeyData == NULL) {
 
1212
                *len = 0;
 
1213
                return NULL;
 
1214
        }
 
1215
 
 
1216
        *len = sm->eapKeyDataLen;
 
1217
        return sm->eapKeyData;
 
1218
}
 
1219
 
 
1220
 
 
1221
u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
 
1222
{
 
1223
        u8 *resp;
 
1224
 
 
1225
        if (sm == NULL || sm->eapRespData == NULL) {
 
1226
                *len = 0;
 
1227
                return NULL;
 
1228
        }
 
1229
 
 
1230
        resp = sm->eapRespData;
 
1231
        *len = sm->eapRespDataLen;
 
1232
        sm->eapRespData = NULL;
 
1233
        sm->eapRespDataLen = 0;
 
1234
 
 
1235
        return resp;
 
1236
}
 
1237
 
 
1238
 
 
1239
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
 
1240
{
 
1241
        if (sm)
 
1242
                sm->scard_ctx = ctx;
 
1243
}