c0c91574c784513ca38e45eac448aa4d1a9d8785
[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 #include <sa/ikev1/tasks/mode_config.h>
23
24 typedef struct private_xauth_t private_xauth_t;
25
26 /**
27 * Status types exchanged
28 */
29 typedef enum {
30 XAUTH_FAILED = 0,
31 XAUTH_OK = 1,
32 } xauth_status_t;
33
34 /**
35 * Private members of a xauth_t task.
36 */
37 struct private_xauth_t {
38
39 /**
40 * Public methods and task_t interface.
41 */
42 xauth_t public;
43
44 /**
45 * Assigned IKE_SA.
46 */
47 ike_sa_t *ike_sa;
48
49 /**
50 * Are we the XAUTH initiator?
51 */
52 bool initiator;
53
54 /**
55 * XAuth backend to use
56 */
57 xauth_method_t *xauth;
58
59 /**
60 * XAuth username
61 */
62 identification_t *user;
63
64 /**
65 * Generated configuration payload
66 */
67 cp_payload_t *cp;
68
69 /**
70 * received identifier
71 */
72 u_int16_t identifier;
73
74 /**
75 * status of Xauth exchange
76 */
77 xauth_status_t status;
78
79 /**
80 * Queue a Mode Config Push mode after completing XAuth?
81 */
82 bool mode_config_push;
83 };
84
85 /**
86 * Load XAuth backend
87 */
88 static xauth_method_t *load_method(private_xauth_t* this)
89 {
90 identification_t *server, *peer;
91 enumerator_t *enumerator;
92 xauth_method_t *xauth;
93 xauth_role_t role;
94 peer_cfg_t *peer_cfg;
95 auth_cfg_t *auth;
96 char *name;
97
98 if (this->initiator)
99 {
100 server = this->ike_sa->get_my_id(this->ike_sa);
101 peer = this->ike_sa->get_other_id(this->ike_sa);
102 role = XAUTH_SERVER;
103 }
104 else
105 {
106 peer = this->ike_sa->get_my_id(this->ike_sa);
107 server = this->ike_sa->get_other_id(this->ike_sa);
108 role = XAUTH_PEER;
109 }
110 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
111 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
112 if (!enumerator->enumerate(enumerator, &auth) ||
113 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
114 {
115 if (!enumerator->enumerate(enumerator, &auth) ||
116 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
117 {
118 DBG1(DBG_CFG, "no XAuth authentication round found");
119 enumerator->destroy(enumerator);
120 return NULL;
121 }
122 }
123 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
124 this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
125 enumerator->destroy(enumerator);
126 if (!this->initiator && this->user)
127 { /* use XAUTH username, if configured */
128 peer = this->user;
129 }
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 for '%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 * Check if we are compliant to a given peer config
191 */
192 static bool is_compliant(private_xauth_t *this, peer_cfg_t *peer_cfg, bool log)
193 {
194 bool complies = TRUE;
195 enumerator_t *e1, *e2;
196 auth_cfg_t *c1, *c2;
197
198 e1 = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
199 e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE);
200 while (e1->enumerate(e1, &c1))
201 {
202 if (!e2->enumerate(e2, &c2) || !c2->complies(c2, c1, log))
203 {
204 complies = FALSE;
205 break;
206 }
207 }
208 e1->destroy(e1);
209 e2->destroy(e2);
210
211 return complies;
212 }
213
214 /**
215 * Check if we are compliant to current config, switch to another if not
216 */
217 static bool select_compliant_config(private_xauth_t *this)
218 {
219 peer_cfg_t *peer_cfg = NULL, *old, *current;
220 identification_t *my_id, *other_id;
221 host_t *my_host, *other_host;
222 enumerator_t *enumerator;
223 bool aggressive;
224
225 old = this->ike_sa->get_peer_cfg(this->ike_sa);
226 if (is_compliant(this, old, TRUE))
227 { /* current config is fine */
228 return TRUE;
229 }
230 DBG1(DBG_CFG, "selected peer config '%s' inacceptable",
231 old->get_name(old));
232 aggressive = old->use_aggressive(old);
233
234 my_host = this->ike_sa->get_my_host(this->ike_sa);
235 other_host = this->ike_sa->get_other_host(this->ike_sa);
236 my_id = this->ike_sa->get_my_id(this->ike_sa);
237 other_id = this->ike_sa->get_other_id(this->ike_sa);
238 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
239 my_host, other_host, my_id, other_id, IKEV1);
240 while (enumerator->enumerate(enumerator, &current))
241 {
242 if (!current->equals(current, old) &&
243 current->use_aggressive(current) == aggressive &&
244 is_compliant(this, current, FALSE))
245 {
246 peer_cfg = current;
247 break;
248 }
249 }
250 if (peer_cfg)
251 {
252 DBG1(DBG_CFG, "switching to peer config '%s'",
253 peer_cfg->get_name(peer_cfg));
254 this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
255 }
256 else
257 {
258 DBG1(DBG_CFG, "no alternative config found");
259 }
260 enumerator->destroy(enumerator);
261
262 return peer_cfg != NULL;
263 }
264
265 /**
266 * Create auth config after successful authentication
267 */
268 static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
269 {
270 auth_cfg_t *auth;
271
272 auth = auth_cfg_create();
273 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
274 if (id)
275 {
276 auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
277 }
278 auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE);
279 this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
280
281 return select_compliant_config(this);
282 }
283
284 METHOD(task_t, build_i_status, status_t,
285 private_xauth_t *this, message_t *message)
286 {
287 cp_payload_t *cp;
288
289 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
290 cp->add_attribute(cp,
291 configuration_attribute_create_value(XAUTH_STATUS, this->status));
292
293 message->add_payload(message, (payload_t *)cp);
294
295 return NEED_MORE;
296 }
297
298 METHOD(task_t, process_i_status, status_t,
299 private_xauth_t *this, message_t *message)
300 {
301 cp_payload_t *cp;
302 adopt_children_job_t *job;
303
304 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
305 if (!cp || cp->get_type(cp) != CFG_ACK)
306 {
307 DBG1(DBG_IKE, "received invalid XAUTH status response");
308 return FAILED;
309 }
310 if (this->status != XAUTH_OK)
311 {
312 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
313 return FAILED;
314 }
315 if (!establish(this))
316 {
317 return FAILED;
318 }
319 this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
320 job = adopt_children_job_create(this->ike_sa->get_id(this->ike_sa));
321 if (this->mode_config_push)
322 {
323 job->queue_task(job,
324 (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
325 }
326 lib->processor->queue_job(lib->processor, (job_t*)job);
327 return SUCCESS;
328 }
329
330 METHOD(task_t, build_i, status_t,
331 private_xauth_t *this, message_t *message)
332 {
333 if (!this->xauth)
334 {
335 cp_payload_t *cp = NULL;
336
337 this->xauth = load_method(this);
338 if (!this->xauth)
339 {
340 return FAILED;
341 }
342 switch (this->xauth->initiate(this->xauth, &cp))
343 {
344 case NEED_MORE:
345 break;
346 case SUCCESS:
347 DESTROY_IF(cp);
348 if (add_auth_cfg(this, NULL, FALSE) && allowed(this))
349 {
350 this->status = XAUTH_OK;
351 }
352 this->public.task.process = _process_i_status;
353 return build_i_status(this, message);
354 default:
355 return FAILED;
356 }
357 message->add_payload(message, (payload_t *)cp);
358 return NEED_MORE;
359 }
360
361 if (this->cp)
362 { /* send previously generated payload */
363 message->add_payload(message, (payload_t *)this->cp);
364 this->cp = NULL;
365 return NEED_MORE;
366 }
367 return FAILED;
368 }
369
370 METHOD(task_t, build_r_ack, status_t,
371 private_xauth_t *this, message_t *message)
372 {
373 cp_payload_t *cp;
374
375 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
376 cp->set_identifier(cp, this->identifier);
377 cp->add_attribute(cp,
378 configuration_attribute_create_chunk(
379 PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_STATUS, chunk_empty));
380
381 message->add_payload(message, (payload_t *)cp);
382
383 if (this->status == XAUTH_OK && allowed(this) && establish(this))
384 {
385 return SUCCESS;
386 }
387 return FAILED;
388 }
389
390 METHOD(task_t, process_r, status_t,
391 private_xauth_t *this, message_t *message)
392 {
393 cp_payload_t *cp;
394
395 if (!this->xauth)
396 {
397 this->xauth = load_method(this);
398 if (!this->xauth)
399 { /* send empty reply */
400 return NEED_MORE;
401 }
402 }
403 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
404 if (!cp)
405 {
406 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
407 return FAILED;
408 }
409 if (cp->get_type(cp) == CFG_REQUEST)
410 {
411 switch (this->xauth->process(this->xauth, cp, &this->cp))
412 {
413 case NEED_MORE:
414 return NEED_MORE;
415 case SUCCESS:
416 case FAILED:
417 default:
418 break;
419 }
420 this->cp = NULL;
421 return NEED_MORE;
422 }
423 if (cp->get_type(cp) == CFG_SET)
424 {
425 configuration_attribute_t *attribute;
426 enumerator_t *enumerator;
427
428 enumerator = cp->create_attribute_enumerator(cp);
429 while (enumerator->enumerate(enumerator, &attribute))
430 {
431 if (attribute->get_type(attribute) == XAUTH_STATUS)
432 {
433 this->status = attribute->get_value(attribute);
434 }
435 }
436 enumerator->destroy(enumerator);
437 if (this->status == XAUTH_OK &&
438 add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE))
439 {
440 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
441 this->xauth->get_identity(this->xauth));
442 }
443 else
444 {
445 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
446 this->xauth->get_identity(this->xauth));
447 }
448 }
449 this->identifier = cp->get_identifier(cp);
450 this->public.task.build = _build_r_ack;
451 return NEED_MORE;
452 }
453
454 METHOD(task_t, build_r, status_t,
455 private_xauth_t *this, message_t *message)
456 {
457 if (!this->cp)
458 { /* send empty reply if building data failed */
459 this->cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
460 }
461 message->add_payload(message, (payload_t *)this->cp);
462 this->cp = NULL;
463 return NEED_MORE;
464 }
465
466 METHOD(task_t, process_i, status_t,
467 private_xauth_t *this, message_t *message)
468 {
469 identification_t *id;
470 cp_payload_t *cp;
471
472 cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
473 if (!cp)
474 {
475 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
476 return FAILED;
477 }
478 switch (this->xauth->process(this->xauth, cp, &this->cp))
479 {
480 case NEED_MORE:
481 return NEED_MORE;
482 case SUCCESS:
483 id = this->xauth->get_identity(this->xauth);
484 DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
485 if (add_auth_cfg(this, id, FALSE) && allowed(this))
486 {
487 this->status = XAUTH_OK;
488 }
489 break;
490 case FAILED:
491 DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
492 this->xauth->get_identity(this->xauth));
493 break;
494 default:
495 return FAILED;
496 }
497 this->public.task.build = _build_i_status;
498 this->public.task.process = _process_i_status;
499 return NEED_MORE;
500 }
501
502 METHOD(task_t, get_type, task_type_t,
503 private_xauth_t *this)
504 {
505 return TASK_XAUTH;
506 }
507
508 METHOD(task_t, migrate, void,
509 private_xauth_t *this, ike_sa_t *ike_sa)
510 {
511 DESTROY_IF(this->xauth);
512 DESTROY_IF(this->cp);
513
514 this->ike_sa = ike_sa;
515 this->xauth = NULL;
516 this->cp = NULL;
517 this->user = NULL;
518 this->status = XAUTH_FAILED;
519
520 if (this->initiator)
521 {
522 this->public.task.build = _build_i;
523 this->public.task.process = _process_i;
524 }
525 else
526 {
527 this->public.task.build = _build_r;
528 this->public.task.process = _process_r;
529 }
530 }
531
532 METHOD(xauth_t, queue_mode_config_push, void,
533 private_xauth_t *this)
534 {
535 this->mode_config_push = TRUE;
536 }
537
538 METHOD(task_t, destroy, void,
539 private_xauth_t *this)
540 {
541 DESTROY_IF(this->xauth);
542 DESTROY_IF(this->cp);
543 free(this);
544 }
545
546 /*
547 * Described in header.
548 */
549 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
550 {
551 private_xauth_t *this;
552
553 INIT(this,
554 .public = {
555 .task = {
556 .get_type = _get_type,
557 .migrate = _migrate,
558 .destroy = _destroy,
559 },
560 .queue_mode_config_push = _queue_mode_config_push,
561 },
562 .initiator = initiator,
563 .ike_sa = ike_sa,
564 .status = XAUTH_FAILED,
565 );
566
567 if (initiator)
568 {
569 this->public.task.build = _build_i;
570 this->public.task.process = _process_i;
571 }
572 else
573 {
574 this->public.task.build = _build_r;
575 this->public.task.process = _process_r;
576 }
577 return &this->public;
578 }