Add trunc and truncf.
[dragonfly.git] / contrib / hostapd-0.4.9 / eap.c
1 /*
2  * hostapd / EAP Standalone Authenticator state machine
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 <unistd.h>
18 #include <netinet/in.h>
19 #include <string.h>
20 #include <sys/socket.h>
21
22 #include "hostapd.h"
23 #include "eloop.h"
24 #include "sta_info.h"
25 #include "eap_i.h"
26
27 #define EAP_MAX_AUTH_ROUNDS 50
28
29 extern const struct eap_method eap_method_identity;
30 #ifdef EAP_MD5
31 extern const struct eap_method eap_method_md5;
32 #endif /* EAP_MD5 */
33 #ifdef EAP_TLS
34 extern const struct eap_method eap_method_tls;
35 #endif /* EAP_TLS */
36 #ifdef EAP_MSCHAPv2
37 extern const struct eap_method eap_method_mschapv2;
38 #endif /* EAP_MSCHAPv2 */
39 #ifdef EAP_PEAP
40 extern const struct eap_method eap_method_peap;
41 #endif /* EAP_PEAP */
42 #ifdef EAP_TLV
43 extern const struct eap_method eap_method_tlv;
44 #endif /* EAP_TLV */
45 #ifdef EAP_GTC
46 extern const struct eap_method eap_method_gtc;
47 #endif /* EAP_GTC */
48 #ifdef EAP_TTLS
49 extern const struct eap_method eap_method_ttls;
50 #endif /* EAP_TTLS */
51 #ifdef EAP_SIM
52 extern const struct eap_method eap_method_sim;
53 #endif /* EAP_SIM */
54 #ifdef EAP_PAX
55 extern const struct eap_method eap_method_pax;
56 #endif /* EAP_PAX */
57 #ifdef EAP_PSK
58 extern const struct eap_method eap_method_psk;
59 #endif /* EAP_PSK */
60
61 static const struct eap_method *eap_methods[] =
62 {
63         &eap_method_identity,
64 #ifdef EAP_MD5
65         &eap_method_md5,
66 #endif /* EAP_MD5 */
67 #ifdef EAP_TLS
68         &eap_method_tls,
69 #endif /* EAP_TLS */
70 #ifdef EAP_MSCHAPv2
71         &eap_method_mschapv2,
72 #endif /* EAP_MSCHAPv2 */
73 #ifdef EAP_PEAP
74         &eap_method_peap,
75 #endif /* EAP_PEAP */
76 #ifdef EAP_TTLS
77         &eap_method_ttls,
78 #endif /* EAP_TTLS */
79 #ifdef EAP_TLV
80         &eap_method_tlv,
81 #endif /* EAP_TLV */
82 #ifdef EAP_GTC
83         &eap_method_gtc,
84 #endif /* EAP_GTC */
85 #ifdef EAP_SIM
86         &eap_method_sim,
87 #endif /* EAP_SIM */
88 #ifdef EAP_PAX
89         &eap_method_pax,
90 #endif /* EAP_PAX */
91 #ifdef EAP_PSK
92         &eap_method_psk,
93 #endif /* EAP_PSK */
94 };
95 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
96
97
98 const struct eap_method * eap_sm_get_eap_methods(int method)
99 {
100         int i;
101         for (i = 0; i < NUM_EAP_METHODS; i++) {
102                 if (eap_methods[i]->method == method)
103                         return eap_methods[i];
104         }
105         return NULL;
106 }
107
108 static void eap_user_free(struct eap_user *user);
109
110
111 /* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
112
113 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
114                                    int eapSRTT, int eapRTTVAR,
115                                    int methodTimeout);
116 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
117 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
118 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
119 static int eap_sm_nextId(struct eap_sm *sm, int id);
120 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
121 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
122 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
123 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
124
125
126 /* Definitions for clarifying state machine implementation */
127 #define SM_STATE(machine, state) \
128 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
129         int global)
130
131 #define SM_ENTRY(machine, state) \
132 if (!global || sm->machine ## _state != machine ## _ ## state) { \
133         sm->changed = TRUE; \
134         wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
135 } \
136 sm->machine ## _state = machine ## _ ## state;
137
138 #define SM_ENTER(machine, state) \
139 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
140 #define SM_ENTER_GLOBAL(machine, state) \
141 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
142
143 #define SM_STEP(machine) \
144 static void sm_ ## machine ## _Step(struct eap_sm *sm)
145
146 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
147
148
149 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
150 {
151         return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
152 }
153
154
155 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
156                            Boolean value)
157 {
158         sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
159 }
160
161
162 static void eapol_set_eapReqData(struct eap_sm *sm,
163                                  const u8 *eapReqData, size_t eapReqDataLen)
164 {
165         wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
166                     sm->eapReqData, sm->eapReqDataLen);
167         sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
168 }
169
170
171 static void eapol_set_eapKeyData(struct eap_sm *sm,
172                                  const u8 *eapKeyData, size_t eapKeyDataLen)
173 {
174         wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
175                     sm->eapKeyData, sm->eapKeyDataLen);
176         sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
177 }
178
179
180 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
181                  int phase2)
182 {
183         struct eap_user *user;
184
185         if (sm == NULL || sm->eapol_cb == NULL ||
186             sm->eapol_cb->get_eap_user == NULL)
187                 return -1;
188
189         eap_user_free(sm->user);
190         sm->user = NULL;
191
192         user = malloc(sizeof(*user));
193         if (user == NULL)
194             return -1;
195         memset(user, 0, sizeof(*user));
196
197         if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
198                                        identity_len, phase2, user) != 0) {
199                 eap_user_free(user);
200                 return -1;
201         }
202
203         sm->user = user;
204         sm->user_eap_method_index = 0;
205
206         return 0;
207 }
208
209
210 SM_STATE(EAP, DISABLED)
211 {
212         SM_ENTRY(EAP, DISABLED);
213         sm->num_rounds = 0;
214 }
215
216
217 SM_STATE(EAP, INITIALIZE)
218 {
219         SM_ENTRY(EAP, INITIALIZE);
220
221         sm->currentId = -1;
222         eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
223         eapol_set_bool(sm, EAPOL_eapFail, FALSE);
224         eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
225         free(sm->eapKeyData);
226         sm->eapKeyData = NULL;
227         sm->eapKeyDataLen = 0;
228         /* eapKeyAvailable = FALSE */
229         eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
230
231         /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
232          * method state needs to be reseted here so that it does not remain in
233          * success state when re-authentication starts. */
234         if (sm->m && sm->eap_method_priv) {
235                 sm->m->reset(sm, sm->eap_method_priv);
236                 sm->eap_method_priv = NULL;
237         }
238         sm->m = NULL;
239         sm->user_eap_method_index = 0;
240
241         if (sm->backend_auth) {
242                 sm->currentMethod = EAP_TYPE_NONE;
243                 /* parse rxResp, respId, respMethod */
244                 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
245                 if (sm->rxResp) {
246                         sm->currentId = sm->respId;
247                 }
248         }
249         sm->num_rounds = 0;
250 }
251
252
253 SM_STATE(EAP, PICK_UP_METHOD)
254 {
255         SM_ENTRY(EAP, PICK_UP_METHOD);
256
257         if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
258                 sm->currentMethod = sm->respMethod;
259                 if (sm->m && sm->eap_method_priv) {
260                         sm->m->reset(sm, sm->eap_method_priv);
261                         sm->eap_method_priv = NULL;
262                 }
263                 sm->m = eap_sm_get_eap_methods(sm->currentMethod);
264                 if (sm->m && sm->m->initPickUp) {
265                         sm->eap_method_priv = sm->m->initPickUp(sm);
266                         if (sm->eap_method_priv == NULL) {
267                                 wpa_printf(MSG_DEBUG, "EAP: Failed to "
268                                            "initialize EAP method %d",
269                                            sm->currentMethod);
270                                 sm->m = NULL;
271                                 sm->currentMethod = EAP_TYPE_NONE;
272                         }
273                 } else {
274                         sm->m = NULL;
275                         sm->currentMethod = EAP_TYPE_NONE;
276                 }
277         }
278 }
279
280
281 SM_STATE(EAP, IDLE)
282 {
283         SM_ENTRY(EAP, IDLE);
284
285         sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
286                                                    sm->eapSRTT, sm->eapRTTVAR,
287                                                    sm->methodTimeout);
288 }
289
290
291 SM_STATE(EAP, RETRANSMIT)
292 {
293         SM_ENTRY(EAP, RETRANSMIT);
294
295         /* TODO: Is this needed since EAPOL state machines take care of
296          * retransmit? */
297 }
298
299
300 SM_STATE(EAP, RECEIVED)
301 {
302         SM_ENTRY(EAP, RECEIVED);
303
304         /* parse rxResp, respId, respMethod */
305         eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
306         sm->num_rounds++;
307 }
308
309
310 SM_STATE(EAP, DISCARD)
311 {
312         SM_ENTRY(EAP, DISCARD);
313         eapol_set_bool(sm, EAPOL_eapResp, FALSE);
314         eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
315 }
316
317
318 SM_STATE(EAP, SEND_REQUEST)
319 {
320         SM_ENTRY(EAP, SEND_REQUEST);
321
322         sm->retransCount = 0;
323         if (sm->eapReqData) {
324                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
325                 free(sm->lastReqData);
326                 sm->lastReqData = sm->eapReqData;
327                 sm->lastReqDataLen = sm->eapReqDataLen;
328                 sm->eapReqData = NULL;
329                 sm->eapReqDataLen = 0;
330                 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
331                 eapol_set_bool(sm, EAPOL_eapReq, TRUE);
332         } else {
333                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
334                 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
335                 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
336                 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
337         }
338 }
339
340
341 SM_STATE(EAP, INTEGRITY_CHECK)
342 {
343         SM_ENTRY(EAP, INTEGRITY_CHECK);
344
345         if (sm->m->check) {
346                 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
347                                           sm->eapRespData, sm->eapRespDataLen);
348         }
349 }
350
351
352 SM_STATE(EAP, METHOD_REQUEST)
353 {
354         SM_ENTRY(EAP, METHOD_REQUEST);
355
356         if (sm->m == NULL) {
357                 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
358                 return;
359         }
360
361         sm->currentId = eap_sm_nextId(sm, sm->currentId);
362         wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
363                    sm->currentId);
364         sm->lastId = sm->currentId;
365         free(sm->eapReqData);
366         sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
367                                          sm->currentId, &sm->eapReqDataLen);
368         if (sm->m->getTimeout)
369                 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
370         else
371                 sm->methodTimeout = 0;
372 }
373
374
375 SM_STATE(EAP, METHOD_RESPONSE)
376 {
377         SM_ENTRY(EAP, METHOD_RESPONSE);
378
379         sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
380                        sm->eapRespDataLen);
381         if (sm->m->isDone(sm, sm->eap_method_priv)) {
382                 eap_sm_Policy_update(sm, NULL, 0);
383                 free(sm->eapKeyData);
384                 if (sm->m->getKey) {
385                         sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
386                                                        &sm->eapKeyDataLen);
387                 } else {
388                         sm->eapKeyData = NULL;
389                         sm->eapKeyDataLen = 0;
390                 }
391                 sm->methodState = METHOD_END;
392         } else {
393                 sm->methodState = METHOD_CONTINUE;
394         }
395 }
396
397
398 SM_STATE(EAP, PROPOSE_METHOD)
399 {
400         SM_ENTRY(EAP, PROPOSE_METHOD);
401
402         sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
403         if (sm->m && sm->eap_method_priv) {
404                 sm->m->reset(sm, sm->eap_method_priv);
405                 sm->eap_method_priv = NULL;
406         }
407         sm->m = eap_sm_get_eap_methods(sm->currentMethod);
408         if (sm->m) {
409                 sm->eap_method_priv = sm->m->init(sm);
410                 if (sm->eap_method_priv == NULL) {
411                         wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
412                                    "method %d", sm->currentMethod);
413                         sm->m = NULL;
414                         sm->currentMethod = EAP_TYPE_NONE;
415                 }
416         }
417         if (sm->currentMethod == EAP_TYPE_IDENTITY ||
418             sm->currentMethod == EAP_TYPE_NOTIFICATION)
419                 sm->methodState = METHOD_CONTINUE;
420         else
421                 sm->methodState = METHOD_PROPOSED;
422 }
423
424
425 SM_STATE(EAP, NAK)
426 {
427         struct eap_hdr *nak;
428         size_t len = 0;
429         u8 *pos, *nak_list = NULL;
430
431         SM_ENTRY(EAP, NAK);
432
433         if (sm->eap_method_priv) {
434                 sm->m->reset(sm, sm->eap_method_priv);
435                 sm->eap_method_priv = NULL;
436         }
437         sm->m = NULL;
438
439         nak = (struct eap_hdr *) sm->eapRespData;
440         if (nak && sm->eapRespDataLen > sizeof(*nak)) {
441                 len = ntohs(nak->length);
442                 if (len > sm->eapRespDataLen)
443                         len = sm->eapRespDataLen;
444                 pos = (u8 *) (nak + 1);
445                 len -= sizeof(*nak);
446                 if (*pos == EAP_TYPE_NAK) {
447                         pos++;
448                         len--;
449                         nak_list = pos;
450                 }
451         }
452         eap_sm_Policy_update(sm, nak_list, len);
453 }
454
455
456 SM_STATE(EAP, SELECT_ACTION)
457 {
458         SM_ENTRY(EAP, SELECT_ACTION);
459
460         sm->decision = eap_sm_Policy_getDecision(sm);
461 }
462
463
464 SM_STATE(EAP, TIMEOUT_FAILURE)
465 {
466         SM_ENTRY(EAP, TIMEOUT_FAILURE);
467
468         eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
469 }
470
471
472 SM_STATE(EAP, FAILURE)
473 {
474         SM_ENTRY(EAP, FAILURE);
475
476         free(sm->eapReqData);
477         sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
478                                              &sm->eapReqDataLen);
479         if (sm->eapReqData) {
480                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
481                 free(sm->eapReqData);
482                 sm->eapReqData = NULL;
483                 sm->eapReqDataLen = 0;
484         }
485         free(sm->lastReqData);
486         sm->lastReqData = NULL;
487         sm->lastReqDataLen = 0;
488         eapol_set_bool(sm, EAPOL_eapFail, TRUE);
489 }
490
491
492 SM_STATE(EAP, SUCCESS)
493 {
494         SM_ENTRY(EAP, SUCCESS);
495
496         free(sm->eapReqData);
497         sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
498                                              &sm->eapReqDataLen);
499         if (sm->eapReqData) {
500                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
501                 free(sm->eapReqData);
502                 sm->eapReqData = NULL;
503                 sm->eapReqDataLen = 0;
504         }
505         free(sm->lastReqData);
506         sm->lastReqData = NULL;
507         sm->lastReqDataLen = 0;
508         if (sm->eapKeyData) {
509                 eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
510         }
511         eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
512 }
513
514
515 SM_STEP(EAP)
516 {
517         if (eapol_get_bool(sm, EAPOL_eapRestart) &&
518             eapol_get_bool(sm, EAPOL_portEnabled))
519                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
520         else if (!eapol_get_bool(sm, EAPOL_portEnabled))
521                 SM_ENTER_GLOBAL(EAP, DISABLED);
522         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
523                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
524                         wpa_printf(MSG_DEBUG, "EAP: more than %d "
525                                    "authentication rounds - abort",
526                                    EAP_MAX_AUTH_ROUNDS);
527                         sm->num_rounds++;
528                         SM_ENTER_GLOBAL(EAP, FAILURE);
529                 }
530         } else switch (sm->EAP_state) {
531         case EAP_INITIALIZE:
532                 if (sm->backend_auth) {
533                         if (!sm->rxResp)
534                                 SM_ENTER(EAP, SELECT_ACTION);
535                         else if (sm->rxResp &&
536                                  (sm->respMethod == EAP_TYPE_NAK ||
537                                   sm->respMethod == EAP_TYPE_EXPANDED_NAK))
538                                 SM_ENTER(EAP, NAK);
539                         else
540                                 SM_ENTER(EAP, PICK_UP_METHOD);
541                 } else {
542                         SM_ENTER(EAP, SELECT_ACTION);
543                 }
544                 break;
545         case EAP_PICK_UP_METHOD:
546                 if (sm->currentMethod == EAP_TYPE_NONE) {
547                         SM_ENTER(EAP, SELECT_ACTION);
548                 } else {
549                         SM_ENTER(EAP, METHOD_RESPONSE);
550                 }
551                 break;
552         case EAP_DISABLED:
553                 if (eapol_get_bool(sm, EAPOL_portEnabled))
554                         SM_ENTER(EAP, INITIALIZE);
555                 break;
556         case EAP_IDLE:
557                 if (sm->retransWhile == 0)
558                         SM_ENTER(EAP, RETRANSMIT);
559                 else if (eapol_get_bool(sm, EAPOL_eapResp))
560                         SM_ENTER(EAP, RECEIVED);
561                 break;
562         case EAP_RETRANSMIT:
563                 if (sm->retransCount > sm->MaxRetrans)
564                         SM_ENTER(EAP, TIMEOUT_FAILURE);
565                 else
566                         SM_ENTER(EAP, IDLE);
567                 break;
568         case EAP_RECEIVED:
569                 if (sm->rxResp && (sm->respId == sm->currentId) &&
570                     (sm->respMethod == EAP_TYPE_NAK ||
571                      sm->respMethod == EAP_TYPE_EXPANDED_NAK)
572                     && (sm->methodState == METHOD_PROPOSED))
573                         SM_ENTER(EAP, NAK);
574                 else if (sm->rxResp && (sm->respId == sm->currentId) &&
575                          (sm->respMethod == sm->currentMethod))
576                         SM_ENTER(EAP, INTEGRITY_CHECK);
577                 else
578                         SM_ENTER(EAP, DISCARD);
579                 break;
580         case EAP_DISCARD:
581                 SM_ENTER(EAP, IDLE);
582                 break;
583         case EAP_SEND_REQUEST:
584                 SM_ENTER(EAP, IDLE);
585                 break;
586         case EAP_INTEGRITY_CHECK:
587                 if (sm->ignore)
588                         SM_ENTER(EAP, DISCARD);
589                 else
590                         SM_ENTER(EAP, METHOD_RESPONSE);
591                 break;
592         case EAP_METHOD_REQUEST:
593                 SM_ENTER(EAP, SEND_REQUEST);
594                 break;
595         case EAP_METHOD_RESPONSE:
596                 if (sm->methodState == METHOD_END)
597                         SM_ENTER(EAP, SELECT_ACTION);
598                 else
599                         SM_ENTER(EAP, METHOD_REQUEST);
600                 break;
601         case EAP_PROPOSE_METHOD:
602                 SM_ENTER(EAP, METHOD_REQUEST);
603                 break;
604         case EAP_NAK:
605                 SM_ENTER(EAP, SELECT_ACTION);
606                 break;
607         case EAP_SELECT_ACTION:
608                 if (sm->decision == DECISION_FAILURE)
609                         SM_ENTER(EAP, FAILURE);
610                 else if (sm->decision == DECISION_SUCCESS)
611                         SM_ENTER(EAP, SUCCESS);
612                 else
613                         SM_ENTER(EAP, PROPOSE_METHOD);
614                 break;
615         case EAP_TIMEOUT_FAILURE:
616                 break;
617         case EAP_FAILURE:
618                 break;
619         case EAP_SUCCESS:
620                 break;
621         }
622 }
623
624
625 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
626                                    int eapSRTT, int eapRTTVAR,
627                                    int methodTimeout)
628 {
629         /* For now, retransmission is done in EAPOL state machines, so make
630          * sure EAP state machine does not end up trying to retransmit packets.
631          */
632         return 1;
633 }
634
635
636 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
637 {
638         struct eap_hdr *hdr;
639         size_t plen;
640
641         /* parse rxResp, respId, respMethod */
642         sm->rxResp = FALSE;
643         sm->respId = -1;
644         sm->respMethod = EAP_TYPE_NONE;
645
646         if (resp == NULL || len < sizeof(*hdr))
647                 return;
648
649         hdr = (struct eap_hdr *) resp;
650         plen = ntohs(hdr->length);
651         if (plen > len) {
652                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
653                            "(len=%lu plen=%lu)", (unsigned long) len,
654                            (unsigned long) plen);
655                 return;
656         }
657
658         sm->respId = hdr->identifier;
659
660         if (hdr->code == EAP_CODE_RESPONSE)
661                 sm->rxResp = TRUE;
662
663         if (len > sizeof(*hdr))
664                 sm->respMethod = *((u8 *) (hdr + 1));
665
666         wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
667                    "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
668 }
669
670
671 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
672 {
673         struct eap_hdr *resp;
674         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
675
676         *len = sizeof(*resp);
677         resp = malloc(*len);
678         if (resp == NULL)
679                 return NULL;
680         resp->code = EAP_CODE_SUCCESS;
681         resp->identifier = id;
682         resp->length = htons(*len);
683
684         return (u8 *) resp;
685 }
686
687
688 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
689 {
690         struct eap_hdr *resp;
691         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
692
693         *len = sizeof(*resp);
694         resp = malloc(*len);
695         if (resp == NULL)
696                 return NULL;
697         resp->code = EAP_CODE_FAILURE;
698         resp->identifier = id;
699         resp->length = htons(*len);
700
701         return (u8 *) resp;
702 }
703
704
705 static int eap_sm_nextId(struct eap_sm *sm, int id)
706 {
707         if (id < 0) {
708                 /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
709                  * random number */
710                 id = rand() & 0xff;
711                 if (id != sm->lastId)
712                         return id;
713         }
714         return (id + 1) & 0xff;
715 }
716
717
718 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
719 {
720         int i, j;
721
722         wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
723                    "index %d)", sm->user_eap_method_index);
724
725         wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
726                     sm->user->methods, EAP_MAX_METHODS);
727         wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
728                     nak_list, len);
729
730         i = sm->user_eap_method_index;
731         while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
732                 for (j = 0; j < len; j++) {
733                         if (nak_list[j] == sm->user->methods[i]) {
734                                 break;
735                         }
736                 }
737
738                 if (j < len) {
739                         /* found */
740                         i++;
741                         continue;
742                 }
743
744                 /* not found - remove from the list */
745                 memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
746                         EAP_MAX_METHODS - i - 1);
747                 sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
748         }
749
750         wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
751                     sm->user->methods, EAP_MAX_METHODS);
752 }
753
754
755 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
756 {
757         if (nak_list == NULL || sm == NULL || sm->user == NULL)
758                 return;
759
760         if (sm->user->phase2) {
761                 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
762                            " info was selected - reject");
763                 sm->decision = DECISION_FAILURE;
764                 return;
765         }
766
767         eap_sm_process_nak(sm, nak_list, len);
768 }
769
770
771 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
772 {
773         EapType next;
774
775         /* In theory, there should be no problems with starting
776          * re-authentication with something else than EAP-Request/Identity and
777          * this does indeed work with wpa_supplicant. However, at least Funk
778          * Supplicant seemed to ignore re-auth if it skipped
779          * EAP-Request/Identity.
780          * Re-auth sets currentId == -1, so that can be used here to select
781          * whether Identity needs to be requested again. */
782         if (sm->identity == NULL || sm->currentId == -1) {
783                 next = EAP_TYPE_IDENTITY;
784                 sm->update_user = TRUE;
785         } else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
786                    sm->user->methods[sm->user_eap_method_index] !=
787                    EAP_TYPE_NONE) {
788                 next = sm->user->methods[sm->user_eap_method_index++];
789         } else {
790                 next = EAP_TYPE_NONE;
791         }
792         wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
793         return next;
794 }
795
796
797 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
798 {
799         if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
800             sm->m->isSuccess(sm, sm->eap_method_priv)) {
801                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
802                            "SUCCESS");
803                 sm->update_user = TRUE;
804                 return DECISION_SUCCESS;
805         }
806
807         if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
808             !sm->m->isSuccess(sm, sm->eap_method_priv)) {
809                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
810                            "FAILURE");
811                 sm->update_user = TRUE;
812                 return DECISION_FAILURE;
813         }
814
815         if ((sm->user == NULL || sm->update_user) && sm->identity) {
816                 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
817                         wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
818                                    "found from database -> FAILURE");
819                         return DECISION_FAILURE;
820                 }
821                 sm->update_user = FALSE;
822         }
823
824         if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
825             sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
826                 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
827                            "available -> CONTINUE");
828                 return DECISION_CONTINUE;
829         }
830
831         if (sm->identity == NULL || sm->currentId == -1) {
832                 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
833                            "yet -> CONTINUE");
834                 return DECISION_CONTINUE;
835         }
836
837         wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
838                    "FAILURE");
839         return DECISION_FAILURE;
840 }
841
842
843 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
844 {
845         return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
846 }
847
848
849 int eap_sm_step(struct eap_sm *sm)
850 {
851         int res = 0;
852         do {
853                 sm->changed = FALSE;
854                 SM_STEP_RUN(EAP);
855                 if (sm->changed)
856                         res = 1;
857         } while (sm->changed);
858         return res;
859 }
860
861
862 u8 eap_get_type(const char *name)
863 {
864         int i;
865         for (i = 0; i < NUM_EAP_METHODS; i++) {
866                 if (strcmp(eap_methods[i]->name, name) == 0)
867                         return eap_methods[i]->method;
868         }
869         return EAP_TYPE_NONE;
870 }
871
872
873 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
874                          size_t eapRespDataLen)
875 {
876         if (sm == NULL)
877                 return;
878         free(sm->eapRespData);
879         sm->eapRespData = malloc(eapRespDataLen);
880         if (sm->eapRespData == NULL)
881                 return;
882         memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
883         sm->eapRespDataLen = eapRespDataLen;
884         wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
885                     eapRespData, eapRespDataLen);
886 }
887
888
889 static void eap_user_free(struct eap_user *user)
890 {
891         if (user == NULL)
892                 return;
893         free(user->password);
894         user->password = NULL;
895         free(user);
896 }
897
898
899 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
900                             struct eap_config *eap_conf)
901 {
902         struct eap_sm *sm;
903
904         sm = malloc(sizeof(*sm));
905         if (sm == NULL)
906                 return NULL;
907         memset(sm, 0, sizeof(*sm));
908         sm->eapol_ctx = eapol_ctx;
909         sm->eapol_cb = eapol_cb;
910         sm->MaxRetrans = 10;
911         sm->ssl_ctx = eap_conf->ssl_ctx;
912         sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
913         sm->backend_auth = eap_conf->backend_auth;
914
915         wpa_printf(MSG_DEBUG, "EAP: State machine created");
916
917         return sm;
918 }
919
920
921 void eap_sm_deinit(struct eap_sm *sm)
922 {
923         if (sm == NULL)
924                 return;
925         wpa_printf(MSG_DEBUG, "EAP: State machine removed");
926         if (sm->m && sm->eap_method_priv)
927                 sm->m->reset(sm, sm->eap_method_priv);
928         free(sm->eapReqData);
929         free(sm->eapKeyData);
930         free(sm->lastReqData);
931         free(sm->eapRespData);
932         free(sm->identity);
933         eap_user_free(sm->user);
934         free(sm);
935 }
936
937
938 void eap_sm_notify_cached(struct eap_sm *sm)
939 {
940         if (sm == NULL)
941                 return;
942
943         sm->EAP_state = EAP_SUCCESS;
944 }