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