Enforce uniqueids=keep based on XAuth identity
[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 if (!this->initiator && this->user)
120 { /* use XAUTH username, if configured */
121 peer = this->user;
122 }
123 enumerator->destroy(enumerator);
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 named '%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 * Create auth config after successful authentication
185 */
186 static void add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
187 {
188 auth_cfg_t *auth;
189
190 auth = auth_cfg_create();
191 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
192 auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
193
194 this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
195 }
196
197 METHOD(task_t, build_i_status, status_t,
198 private_xauth_t *this, message_t *message)
199 {
200 cp_payload_t *cp;
201
202 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
203 cp->add_attribute(cp,
204 configuration_attribute_create_value(XAUTH_STATUS, this->status));
205
206 message->add_payload(message, (payload_t *)cp);
207
208 return NEED_MORE;
209 }
210
211 METHOD(task_t, build_i, status_t,
212 private_xauth_t *this, message_t *message)
213 {
214 if (!this->xauth)
215 {
216 cp_payload_t *cp;
217
218 this->xauth = load_method(this);
219 if (!this->xauth)
220 {
221 return FAILED;
222 }
223 if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
224 {
225 return FAILED;
226 }
227 message->add_payload(message, (payload_t *)cp);
228 return NEED_MORE;
229 }
230
231 if (this->cp)
232 { /* send previously generated payload */
233 message->add_payload(message, (payload_t *)this->cp);
234 this->cp = NULL;
235 return NEED_MORE;
236 }
237 return FAILED;
238 }
239
240 METHOD(task_t, build_r_ack, status_t,
241 private_xauth_t *this, message_t *message)
242 {
243 cp_payload_t *cp;
244
245 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
246 cp->set_identifier(cp, this->identifier);
247 cp->add_attribute(cp,
248 configuration_attribute_create_chunk(
249 CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
250
251 message->add_payload(message, (payload_t *)cp);
252
253 if (this->status == XAUTH_OK && allowed(this) && establish(this))
254 {
255 return SUCCESS;
256 }
257 return FAILED;
258 }
259
260 METHOD(task_t, process_r, status_t,
261 private_xauth_t *this, message_t *message)
262 {
263 cp_payload_t *cp;
264
265 if (!this->xauth)
266 {
267 this->xauth = load_method(this);
268 if (!this->xauth)
269 { /* send empty reply */
270 return NEED_MORE;
271 }
272 }
273 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
274 if (!cp)
275 {
276 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
277 return FAILED;
278 }
279 if (cp->get_type(cp) == CFG_REQUEST)
280 {
281 switch (this->xauth->process(this->xauth, cp, &this->cp))
282 {
283 case NEED_MORE:
284 return NEED_MORE;
285 case SUCCESS:
286 case FAILED:
287 default:
288 break;
289 }
290 this->cp = NULL;
291 return NEED_MORE;
292 }
293 if (cp->get_type(cp) == CFG_SET)
294 {
295 configuration_attribute_t *attribute;
296 enumerator_t *enumerator;
297
298 enumerator = cp->create_attribute_enumerator(cp);
299 while (enumerator->enumerate(enumerator, &attribute))
300 {
301 if (attribute->get_type(attribute) == XAUTH_STATUS)
302 {
303 this->status = attribute->get_value(attribute);
304 }
305 }
306 enumerator->destroy(enumerator);
307 if (this->status == XAUTH_OK)
308 {
309 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
310 this->xauth->get_identity(this->xauth));
311 add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE);
312 }
313 else
314 {
315 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
316 this->xauth->get_identity(this->xauth));
317 }
318 }
319 this->identifier = cp->get_identifier(cp);
320 this->public.task.build = _build_r_ack;
321 return NEED_MORE;
322 }
323
324 METHOD(task_t, build_r, status_t,
325 private_xauth_t *this, message_t *message)
326 {
327 if (!this->cp)
328 { /* send empty reply if building data failed */
329 this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
330 }
331 message->add_payload(message, (payload_t *)this->cp);
332 this->cp = NULL;
333 return NEED_MORE;
334 }
335
336 METHOD(task_t, process_i_status, status_t,
337 private_xauth_t *this, message_t *message)
338 {
339 cp_payload_t *cp;
340
341 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
342 if (!cp || cp->get_type(cp) != CFG_ACK)
343 {
344 DBG1(DBG_IKE, "received invalid XAUTH status response");
345 return FAILED;
346 }
347 if (this->status != XAUTH_OK)
348 {
349 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
350 return FAILED;
351 }
352 if (!establish(this))
353 {
354 return FAILED;
355 }
356 this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
357 lib->processor->queue_job(lib->processor, (job_t*)
358 adopt_children_job_create(this->ike_sa->get_id(this->ike_sa)));
359 return SUCCESS;
360 }
361
362 METHOD(task_t, process_i, status_t,
363 private_xauth_t *this, message_t *message)
364 {
365 identification_t *id;
366 cp_payload_t *cp;
367
368 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
369 if (!cp)
370 {
371 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
372 return FAILED;
373 }
374 switch (this->xauth->process(this->xauth, cp, &this->cp))
375 {
376 case NEED_MORE:
377 return NEED_MORE;
378 case SUCCESS:
379 id = this->xauth->get_identity(this->xauth);
380 if (this->user && !id->matches(id, this->user))
381 {
382 DBG1(DBG_IKE, "XAuth username '%Y' does not match to "
383 "configured username '%Y'", id, this->user);
384 break;
385 }
386 DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
387 add_auth_cfg(this, id, FALSE);
388 if (allowed(this))
389 {
390 this->status = XAUTH_OK;
391 }
392 break;
393 case FAILED:
394 DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
395 this->xauth->get_identity(this->xauth));
396 break;
397 default:
398 return FAILED;
399 }
400 this->public.task.build = _build_i_status;
401 this->public.task.process = _process_i_status;
402 return NEED_MORE;
403 }
404
405 METHOD(task_t, get_type, task_type_t,
406 private_xauth_t *this)
407 {
408 return TASK_XAUTH;
409 }
410
411 METHOD(task_t, migrate, void,
412 private_xauth_t *this, ike_sa_t *ike_sa)
413 {
414 DESTROY_IF(this->xauth);
415 DESTROY_IF(this->cp);
416
417 this->ike_sa = ike_sa;
418 this->xauth = NULL;
419 this->cp = NULL;
420 this->user = NULL;
421 this->status = XAUTH_FAILED;
422
423 if (this->initiator)
424 {
425 this->public.task.build = _build_i;
426 this->public.task.process = _process_i;
427 }
428 else
429 {
430 this->public.task.build = _build_r;
431 this->public.task.process = _process_r;
432 }
433 }
434
435 METHOD(task_t, destroy, void,
436 private_xauth_t *this)
437 {
438 DESTROY_IF(this->xauth);
439 DESTROY_IF(this->cp);
440 free(this);
441 }
442
443 /*
444 * Described in header.
445 */
446 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
447 {
448 private_xauth_t *this;
449
450 INIT(this,
451 .public = {
452 .task = {
453 .get_type = _get_type,
454 .migrate = _migrate,
455 .destroy = _destroy,
456 },
457 },
458 .initiator = initiator,
459 .ike_sa = ike_sa,
460 .status = XAUTH_FAILED,
461 );
462
463 if (initiator)
464 {
465 this->public.task.build = _build_i;
466 this->public.task.process = _process_i;
467 }
468 else
469 {
470 this->public.task.build = _build_r;
471 this->public.task.process = _process_r;
472 }
473 return &this->public;
474 }