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