Re-initialize hostapd/wpa_supplicant git repository based on 0.6.3 release
[mech_eap.git] / src / eap_server / eap_gtc.c
1 /*
2  * hostapd / EAP-GTC (RFC 3748)
3  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.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 "includes.h"
16
17 #include "common.h"
18 #include "eap_i.h"
19
20
21 struct eap_gtc_data {
22         enum { CONTINUE, SUCCESS, FAILURE } state;
23         int prefix;
24 };
25
26
27 static void * eap_gtc_init(struct eap_sm *sm)
28 {
29         struct eap_gtc_data *data;
30
31         data = os_zalloc(sizeof(*data));
32         if (data == NULL)
33                 return NULL;
34         data->state = CONTINUE;
35
36 #ifdef EAP_FAST
37         if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
38             sm->m->method == EAP_TYPE_FAST) {
39                 wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
40                            "with challenge/response");
41                 data->prefix = 1;
42         }
43 #endif /* EAP_FAST */
44
45         return data;
46 }
47
48
49 static void eap_gtc_reset(struct eap_sm *sm, void *priv)
50 {
51         struct eap_gtc_data *data = priv;
52         os_free(data);
53 }
54
55
56 static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
57 {
58         struct eap_gtc_data *data = priv;
59         struct wpabuf *req;
60         char *msg;
61         size_t msg_len;
62
63         msg = data->prefix ? "CHALLENGE=Password" : "Password";
64
65         msg_len = os_strlen(msg);
66         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len,
67                             EAP_CODE_REQUEST, id);
68         if (req == NULL) {
69                 wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
70                            "request");
71                 data->state = FAILURE;
72                 return NULL;
73         }
74
75         wpabuf_put_data(req, msg, msg_len);
76
77         data->state = CONTINUE;
78
79         return req;
80 }
81
82
83 static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
84                              struct wpabuf *respData)
85 {
86         const u8 *pos;
87         size_t len;
88
89         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
90         if (pos == NULL || len < 1) {
91                 wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
92                 return TRUE;
93         }
94
95         return FALSE;
96 }
97
98
99 static void eap_gtc_process(struct eap_sm *sm, void *priv,
100                             struct wpabuf *respData)
101 {
102         struct eap_gtc_data *data = priv;
103         const u8 *pos;
104         size_t rlen;
105
106         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen);
107         if (pos == NULL || rlen < 1)
108                 return; /* Should not happen - frame already validated */
109
110         wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
111
112 #ifdef EAP_FAST
113         if (data->prefix) {
114                 const u8 *pos2, *end;
115                 /* "RESPONSE=<user>\0<password>" */
116                 if (rlen < 10) {
117                         wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
118                                    "for EAP-FAST prefix");
119                         data->state = FAILURE;
120                         return;
121                 }
122
123                 end = pos + rlen;
124                 pos += 9;
125                 pos2 = pos;
126                 while (pos2 < end && *pos2)
127                         pos2++;
128                 if (pos2 == end) {
129                         wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
130                                    "response to EAP-FAST prefix");
131                         data->state = FAILURE;
132                         return;
133                 }
134
135                 wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
136                                   pos, pos2 - pos);
137                 os_free(sm->identity);
138                 sm->identity_len = pos2 - pos;
139                 sm->identity = os_malloc(sm->identity_len);
140                 if (sm->identity == NULL) {
141                         data->state = FAILURE;
142                         return;
143                 }
144                 os_memcpy(sm->identity, pos, sm->identity_len);
145
146                 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
147                         wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
148                                           "Identity not found in the user "
149                                           "database",
150                                           sm->identity, sm->identity_len);
151                         data->state = FAILURE;
152                         return;
153                 }
154
155                 pos = pos2 + 1;
156                 rlen = end - pos;
157                 wpa_hexdump_ascii_key(MSG_MSGDUMP,
158                                       "EAP-GTC: Response password",
159                                       pos, rlen);
160         }
161 #endif /* EAP_FAST */
162
163         if (sm->user == NULL || sm->user->password == NULL ||
164             sm->user->password_hash) {
165                 wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
166                            "configured");
167                 data->state = FAILURE;
168                 return;
169         }
170
171         if (rlen != sm->user->password_len ||
172             os_memcmp(pos, sm->user->password, rlen) != 0) {
173                 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
174                 data->state = FAILURE;
175         } else {
176                 wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
177                 data->state = SUCCESS;
178         }
179 }
180
181
182 static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
183 {
184         struct eap_gtc_data *data = priv;
185         return data->state != CONTINUE;
186 }
187
188
189 static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
190 {
191         struct eap_gtc_data *data = priv;
192         return data->state == SUCCESS;
193 }
194
195
196 int eap_server_gtc_register(void)
197 {
198         struct eap_method *eap;
199         int ret;
200
201         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
202                                       EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
203         if (eap == NULL)
204                 return -1;
205
206         eap->init = eap_gtc_init;
207         eap->reset = eap_gtc_reset;
208         eap->buildReq = eap_gtc_buildReq;
209         eap->check = eap_gtc_check;
210         eap->process = eap_gtc_process;
211         eap->isDone = eap_gtc_isDone;
212         eap->isSuccess = eap_gtc_isSuccess;
213
214         ret = eap_server_method_register(eap);
215         if (ret)
216                 eap_server_method_free(eap);
217         return ret;
218 }