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