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