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