Check if XAuth round complies to configured authentication round
[strongswan.git] / src / libcharon / sa / ikev1 / tasks / xauth.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "xauth.h"
17
18 #include <daemon.h>
19 #include <hydra.h>
20 #include <encoding/payloads/cp_payload.h>
21 #include <processing/jobs/adopt_children_job.h>
22
23 typedef struct private_xauth_t private_xauth_t;
24
25 /**
26 * Status types exchanged
27 */
28 typedef enum {
29 XAUTH_FAILED = 0,
30 XAUTH_OK = 1,
31 } xauth_status_t;
32
33 /**
34 * Private members of a xauth_t task.
35 */
36 struct private_xauth_t {
37
38 /**
39 * Public methods and task_t interface.
40 */
41 xauth_t public;
42
43 /**
44 * Assigned IKE_SA.
45 */
46 ike_sa_t *ike_sa;
47
48 /**
49 * Are we the XAUTH initiator?
50 */
51 bool initiator;
52
53 /**
54 * Authentication requirements to fulfill
55 */
56 auth_cfg_t *auth;
57
58 /**
59 * XAuth backend to use
60 */
61 xauth_method_t *xauth;
62
63 /**
64 * XAuth username
65 */
66 identification_t *user;
67
68 /**
69 * Generated configuration payload
70 */
71 cp_payload_t *cp;
72
73 /**
74 * received identifier
75 */
76 u_int16_t identifier;
77
78 /**
79 * status of Xauth exchange
80 */
81 xauth_status_t status;
82 };
83
84 /**
85 * Load XAuth backend
86 */
87 static xauth_method_t *load_method(private_xauth_t* this)
88 {
89 identification_t *server, *peer;
90 enumerator_t *enumerator;
91 xauth_method_t *xauth;
92 xauth_role_t role;
93 peer_cfg_t *peer_cfg;
94 auth_cfg_t *auth;
95 char *name;
96
97 if (this->initiator)
98 {
99 server = this->ike_sa->get_my_id(this->ike_sa);
100 peer = this->ike_sa->get_other_id(this->ike_sa);
101 role = XAUTH_SERVER;
102 }
103 else
104 {
105 peer = this->ike_sa->get_my_id(this->ike_sa);
106 server = this->ike_sa->get_other_id(this->ike_sa);
107 role = XAUTH_PEER;
108 }
109 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
110 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
111 if (!enumerator->enumerate(enumerator, &auth) ||
112 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
113 {
114 if (!enumerator->enumerate(enumerator, &auth) ||
115 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
116 {
117 DBG1(DBG_CFG, "no XAuth authentication round found");
118 enumerator->destroy(enumerator);
119 return NULL;
120 }
121 }
122 enumerator->destroy(enumerator);
123 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
124 this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
125 if (!this->initiator && this->user)
126 { /* use XAUTH username, if configured */
127 peer = this->user;
128 }
129 this->auth = auth;
130 xauth = charon->xauth->create_instance(charon->xauth, name, role,
131 server, peer);
132 if (!xauth)
133 {
134 if (name)
135 {
136 DBG1(DBG_CFG, "no XAuth method found named '%s'", name);
137 }
138 else
139 {
140 DBG1(DBG_CFG, "no XAuth method found");
141 }
142 }
143 return xauth;
144 }
145
146 /**
147 * Check if XAuth connection is allowed to succeed
148 */
149 static bool allowed(private_xauth_t *this)
150 {
151 if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
152 this->ike_sa, FALSE))
153 {
154 DBG1(DBG_IKE, "cancelling XAuth due to uniqueness policy");
155 return FALSE;
156 }
157 if (!charon->bus->authorize(charon->bus, FALSE))
158 {
159 DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling");
160 return FALSE;
161 }
162 if (!charon->bus->authorize(charon->bus, TRUE))
163 {
164 DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
165 return FALSE;
166 }
167 return TRUE;
168 }
169
170 /**
171 * Set IKE_SA to established state
172 */
173 static bool establish(private_xauth_t *this)
174 {
175 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
176 this->ike_sa->get_name(this->ike_sa),
177 this->ike_sa->get_unique_id(this->ike_sa),
178 this->ike_sa->get_my_host(this->ike_sa),
179 this->ike_sa->get_my_id(this->ike_sa),
180 this->ike_sa->get_other_host(this->ike_sa),
181 this->ike_sa->get_other_id(this->ike_sa));
182
183 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
184 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
185
186 return TRUE;
187 }
188
189 /**
190 * Create auth config after successful authentication
191 */
192 static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
193 {
194 auth_cfg_t *auth;
195
196 auth = auth_cfg_create();
197 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
198 auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
199 auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), TRUE);
200
201 if (!auth->complies(auth, this->auth, TRUE))
202 {
203 auth->destroy(auth);
204 return FALSE;
205 }
206 this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
207 return TRUE;
208 }
209
210 METHOD(task_t, build_i_status, status_t,
211 private_xauth_t *this, message_t *message)
212 {
213 cp_payload_t *cp;
214
215 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
216 cp->add_attribute(cp,
217 configuration_attribute_create_value(XAUTH_STATUS, this->status));
218
219 message->add_payload(message, (payload_t *)cp);
220
221 return NEED_MORE;
222 }
223
224 METHOD(task_t, build_i, status_t,
225 private_xauth_t *this, message_t *message)
226 {
227 if (!this->xauth)
228 {
229 cp_payload_t *cp;
230
231 this->xauth = load_method(this);
232 if (!this->xauth)
233 {
234 return FAILED;
235 }
236 if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
237 {
238 return FAILED;
239 }
240 message->add_payload(message, (payload_t *)cp);
241 return NEED_MORE;
242 }
243
244 if (this->cp)
245 { /* send previously generated payload */
246 message->add_payload(message, (payload_t *)this->cp);
247 this->cp = NULL;
248 return NEED_MORE;
249 }
250 return FAILED;
251 }
252
253 METHOD(task_t, build_r_ack, status_t,
254 private_xauth_t *this, message_t *message)
255 {
256 cp_payload_t *cp;
257
258 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
259 cp->set_identifier(cp, this->identifier);
260 cp->add_attribute(cp,
261 configuration_attribute_create_chunk(
262 CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
263
264 message->add_payload(message, (payload_t *)cp);
265
266 if (this->status == XAUTH_OK && allowed(this) && establish(this))
267 {
268 return SUCCESS;
269 }
270 return FAILED;
271 }
272
273 METHOD(task_t, process_r, status_t,
274 private_xauth_t *this, message_t *message)
275 {
276 cp_payload_t *cp;
277
278 if (!this->xauth)
279 {
280 this->xauth = load_method(this);
281 if (!this->xauth)
282 { /* send empty reply */
283 return NEED_MORE;
284 }
285 }
286 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
287 if (!cp)
288 {
289 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
290 return FAILED;
291 }
292 if (cp->get_type(cp) == CFG_REQUEST)
293 {
294 switch (this->xauth->process(this->xauth, cp, &this->cp))
295 {
296 case NEED_MORE:
297 return NEED_MORE;
298 case SUCCESS:
299 case FAILED:
300 default:
301 break;
302 }
303 this->cp = NULL;
304 return NEED_MORE;
305 }
306 if (cp->get_type(cp) == CFG_SET)
307 {
308 configuration_attribute_t *attribute;
309 enumerator_t *enumerator;
310
311 enumerator = cp->create_attribute_enumerator(cp);
312 while (enumerator->enumerate(enumerator, &attribute))
313 {
314 if (attribute->get_type(attribute) == XAUTH_STATUS)
315 {
316 this->status = attribute->get_value(attribute);
317 }
318 }
319 enumerator->destroy(enumerator);
320 if (this->status == XAUTH_OK &&
321 add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE))
322 {
323 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
324 this->xauth->get_identity(this->xauth));
325 }
326 else
327 {
328 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
329 this->xauth->get_identity(this->xauth));
330 }
331 }
332 this->identifier = cp->get_identifier(cp);
333 this->public.task.build = _build_r_ack;
334 return NEED_MORE;
335 }
336
337 METHOD(task_t, build_r, status_t,
338 private_xauth_t *this, message_t *message)
339 {
340 if (!this->cp)
341 { /* send empty reply if building data failed */
342 this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
343 }
344 message->add_payload(message, (payload_t *)this->cp);
345 this->cp = NULL;
346 return NEED_MORE;
347 }
348
349 METHOD(task_t, process_i_status, status_t,
350 private_xauth_t *this, message_t *message)
351 {
352 cp_payload_t *cp;
353
354 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
355 if (!cp || cp->get_type(cp) != CFG_ACK)
356 {
357 DBG1(DBG_IKE, "received invalid XAUTH status response");
358 return FAILED;
359 }
360 if (this->status != XAUTH_OK)
361 {
362 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
363 return FAILED;
364 }
365 if (!establish(this))
366 {
367 return FAILED;
368 }
369 this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
370 lib->processor->queue_job(lib->processor, (job_t*)
371 adopt_children_job_create(this->ike_sa->get_id(this->ike_sa)));
372 return SUCCESS;
373 }
374
375 METHOD(task_t, process_i, status_t,
376 private_xauth_t *this, message_t *message)
377 {
378 identification_t *id;
379 cp_payload_t *cp;
380
381 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
382 if (!cp)
383 {
384 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
385 return FAILED;
386 }
387 switch (this->xauth->process(this->xauth, cp, &this->cp))
388 {
389 case NEED_MORE:
390 return NEED_MORE;
391 case SUCCESS:
392 id = this->xauth->get_identity(this->xauth);
393 if (this->user && !id->matches(id, this->user))
394 {
395 DBG1(DBG_IKE, "XAuth username '%Y' does not match to "
396 "configured username '%Y'", id, this->user);
397 break;
398 }
399 DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
400 if (add_auth_cfg(this, id, FALSE) && allowed(this))
401 {
402 this->status = XAUTH_OK;
403 }
404 break;
405 case FAILED:
406 DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
407 this->xauth->get_identity(this->xauth));
408 break;
409 default:
410 return FAILED;
411 }
412 this->public.task.build = _build_i_status;
413 this->public.task.process = _process_i_status;
414 return NEED_MORE;
415 }
416
417 METHOD(task_t, get_type, task_type_t,
418 private_xauth_t *this)
419 {
420 return TASK_XAUTH;
421 }
422
423 METHOD(task_t, migrate, void,
424 private_xauth_t *this, ike_sa_t *ike_sa)
425 {
426 DESTROY_IF(this->xauth);
427 DESTROY_IF(this->cp);
428
429 this->ike_sa = ike_sa;
430 this->xauth = NULL;
431 this->cp = NULL;
432 this->user = NULL;
433 this->status = XAUTH_FAILED;
434
435 if (this->initiator)
436 {
437 this->public.task.build = _build_i;
438 this->public.task.process = _process_i;
439 }
440 else
441 {
442 this->public.task.build = _build_r;
443 this->public.task.process = _process_r;
444 }
445 }
446
447 METHOD(task_t, destroy, void,
448 private_xauth_t *this)
449 {
450 DESTROY_IF(this->xauth);
451 DESTROY_IF(this->cp);
452 free(this);
453 }
454
455 /*
456 * Described in header.
457 */
458 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
459 {
460 private_xauth_t *this;
461
462 INIT(this,
463 .public = {
464 .task = {
465 .get_type = _get_type,
466 .migrate = _migrate,
467 .destroy = _destroy,
468 },
469 },
470 .initiator = initiator,
471 .ike_sa = ike_sa,
472 .status = XAUTH_FAILED,
473 );
474
475 if (initiator)
476 {
477 this->public.task.build = _build_i;
478 this->public.task.process = _process_i;
479 }
480 else
481 {
482 this->public.task.build = _build_r;
483 this->public.task.process = _process_r;
484 }
485 return &this->public;
486 }