added strongswan.conf option charon.reuse_iksa=no to create each CHILD_SA in a new...
[strongswan.git] / src / charon / control / controller.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 * $Id$
16 */
17
18 #include "controller.h"
19
20 #include <sys/types.h>
21 #include <dirent.h>
22 #include <sys/stat.h>
23 #include <dlfcn.h>
24
25 #include <daemon.h>
26 #include <library.h>
27
28
29 typedef struct private_controller_t private_controller_t;
30 typedef struct interface_bus_listener_t interface_bus_listener_t;
31
32 /**
33 * Private data of an stroke_t object.
34 */
35 struct private_controller_t {
36
37 /**
38 * Public part of stroke_t object.
39 */
40 controller_t public;
41
42 /**
43 * should we reuse established IKE_SAs when setting up CHILD_SAs?
44 */
45 bool reuse_ikesa;
46 };
47
48
49 /**
50 * helper struct to map bus listener callbacks to interface callbacks
51 */
52 struct interface_bus_listener_t {
53
54 /**
55 * public bus listener interface
56 */
57 bus_listener_t public;
58
59 /**
60 * status of the operation, return to method callers
61 */
62 status_t status;
63
64 /**
65 * IKE SA to filter log output
66 */
67 ike_sa_t *ike_sa;
68
69 /**
70 * interface callback (listener gets redirected to here)
71 */
72 controller_cb_t callback;
73
74 /**
75 * user parameter to pass to callback
76 */
77 void *param;
78
79 /**
80 * child configuration, used for initiate
81 */
82 child_cfg_t *child_cfg;
83
84 /**
85 * peer configuration, used for initiate
86 */
87 peer_cfg_t *peer_cfg;
88
89 /**
90 * unique ID, used for various methods
91 */
92 u_int32_t id;
93 };
94
95
96 typedef struct interface_job_t interface_job_t;
97
98 /**
99 * job for asynchronous listen operations
100 */
101 struct interface_job_t {
102 /**
103 * job interface
104 */
105 job_t public;
106
107 /**
108 * associated listener
109 */
110 interface_bus_listener_t listener;
111
112 /**
113 * back reference to controller
114 */
115 private_controller_t *controller;
116 };
117
118 /**
119 * Implementation of controller_t.create_ike_sa_iterator.
120 */
121 static enumerator_t* create_ike_sa_enumerator(controller_t *this)
122 {
123 return charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
124 }
125
126 /**
127 * listener function for initiate
128 */
129 static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
130 level_t level, int thread, ike_sa_t *ike_sa,
131 char* format, va_list args)
132 {
133 if (this->ike_sa == ike_sa)
134 {
135 if (!this->callback(this->param, signal, level, ike_sa, format, args))
136 {
137 return FALSE;
138 }
139 switch (signal)
140 {
141 case CHILD_UP_SUCCESS:
142 this->status = SUCCESS;
143 return FALSE;
144 case IKE_UP_FAILED:
145 case CHILD_UP_FAILED:
146 return FALSE;
147 default:
148 break;
149 }
150 }
151 return TRUE;
152 }
153
154 /**
155 * execute function for initiate
156 */
157 static status_t initiate_execute(interface_job_t *job)
158 {
159 ike_sa_t *ike_sa;
160 interface_bus_listener_t *listener = &job->listener;
161 peer_cfg_t *peer_cfg = listener->peer_cfg;
162
163 if (job->controller->reuse_ikesa)
164 {
165 ike_sa = charon->ike_sa_manager->checkout_by_config(
166 charon->ike_sa_manager, peer_cfg);
167 }
168 else
169 {
170 ike_sa = charon->ike_sa_manager->checkout_new(
171 charon->ike_sa_manager, TRUE);
172 }
173 listener->ike_sa = ike_sa;
174
175 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
176 {
177 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
178 }
179 peer_cfg->destroy(peer_cfg);
180
181 if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS)
182 {
183 return charon->ike_sa_manager->checkin_and_destroy(
184 charon->ike_sa_manager, ike_sa);
185 }
186 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
187 }
188
189 /**
190 * Implementation of controller_t.initiate.
191 */
192 static status_t initiate(private_controller_t *this,
193 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
194 controller_cb_t callback, void *param)
195 {
196 interface_job_t job;
197
198 job.listener.public.signal = (void*)initiate_listener;
199 job.listener.ike_sa = NULL;
200 job.listener.callback = callback;
201 job.listener.param = param;
202 job.listener.status = FAILED;
203 job.listener.child_cfg = child_cfg;
204 job.listener.peer_cfg = peer_cfg;
205 job.controller = this;
206 job.public.execute = (void*)initiate_execute;
207 job.public.destroy = nop;
208
209 if (callback == NULL)
210 {
211 return initiate_execute(&job);
212 }
213 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
214 return job.listener.status;
215 }
216
217 /**
218 * listener function for terminate_ike
219 */
220 static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal,
221 level_t level, int thread, ike_sa_t *ike_sa,
222 char* format, va_list args)
223 {
224 if (this->ike_sa == ike_sa)
225 {
226 if (!this->callback(this->param, signal, level, ike_sa, format, args))
227 {
228 return FALSE;
229 }
230 switch (signal)
231 {
232 case IKE_DOWN_SUCCESS:
233 this->status = SUCCESS;
234 return FALSE;
235 case IKE_DOWN_FAILED:
236 return FALSE;
237 default:
238 break;
239 }
240 }
241 return TRUE;
242 }
243
244 /**
245 * execute function for terminate_ike
246 */
247 static status_t terminate_ike_execute(interface_job_t *job)
248 {
249 ike_sa_t *ike_sa;
250 interface_bus_listener_t *listener = &job->listener;
251
252 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
253 listener->id, FALSE);
254 if (ike_sa == NULL)
255 {
256 SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with "
257 "ID %d not found", listener->id);
258 return NOT_FOUND;
259 }
260 listener->ike_sa = ike_sa;
261
262 if (ike_sa->delete(ike_sa) == DESTROY_ME)
263 {
264 return charon->ike_sa_manager->checkin_and_destroy(
265 charon->ike_sa_manager, ike_sa);
266 }
267 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
268 }
269
270 /**
271 * Implementation of controller_t.terminate_ike.
272 */
273 static status_t terminate_ike(private_controller_t *this, u_int32_t unique_id,
274 controller_cb_t callback, void *param)
275 {
276 interface_job_t job;
277
278 job.listener.public.signal = (void*)terminate_ike_listener;
279 job.listener.ike_sa = NULL;
280 job.listener.callback = callback;
281 job.listener.param = param;
282 job.listener.status = FAILED;
283 job.listener.id = unique_id;
284 job.controller = this;
285 job.public.execute = (void*)terminate_ike_execute;
286 job.public.destroy = nop;
287
288 if (callback == NULL)
289 {
290 return terminate_ike_execute(&job);
291 }
292 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
293 return job.listener.status;
294 }
295 /**
296 * listener function for terminate_child
297 */
298 static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal,
299 level_t level, int thread, ike_sa_t *ike_sa,
300 char* format, va_list args)
301 {
302 if (this->ike_sa == ike_sa)
303 {
304 if (!this->callback(this->param, signal, level, ike_sa, format, args))
305 {
306 return FALSE;
307 }
308 switch (signal)
309 {
310 case CHILD_DOWN_SUCCESS:
311 case IKE_DOWN_SUCCESS:
312 this->status = SUCCESS;
313 return FALSE;
314 case IKE_DOWN_FAILED:
315 case CHILD_DOWN_FAILED:
316 return FALSE;
317 default:
318 break;
319 }
320 }
321 return TRUE;
322 }
323
324 /**
325 * execute function for terminate_child
326 */
327 static status_t terminate_child_execute(interface_job_t *job)
328 {
329 ike_sa_t *ike_sa;
330 child_sa_t *child_sa;
331 iterator_t *iterator;
332 interface_bus_listener_t *listener = &job->listener;
333
334 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
335 listener->id, TRUE);
336 if (ike_sa == NULL)
337 {
338 SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with "
339 "ID %d not found", listener->id);
340 return NOT_FOUND;
341 }
342 listener->ike_sa = ike_sa;
343
344 iterator = ike_sa->create_child_sa_iterator(ike_sa);
345 while (iterator->iterate(iterator, (void**)&child_sa))
346 {
347 if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
348 child_sa->get_reqid(child_sa) == listener->id)
349 {
350 break;
351 }
352 child_sa = NULL;
353 }
354 iterator->destroy(iterator);
355
356 if (child_sa == NULL)
357 {
358 SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with "
359 "ID %d not found", listener->id);
360 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
361 return NOT_FOUND;
362 }
363
364 if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
365 child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
366 {
367 return charon->ike_sa_manager->checkin_and_destroy(
368 charon->ike_sa_manager, ike_sa);
369 }
370 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
371 }
372
373 /**
374 * Implementation of controller_t.terminate_child.
375 */
376 static status_t terminate_child(private_controller_t *this, u_int32_t reqid,
377 controller_cb_t callback, void *param)
378 {
379 interface_job_t job;
380
381 job.listener.public.signal = (void*)terminate_child_listener;
382 job.listener.ike_sa = NULL;
383 job.listener.callback = callback;
384 job.listener.param = param;
385 job.listener.status = FAILED;
386 job.listener.id = reqid;
387 job.controller = this;
388 job.public.execute = (void*)terminate_child_execute;
389 job.public.destroy = nop;
390
391 if (callback == NULL)
392 {
393 return terminate_child_execute(&job);
394 }
395 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
396 return job.listener.status;
397 }
398
399 /**
400 * listener function for route
401 */
402 static bool route_listener(interface_bus_listener_t *this, signal_t signal,
403 level_t level, int thread, ike_sa_t *ike_sa,
404 char* format, va_list args)
405 {
406 if (this->ike_sa == ike_sa)
407 {
408 if (!this->callback(this->param, signal, level, ike_sa, format, args))
409 {
410 return FALSE;
411 }
412 switch (signal)
413 {
414 case CHILD_ROUTE_SUCCESS:
415 this->status = SUCCESS;
416 return FALSE;
417 case CHILD_ROUTE_FAILED:
418 return FALSE;
419 default:
420 break;
421 }
422 }
423 return TRUE;
424 }
425
426 /**
427 * execute function for route
428 */
429 static status_t route_execute(interface_job_t *job)
430 {
431 ike_sa_t *ike_sa;
432 interface_bus_listener_t *listener = &job->listener;
433 peer_cfg_t *peer_cfg = listener->peer_cfg;
434
435 if (job->controller->reuse_ikesa)
436 {
437 ike_sa = charon->ike_sa_manager->checkout_by_config(
438 charon->ike_sa_manager, peer_cfg);
439 }
440 else
441 {
442 ike_sa = charon->ike_sa_manager->checkout_new(
443 charon->ike_sa_manager, TRUE);
444 }
445 listener->ike_sa = ike_sa;
446
447 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
448 {
449 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
450 }
451 if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME)
452 {
453 return charon->ike_sa_manager->checkin_and_destroy(
454 charon->ike_sa_manager, ike_sa);
455 }
456 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
457 }
458
459 /**
460 * Implementation of controller_t.route.
461 */
462 static status_t route(private_controller_t *this,
463 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
464 controller_cb_t callback, void *param)
465 {
466 interface_job_t job;
467
468 job.listener.public.signal = (void*)route_listener;
469 job.listener.ike_sa = NULL;
470 job.listener.callback = callback;
471 job.listener.param = param;
472 job.listener.status = FAILED;
473 job.listener.peer_cfg = peer_cfg;
474 job.listener.child_cfg = child_cfg;
475 job.controller = this;
476 job.public.execute = (void*)route_execute;
477 job.public.destroy = nop;
478
479 if (callback == NULL)
480 {
481 return route_execute(&job);
482 }
483 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
484 return job.listener.status;
485 }
486
487 /**
488 * listener function for unroute
489 */
490 static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
491 level_t level, int thread, ike_sa_t *ike_sa,
492 char* format, va_list args)
493 {
494 if (this->ike_sa == ike_sa)
495 {
496 if (!this->callback(this->param, signal, level, ike_sa, format, args))
497 {
498 return FALSE;
499 }
500 switch (signal)
501 {
502 case CHILD_UNROUTE_SUCCESS:
503 this->status = SUCCESS;
504 return FALSE;
505 case CHILD_UNROUTE_FAILED:
506 return FALSE;
507 default:
508 break;
509 }
510 }
511 return TRUE;
512 }
513 /**
514 * execute function for unroute
515 */
516 static status_t unroute_execute(interface_job_t *job)
517 {
518 ike_sa_t *ike_sa;
519 interface_bus_listener_t *listener = &job->listener;
520
521 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
522 listener->id, TRUE);
523 if (ike_sa == NULL)
524 {
525 SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with "
526 "ID %d not found", listener->id);
527 return NOT_FOUND;
528 }
529 listener->ike_sa = ike_sa;
530 if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME)
531 {
532 return charon->ike_sa_manager->checkin_and_destroy(
533 charon->ike_sa_manager, ike_sa);
534 }
535 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
536 }
537
538 /**
539 * Implementation of controller_t.unroute.
540 */
541 static status_t unroute(private_controller_t *this, u_int32_t reqid,
542 controller_cb_t callback, void *param)
543 {
544 interface_job_t job;
545
546 job.listener.public.signal = (void*)unroute_listener;
547 job.listener.ike_sa = NULL;
548 job.listener.callback = callback;
549 job.listener.param = param;
550 job.listener.status = FAILED;
551 job.listener.id = reqid;
552 job.controller = this;
553 job.public.execute = (void*)unroute_execute;
554 job.public.destroy = nop;
555
556 if (callback == NULL)
557 {
558 return unroute_execute(&job);
559 }
560 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
561 return job.listener.status;
562 }
563
564 /**
565 * See header
566 */
567 bool controller_cb_empty(void *param, signal_t signal, level_t level,
568 ike_sa_t *ike_sa, char *format, va_list args)
569 {
570 return TRUE;
571 }
572
573 /**
574 * Implementation of stroke_t.destroy.
575 */
576 static void destroy(private_controller_t *this)
577 {
578 free(this);
579 }
580
581 /*
582 * Described in header-file
583 */
584 controller_t *controller_create(void)
585 {
586 private_controller_t *this = malloc_thing(private_controller_t);
587
588 this->public.create_ike_sa_enumerator = (enumerator_t*(*)(controller_t*))create_ike_sa_enumerator;
589 this->public.initiate = (status_t(*)(controller_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate;
590 this->public.terminate_ike = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void*))terminate_ike;
591 this->public.terminate_child = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void *param))terminate_child;
592 this->public.route = (status_t(*)(controller_t*,peer_cfg_t*, child_cfg_t*,controller_cb_t,void*))route;
593 this->public.unroute = (status_t(*)(controller_t*,u_int32_t,controller_cb_t,void*))unroute;
594 this->public.destroy = (void (*)(controller_t*))destroy;
595
596 this->reuse_ikesa = lib->settings->get_bool(lib->settings,
597 "charon.reuse_ikesa", TRUE);
598 return &this->public;
599 }
600