libhydra: Move kernel interface to libcharon
[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 <encoding/payloads/cp_payload.h>
20 #include <processing/jobs/adopt_children_job.h>
21 #include <sa/ikev1/tasks/mode_config.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 * XAuth backend to use
55 */
56 xauth_method_t *xauth;
57
58 /**
59 * XAuth username
60 */
61 identification_t *user;
62
63 /**
64 * Generated configuration payload
65 */
66 cp_payload_t *cp;
67
68 /**
69 * received identifier
70 */
71 u_int16_t identifier;
72
73 /**
74 * status of Xauth exchange
75 */
76 xauth_status_t status;
77
78 /**
79 * Queue a Mode Config Push mode after completing XAuth?
80 */
81 bool mode_config_push;
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 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
123 this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
124 enumerator->destroy(enumerator);
125 if (!this->initiator && this->user)
126 { /* use XAUTH username, if configured */
127 peer = this->user;
128 }
129 xauth = charon->xauth->create_instance(charon->xauth, name, role,
130 server, peer);
131 if (!xauth)
132 {
133 if (name)
134 {
135 DBG1(DBG_CFG, "no XAuth method found for '%s'", name);
136 }
137 else
138 {
139 DBG1(DBG_CFG, "no XAuth method found");
140 }
141 }
142 return xauth;
143 }
144
145 /**
146 * Check if XAuth connection is allowed to succeed
147 */
148 static bool allowed(private_xauth_t *this)
149 {
150 if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
151 this->ike_sa, FALSE))
152 {
153 DBG1(DBG_IKE, "cancelling XAuth due to uniqueness policy");
154 return FALSE;
155 }
156 if (!charon->bus->authorize(charon->bus, FALSE))
157 {
158 DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling");
159 return FALSE;
160 }
161 if (!charon->bus->authorize(charon->bus, TRUE))
162 {
163 DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
164 return FALSE;
165 }
166 return TRUE;
167 }
168
169 /**
170 * Set IKE_SA to established state
171 */
172 static bool establish(private_xauth_t *this)
173 {
174 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
175 this->ike_sa->get_name(this->ike_sa),
176 this->ike_sa->get_unique_id(this->ike_sa),
177 this->ike_sa->get_my_host(this->ike_sa),
178 this->ike_sa->get_my_id(this->ike_sa),
179 this->ike_sa->get_other_host(this->ike_sa),
180 this->ike_sa->get_other_id(this->ike_sa));
181
182 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
183 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
184
185 return TRUE;
186 }
187
188 /**
189 * Check if we are compliant to a given peer config
190 */
191 static bool is_compliant(private_xauth_t *this, peer_cfg_t *peer_cfg, bool log)
192 {
193 bool complies = TRUE;
194 enumerator_t *e1, *e2;
195 auth_cfg_t *c1, *c2;
196
197 e1 = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
198 e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE);
199 while (e1->enumerate(e1, &c1))
200 {
201 if (!e2->enumerate(e2, &c2) || !c2->complies(c2, c1, log))
202 {
203 complies = FALSE;
204 break;
205 }
206 }
207 e1->destroy(e1);
208 e2->destroy(e2);
209
210 return complies;
211 }
212
213 /**
214 * Check if we are compliant to current config, switch to another if not
215 */
216 static bool select_compliant_config(private_xauth_t *this)
217 {
218 peer_cfg_t *peer_cfg = NULL, *old, *current;
219 identification_t *my_id, *other_id;
220 host_t *my_host, *other_host;
221 enumerator_t *enumerator;
222 bool aggressive;
223
224 old = this->ike_sa->get_peer_cfg(this->ike_sa);
225 if (is_compliant(this, old, TRUE))
226 { /* current config is fine */
227 return TRUE;
228 }
229 DBG1(DBG_CFG, "selected peer config '%s' inacceptable",
230 old->get_name(old));
231 aggressive = old->use_aggressive(old);
232
233 my_host = this->ike_sa->get_my_host(this->ike_sa);
234 other_host = this->ike_sa->get_other_host(this->ike_sa);
235 my_id = this->ike_sa->get_my_id(this->ike_sa);
236 other_id = this->ike_sa->get_other_id(this->ike_sa);
237 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
238 my_host, other_host, my_id, other_id, IKEV1);
239 while (enumerator->enumerate(enumerator, &current))
240 {
241 if (!current->equals(current, old) &&
242 current->use_aggressive(current) == aggressive &&
243 is_compliant(this, current, FALSE))
244 {
245 peer_cfg = current;
246 break;
247 }
248 }
249 if (peer_cfg)
250 {
251 DBG1(DBG_CFG, "switching to peer config '%s'",
252 peer_cfg->get_name(peer_cfg));
253 this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
254 }
255 else
256 {
257 DBG1(DBG_CFG, "no alternative config found");
258 }
259 enumerator->destroy(enumerator);
260
261 return peer_cfg != NULL;
262 }
263
264 /**
265 * Create auth config after successful authentication
266 */
267 static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
268 {
269 auth_cfg_t *auth;
270
271 auth = auth_cfg_create();
272 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
273 if (id)
274 {
275 auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
276 }
277 auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE);
278 this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
279
280 return select_compliant_config(this);
281 }
282
283 METHOD(task_t, build_i_status, status_t,
284 private_xauth_t *this, message_t *message)
285 {
286 cp_payload_t *cp;
287
288 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
289 cp->add_attribute(cp,
290 configuration_attribute_create_value(XAUTH_STATUS, this->status));
291
292 message->add_payload(message, (payload_t *)cp);
293
294 return NEED_MORE;
295 }
296
297 METHOD(task_t, process_i_status, status_t,
298 private_xauth_t *this, message_t *message)
299 {
300 cp_payload_t *cp;
301 adopt_children_job_t *job;
302
303 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
304 if (!cp || cp->get_type(cp) != CFG_ACK)
305 {
306 DBG1(DBG_IKE, "received invalid XAUTH status response");
307 return FAILED;
308 }
309 if (this->status != XAUTH_OK)
310 {
311 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
312 return FAILED;
313 }
314 if (!establish(this))
315 {
316 return FAILED;
317 }
318 this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
319 job = adopt_children_job_create(this->ike_sa->get_id(this->ike_sa));
320 if (this->mode_config_push)
321 {
322 job->queue_task(job,
323 (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
324 }
325 lib->processor->queue_job(lib->processor, (job_t*)job);
326 return SUCCESS;
327 }
328
329 METHOD(task_t, build_i, status_t,
330 private_xauth_t *this, message_t *message)
331 {
332 if (!this->xauth)
333 {
334 cp_payload_t *cp = NULL;
335
336 this->xauth = load_method(this);
337 if (!this->xauth)
338 {
339 return FAILED;
340 }
341 switch (this->xauth->initiate(this->xauth, &cp))
342 {
343 case NEED_MORE:
344 break;
345 case SUCCESS:
346 DESTROY_IF(cp);
347 if (add_auth_cfg(this, NULL, FALSE) && allowed(this))
348 {
349 this->status = XAUTH_OK;
350 }
351 this->public.task.process = _process_i_status;
352 return build_i_status(this, message);
353 default:
354 return FAILED;
355 }
356 message->add_payload(message, (payload_t *)cp);
357 return NEED_MORE;
358 }
359
360 if (this->cp)
361 { /* send previously generated payload */
362 message->add_payload(message, (payload_t *)this->cp);
363 this->cp = NULL;
364 return NEED_MORE;
365 }
366 return FAILED;
367 }
368
369 METHOD(task_t, build_r_ack, status_t,
370 private_xauth_t *this, message_t *message)
371 {
372 cp_payload_t *cp;
373
374 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
375 cp->set_identifier(cp, this->identifier);
376 cp->add_attribute(cp,
377 configuration_attribute_create_chunk(
378 PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_STATUS, chunk_empty));
379
380 message->add_payload(message, (payload_t *)cp);
381
382 if (this->status == XAUTH_OK && allowed(this) && establish(this))
383 {
384 return SUCCESS;
385 }
386 return FAILED;
387 }
388
389 METHOD(task_t, process_r, status_t,
390 private_xauth_t *this, message_t *message)
391 {
392 cp_payload_t *cp;
393
394 if (!this->xauth)
395 {
396 this->xauth = load_method(this);
397 if (!this->xauth)
398 { /* send empty reply */
399 return NEED_MORE;
400 }
401 }
402 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
403 if (!cp)
404 {
405 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
406 return FAILED;
407 }
408 if (cp->get_type(cp) == CFG_REQUEST)
409 {
410 switch (this->xauth->process(this->xauth, cp, &this->cp))
411 {
412 case NEED_MORE:
413 return NEED_MORE;
414 case SUCCESS:
415 case FAILED:
416 default:
417 break;
418 }
419 this->cp = NULL;
420 return NEED_MORE;
421 }
422 if (cp->get_type(cp) == CFG_SET)
423 {
424 configuration_attribute_t *attribute;
425 enumerator_t *enumerator;
426
427 enumerator = cp->create_attribute_enumerator(cp);
428 while (enumerator->enumerate(enumerator, &attribute))
429 {
430 if (attribute->get_type(attribute) == XAUTH_STATUS)
431 {
432 this->status = attribute->get_value(attribute);
433 }
434 }
435 enumerator->destroy(enumerator);
436 if (this->status == XAUTH_OK &&
437 add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE))
438 {
439 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
440 this->xauth->get_identity(this->xauth));
441 }
442 else
443 {
444 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
445 this->xauth->get_identity(this->xauth));
446 }
447 }
448 this->identifier = cp->get_identifier(cp);
449 this->public.task.build = _build_r_ack;
450 return NEED_MORE;
451 }
452
453 METHOD(task_t, build_r, status_t,
454 private_xauth_t *this, message_t *message)
455 {
456 if (!this->cp)
457 { /* send empty reply if building data failed */
458 this->cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
459 }
460 message->add_payload(message, (payload_t *)this->cp);
461 this->cp = NULL;
462 return NEED_MORE;
463 }
464
465 METHOD(task_t, process_i, status_t,
466 private_xauth_t *this, message_t *message)
467 {
468 identification_t *id;
469 cp_payload_t *cp;
470
471 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
472 if (!cp)
473 {
474 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
475 return FAILED;
476 }
477 switch (this->xauth->process(this->xauth, cp, &this->cp))
478 {
479 case NEED_MORE:
480 return NEED_MORE;
481 case SUCCESS:
482 id = this->xauth->get_identity(this->xauth);
483 DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
484 if (add_auth_cfg(this, id, FALSE) && allowed(this))
485 {
486 this->status = XAUTH_OK;
487 }
488 break;
489 case FAILED:
490 DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
491 this->xauth->get_identity(this->xauth));
492 break;
493 default:
494 return FAILED;
495 }
496 this->public.task.build = _build_i_status;
497 this->public.task.process = _process_i_status;
498 return NEED_MORE;
499 }
500
501 METHOD(task_t, get_type, task_type_t,
502 private_xauth_t *this)
503 {
504 return TASK_XAUTH;
505 }
506
507 METHOD(task_t, migrate, void,
508 private_xauth_t *this, ike_sa_t *ike_sa)
509 {
510 DESTROY_IF(this->xauth);
511 DESTROY_IF(this->cp);
512
513 this->ike_sa = ike_sa;
514 this->xauth = NULL;
515 this->cp = NULL;
516 this->user = NULL;
517 this->status = XAUTH_FAILED;
518
519 if (this->initiator)
520 {
521 this->public.task.build = _build_i;
522 this->public.task.process = _process_i;
523 }
524 else
525 {
526 this->public.task.build = _build_r;
527 this->public.task.process = _process_r;
528 }
529 }
530
531 METHOD(xauth_t, queue_mode_config_push, void,
532 private_xauth_t *this)
533 {
534 this->mode_config_push = TRUE;
535 }
536
537 METHOD(task_t, destroy, void,
538 private_xauth_t *this)
539 {
540 DESTROY_IF(this->xauth);
541 DESTROY_IF(this->cp);
542 free(this);
543 }
544
545 /*
546 * Described in header.
547 */
548 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
549 {
550 private_xauth_t *this;
551
552 INIT(this,
553 .public = {
554 .task = {
555 .get_type = _get_type,
556 .migrate = _migrate,
557 .destroy = _destroy,
558 },
559 .queue_mode_config_push = _queue_mode_config_push,
560 },
561 .initiator = initiator,
562 .ike_sa = ike_sa,
563 .status = XAUTH_FAILED,
564 );
565
566 if (initiator)
567 {
568 this->public.task.build = _build_i;
569 this->public.task.process = _process_i;
570 }
571 else
572 {
573 this->public.task.build = _build_r;
574 this->public.task.process = _process_r;
575 }
576 return &this->public;
577 }