]>
Commit | Line | Data |
---|---|---|
1caa265c | 1 | /* |
27128c1e MW |
2 | * Copyright (C) 2007-2012 Martin Willi |
3 | * Copyright (C) 2012 revosec AG | |
1caa265c MW |
4 | * Hochschule fuer Technik Rapperswil |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
1caa265c | 15 | */ |
7daf5226 | 16 | |
1caa265c MW |
17 | #include "eap_gtc.h" |
18 | ||
19 | #include <daemon.h> | |
20 | #include <library.h> | |
1caa265c | 21 | |
1995f79f | 22 | #define GTC_REQUEST_MSG "password" |
1caa265c MW |
23 | |
24 | typedef struct private_eap_gtc_t private_eap_gtc_t; | |
25 | ||
26 | /** | |
27 | * Private data of an eap_gtc_t object. | |
28 | */ | |
29 | struct private_eap_gtc_t { | |
7daf5226 | 30 | |
1caa265c MW |
31 | /** |
32 | * Public authenticator_t interface. | |
33 | */ | |
34 | eap_gtc_t public; | |
7daf5226 | 35 | |
1caa265c MW |
36 | /** |
37 | * ID of the server | |
38 | */ | |
39 | identification_t *server; | |
7daf5226 | 40 | |
1caa265c MW |
41 | /** |
42 | * ID of the peer | |
43 | */ | |
44 | identification_t *peer; | |
7daf5226 | 45 | |
1caa265c MW |
46 | /** |
47 | * EAP message identififier | |
48 | */ | |
49 | u_int8_t identifier; | |
50 | }; | |
51 | ||
52 | typedef struct eap_gtc_header_t eap_gtc_header_t; | |
53 | ||
54 | /** | |
55 | * packed eap GTC header struct | |
56 | */ | |
57 | struct eap_gtc_header_t { | |
58 | /** EAP code (REQUEST/RESPONSE) */ | |
59 | u_int8_t code; | |
60 | /** unique message identifier */ | |
61 | u_int8_t identifier; | |
62 | /** length of whole message */ | |
63 | u_int16_t length; | |
64 | /** EAP type */ | |
65 | u_int8_t type; | |
66 | /** type data */ | |
67 | u_int8_t data[]; | |
68 | } __attribute__((__packed__)); | |
69 | ||
e053961d AS |
70 | METHOD(eap_method_t, initiate_peer, status_t, |
71 | private_eap_gtc_t *this, eap_payload_t **out) | |
1caa265c MW |
72 | { |
73 | /* peer never initiates */ | |
74 | return FAILED; | |
75 | } | |
76 | ||
e053961d AS |
77 | METHOD(eap_method_t, initiate_server, status_t, |
78 | private_eap_gtc_t *this, eap_payload_t **out) | |
1caa265c MW |
79 | { |
80 | eap_gtc_header_t *req; | |
81 | size_t len; | |
7daf5226 | 82 | |
1caa265c MW |
83 | len = strlen(GTC_REQUEST_MSG); |
84 | req = alloca(sizeof(eap_gtc_header_t) + len); | |
85 | req->length = htons(sizeof(eap_gtc_header_t) + len); | |
86 | req->code = EAP_REQUEST; | |
87 | req->identifier = this->identifier; | |
88 | req->type = EAP_GTC; | |
89 | memcpy(req->data, GTC_REQUEST_MSG, len); | |
7daf5226 | 90 | |
1caa265c MW |
91 | *out = eap_payload_create_data(chunk_create((void*)req, |
92 | sizeof(eap_gtc_header_t) + len)); | |
93 | return NEED_MORE; | |
94 | } | |
95 | ||
e053961d AS |
96 | METHOD(eap_method_t, process_peer, status_t, |
97 | private_eap_gtc_t *this, eap_payload_t *in, eap_payload_t **out) | |
1caa265c MW |
98 | { |
99 | eap_gtc_header_t *res; | |
100 | shared_key_t *shared; | |
101 | chunk_t key; | |
102 | size_t len; | |
103 | ||
2ccc02a4 MW |
104 | shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, |
105 | this->peer, this->server); | |
1caa265c MW |
106 | if (shared == NULL) |
107 | { | |
d24a74c5 | 108 | DBG1(DBG_IKE, "no EAP key found for '%Y' - '%Y'", |
1995f79f | 109 | this->peer, this->server); |
1caa265c MW |
110 | return FAILED; |
111 | } | |
112 | key = shared->get_key(shared); | |
113 | len = key.len; | |
7daf5226 | 114 | |
b848f037 | 115 | /* TODO: According to the draft we should "SASLprep" password, RFC4013. */ |
1caa265c | 116 | |
07313dbe | 117 | this->identifier = in->get_identifier(in); |
1caa265c MW |
118 | res = alloca(sizeof(eap_gtc_header_t) + len); |
119 | res->length = htons(sizeof(eap_gtc_header_t) + len); | |
120 | res->code = EAP_RESPONSE; | |
07313dbe | 121 | res->identifier = this->identifier; |
1caa265c MW |
122 | res->type = EAP_GTC; |
123 | memcpy(res->data, key.ptr, len); | |
7daf5226 | 124 | |
1caa265c | 125 | shared->destroy(shared); |
7daf5226 | 126 | |
1caa265c MW |
127 | *out = eap_payload_create_data(chunk_create((void*)res, |
128 | sizeof(eap_gtc_header_t) + len)); | |
129 | return NEED_MORE; | |
130 | } | |
131 | ||
e053961d AS |
132 | METHOD(eap_method_t, process_server, status_t, |
133 | private_eap_gtc_t *this, eap_payload_t *in, eap_payload_t **out) | |
1caa265c | 134 | { |
27128c1e MW |
135 | status_t status = FAILED; |
136 | chunk_t user, pass; | |
137 | xauth_method_t *xauth; | |
138 | cp_payload_t *ci, *co; | |
139 | char *backend; | |
140 | ||
141 | user = this->peer->get_encoding(this->peer); | |
142 | pass = chunk_skip(in->get_data(in), 5); | |
143 | if (this->identifier != in->get_identifier(in) || !pass.len) | |
1caa265c MW |
144 | { |
145 | DBG1(DBG_IKE, "received invalid EAP-GTC message"); | |
146 | return FAILED; | |
147 | } | |
7daf5226 | 148 | |
27128c1e MW |
149 | /* get XAuth backend to use for credential verification. Default to PAM |
150 | * to support legacy EAP-GTC configurations */ | |
151 | backend = lib->settings->get_str(lib->settings, | |
d223fe80 | 152 | "%s.plugins.eap-gtc.backend", "pam", lib->ns); |
27128c1e MW |
153 | xauth = charon->xauth->create_instance(charon->xauth, backend, XAUTH_SERVER, |
154 | this->server, this->peer); | |
155 | if (!xauth) | |
1995f79f | 156 | { |
27128c1e MW |
157 | DBG1(DBG_IKE, "creating EAP-GTC XAuth backend '%s' failed", backend); |
158 | return FAILED; | |
1995f79f | 159 | } |
27128c1e | 160 | if (xauth->initiate(xauth, &co) == NEED_MORE) |
1caa265c | 161 | { |
27128c1e MW |
162 | /* assume that "out" contains username/password attributes */ |
163 | co->destroy(co); | |
164 | ci = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); | |
165 | ci->add_attribute(ci, configuration_attribute_create_chunk( | |
166 | CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); | |
167 | ci->add_attribute(ci, configuration_attribute_create_chunk( | |
168 | CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); | |
169 | switch (xauth->process(xauth, ci, &co)) | |
170 | { | |
171 | case SUCCESS: | |
172 | status = SUCCESS; | |
173 | break; | |
174 | case NEED_MORE: | |
175 | /* TODO: multiple exchanges currently not supported */ | |
176 | co->destroy(co); | |
177 | break; | |
178 | case FAILED: | |
179 | default: | |
180 | break; | |
181 | } | |
182 | ci->destroy(ci); | |
1caa265c | 183 | } |
27128c1e MW |
184 | xauth->destroy(xauth); |
185 | return status; | |
1caa265c MW |
186 | } |
187 | ||
e053961d AS |
188 | METHOD(eap_method_t, get_type, eap_type_t, |
189 | private_eap_gtc_t *this, u_int32_t *vendor) | |
1caa265c MW |
190 | { |
191 | *vendor = 0; | |
192 | return EAP_GTC; | |
193 | } | |
194 | ||
e053961d AS |
195 | METHOD(eap_method_t, get_msk, status_t, |
196 | private_eap_gtc_t *this, chunk_t *msk) | |
1caa265c MW |
197 | { |
198 | return FAILED; | |
199 | } | |
200 | ||
05aa206d AS |
201 | METHOD(eap_method_t, get_identifier, u_int8_t, |
202 | private_eap_gtc_t *this) | |
203 | { | |
204 | return this->identifier; | |
205 | } | |
206 | ||
207 | METHOD(eap_method_t, set_identifier, void, | |
208 | private_eap_gtc_t *this, u_int8_t identifier) | |
209 | { | |
210 | this->identifier = identifier; | |
211 | } | |
212 | ||
e053961d AS |
213 | METHOD(eap_method_t, is_mutual, bool, |
214 | private_eap_gtc_t *this) | |
1caa265c MW |
215 | { |
216 | return FALSE; | |
217 | } | |
218 | ||
e053961d AS |
219 | METHOD(eap_method_t, destroy, void, |
220 | private_eap_gtc_t *this) | |
1caa265c | 221 | { |
82290106 MW |
222 | this->peer->destroy(this->peer); |
223 | this->server->destroy(this->server); | |
1caa265c MW |
224 | free(this); |
225 | } | |
226 | ||
227 | /** | |
228 | * Generic constructor | |
229 | */ | |
230 | static private_eap_gtc_t *eap_gtc_create_generic(identification_t *server, | |
231 | identification_t *peer) | |
232 | { | |
e053961d AS |
233 | private_eap_gtc_t *this; |
234 | ||
235 | INIT(this, | |
236 | .public = { | |
237 | .eap_method_interface = { | |
238 | .get_type = _get_type, | |
239 | .is_mutual = _is_mutual, | |
240 | .get_msk = _get_msk, | |
05aa206d AS |
241 | .get_identifier = _get_identifier, |
242 | .set_identifier = _set_identifier, | |
e053961d AS |
243 | .destroy = _destroy, |
244 | }, | |
245 | }, | |
246 | .peer = peer->clone(peer), | |
247 | .server = server->clone(server), | |
248 | ); | |
7daf5226 | 249 | |
1caa265c MW |
250 | return this; |
251 | } | |
252 | ||
253 | /* | |
254 | * see header | |
255 | */ | |
256 | eap_gtc_t *eap_gtc_create_server(identification_t *server, identification_t *peer) | |
257 | { | |
258 | private_eap_gtc_t *this = eap_gtc_create_generic(server, peer); | |
7daf5226 | 259 | |
e053961d AS |
260 | this->public.eap_method_interface.initiate = _initiate_server; |
261 | this->public.eap_method_interface.process = _process_server; | |
1caa265c | 262 | |
82290106 MW |
263 | /* generate a non-zero identifier */ |
264 | do { | |
265 | this->identifier = random(); | |
266 | } while (!this->identifier); | |
267 | ||
1caa265c MW |
268 | return &this->public; |
269 | } | |
270 | ||
271 | /* | |
272 | * see header | |
273 | */ | |
274 | eap_gtc_t *eap_gtc_create_peer(identification_t *server, identification_t *peer) | |
275 | { | |
276 | private_eap_gtc_t *this = eap_gtc_create_generic(server, peer); | |
7daf5226 | 277 | |
e053961d AS |
278 | this->public.eap_method_interface.initiate = _initiate_peer; |
279 | this->public.eap_method_interface.process = _process_peer; | |
1caa265c MW |
280 | |
281 | return &this->public; | |
282 | } |