]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
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 | ||
1e5839e0 | 36 | #ifdef EAP_SERVER_FAST |
6fc6879b JM |
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 | } | |
1e5839e0 | 43 | #endif /* EAP_SERVER_FAST */ |
6fc6879b JM |
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 | ||
1e5839e0 | 112 | #ifdef EAP_SERVER_FAST |
6fc6879b JM |
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); | |
13b3f339 JM |
137 | if (sm->identity && sm->require_identity_match && |
138 | (pos2 - pos != (int) sm->identity_len || | |
139 | os_memcmp(pos, sm->identity, sm->identity_len))) { | |
140 | wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " | |
141 | "not match with required Identity"); | |
142 | wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " | |
143 | "identity", | |
144 | sm->identity, sm->identity_len); | |
6fc6879b JM |
145 | data->state = FAILURE; |
146 | return; | |
13b3f339 JM |
147 | } else { |
148 | os_free(sm->identity); | |
149 | sm->identity_len = pos2 - pos; | |
150 | sm->identity = os_malloc(sm->identity_len); | |
151 | if (sm->identity == NULL) { | |
152 | data->state = FAILURE; | |
153 | return; | |
154 | } | |
155 | os_memcpy(sm->identity, pos, sm->identity_len); | |
6fc6879b | 156 | } |
6fc6879b JM |
157 | |
158 | if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { | |
159 | wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " | |
160 | "Identity not found in the user " | |
161 | "database", | |
162 | sm->identity, sm->identity_len); | |
163 | data->state = FAILURE; | |
164 | return; | |
165 | } | |
166 | ||
167 | pos = pos2 + 1; | |
168 | rlen = end - pos; | |
169 | wpa_hexdump_ascii_key(MSG_MSGDUMP, | |
170 | "EAP-GTC: Response password", | |
171 | pos, rlen); | |
172 | } | |
1e5839e0 | 173 | #endif /* EAP_SERVER_FAST */ |
6fc6879b JM |
174 | |
175 | if (sm->user == NULL || sm->user->password == NULL || | |
176 | sm->user->password_hash) { | |
177 | wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " | |
178 | "configured"); | |
179 | data->state = FAILURE; | |
180 | return; | |
181 | } | |
182 | ||
183 | if (rlen != sm->user->password_len || | |
184 | os_memcmp(pos, sm->user->password, rlen) != 0) { | |
185 | wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); | |
186 | data->state = FAILURE; | |
187 | } else { | |
188 | wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); | |
189 | data->state = SUCCESS; | |
190 | } | |
191 | } | |
192 | ||
193 | ||
194 | static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) | |
195 | { | |
196 | struct eap_gtc_data *data = priv; | |
197 | return data->state != CONTINUE; | |
198 | } | |
199 | ||
200 | ||
201 | static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) | |
202 | { | |
203 | struct eap_gtc_data *data = priv; | |
204 | return data->state == SUCCESS; | |
205 | } | |
206 | ||
207 | ||
208 | int eap_server_gtc_register(void) | |
209 | { | |
210 | struct eap_method *eap; | |
211 | int ret; | |
212 | ||
213 | eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, | |
214 | EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); | |
215 | if (eap == NULL) | |
216 | return -1; | |
217 | ||
218 | eap->init = eap_gtc_init; | |
219 | eap->reset = eap_gtc_reset; | |
220 | eap->buildReq = eap_gtc_buildReq; | |
221 | eap->check = eap_gtc_check; | |
222 | eap->process = eap_gtc_process; | |
223 | eap->isDone = eap_gtc_isDone; | |
224 | eap->isSuccess = eap_gtc_isSuccess; | |
225 | ||
226 | ret = eap_server_method_register(eap); | |
227 | if (ret) | |
228 | eap_server_method_free(eap); | |
229 | return ret; | |
230 | } |