Removed strayed code fragment
[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
16 #include "controller.h"
17
18 #include <sys/types.h>
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <dlfcn.h>
22
23 #include <daemon.h>
24 #include <library.h>
25
26
27 typedef struct private_controller_t private_controller_t;
28 typedef struct interface_listener_t interface_listener_t;
29
30 /**
31 * Private data of an stroke_t object.
32 */
33 struct private_controller_t {
34
35 /**
36 * Public part of stroke_t object.
37 */
38 controller_t public;
39 };
40
41 /**
42 * helper struct to map listener callbacks to interface callbacks
43 */
44 struct interface_listener_t {
45
46 /**
47 * public bus listener interface
48 */
49 listener_t public;
50
51 /**
52 * status of the operation, return to method callers
53 */
54 status_t status;
55
56 /**
57 * interface callback (listener gets redirected to here)
58 */
59 controller_cb_t callback;
60
61 /**
62 * user parameter to pass to callback
63 */
64 void *param;
65
66 /**
67 * child configuration, used for initiate
68 */
69 child_cfg_t *child_cfg;
70
71 /**
72 * peer configuration, used for initiate
73 */
74 peer_cfg_t *peer_cfg;
75
76 /**
77 * IKE_SA to handle
78 */
79 ike_sa_t *ike_sa;
80
81 /**
82 * CHILD_SA to handle
83 */
84 child_sa_t *child_sa;
85
86 /**
87 * unique ID, used for various methods
88 */
89 u_int32_t id;
90 };
91
92
93 typedef struct interface_job_t interface_job_t;
94
95 /**
96 * job for asynchronous listen operations
97 */
98 struct interface_job_t {
99 /**
100 * job interface
101 */
102 job_t public;
103
104 /**
105 * associated listener
106 */
107 interface_listener_t listener;
108 };
109
110 /**
111 * listener log function
112 */
113 static bool listener_log(interface_listener_t *this, debug_t group,
114 level_t level, int thread, ike_sa_t *ike_sa,
115 char* format, va_list args)
116 {
117 if (this->ike_sa == ike_sa)
118 {
119 if (!this->callback(this->param, group, level, ike_sa, format, args))
120 {
121 return FALSE;
122 }
123 }
124 return TRUE;
125 }
126
127 /**
128 * Implementation of listener_t.ike_state_change
129 */
130 static bool listener_ike_state(interface_listener_t *this, ike_sa_t *ike_sa,
131 ike_sa_state_t state)
132 {
133 if (this->ike_sa == ike_sa)
134 {
135 switch (state)
136 {
137 #ifdef ME
138 case IKE_ESTABLISHED:
139 { /* mediation connections are complete without CHILD_SA */
140 peer_cfg_t *peer_cfg = ike_sa->get_peer_cfg(ike_sa);
141
142 if (peer_cfg->is_mediation(peer_cfg))
143 {
144 this->status = SUCCESS;
145 return FALSE;
146 }
147 break;
148 }
149 #endif /* ME */
150 case IKE_DESTROYING:
151 if (ike_sa->get_state(ike_sa) == IKE_DELETING)
152 { /* proper termination */
153 this->status = SUCCESS;
154 }
155 return FALSE;
156 default:
157 break;
158 }
159 }
160 return TRUE;
161 }
162
163 /**
164 * Implementation of listener_t.child_state_change
165 */
166 static bool listener_child_state(interface_listener_t *this, ike_sa_t *ike_sa,
167 child_sa_t *child_sa, child_sa_state_t state)
168 {
169 if (this->ike_sa == ike_sa)
170 {
171 switch (state)
172 {
173 case CHILD_INSTALLED:
174 this->status = SUCCESS;
175 return FALSE;
176 case CHILD_DESTROYING:
177 switch (child_sa->get_state(child_sa))
178 {
179 case CHILD_DELETING:
180 /* proper delete */
181 this->status = SUCCESS;
182 break;
183 default:
184 break;
185 }
186 return FALSE;
187 default:
188 break;
189 }
190 }
191 return TRUE;
192 }
193
194 /**
195 * cleanup job if job is never executed
196 */
197 static void recheckin(interface_job_t *job)
198 {
199 if (job->listener.ike_sa)
200 {
201 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
202 job->listener.ike_sa);
203 }
204 }
205
206 /**
207 * Implementation of controller_t.create_ike_sa_iterator.
208 */
209 static enumerator_t* create_ike_sa_enumerator(controller_t *this)
210 {
211 return charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
212 }
213
214 /**
215 * execute function for initiate
216 */
217 static status_t initiate_execute(interface_job_t *job)
218 {
219 ike_sa_t *ike_sa;
220 interface_listener_t *listener = &job->listener;
221 peer_cfg_t *peer_cfg = listener->peer_cfg;
222
223 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
224 peer_cfg);
225 listener->ike_sa = ike_sa;
226
227 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
228 {
229 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
230 }
231 peer_cfg->destroy(peer_cfg);
232
233 if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
234 {
235 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
236 return SUCCESS;
237 }
238 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
239 return FAILED;
240 }
241
242 /**
243 * Implementation of controller_t.initiate.
244 */
245 static status_t initiate(private_controller_t *this,
246 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
247 controller_cb_t callback, void *param)
248 {
249 interface_job_t job = {
250 .listener = {
251 .public = {
252 .log = (void*)listener_log,
253 .ike_state_change = (void*)listener_ike_state,
254 .child_state_change = (void*)listener_child_state,
255 },
256 .callback = callback,
257 .param = param,
258 .status = FAILED,
259 .child_cfg = child_cfg,
260 .peer_cfg = peer_cfg,
261 },
262 .public = {
263 .execute = (void*)initiate_execute,
264 .destroy = (void*)recheckin,
265 },
266 };
267 if (callback == NULL)
268 {
269 return initiate_execute(&job);
270 }
271 charon->bus->listen(charon->bus, &job.listener.public, (job_t*)&job);
272 return job.listener.status;
273 }
274
275 /**
276 * execute function for terminate_ike
277 */
278 static status_t terminate_ike_execute(interface_job_t *job)
279 {
280 interface_listener_t *listener = &job->listener;
281 ike_sa_t *ike_sa = listener->ike_sa;
282
283 charon->bus->set_sa(charon->bus, ike_sa);
284
285 if (ike_sa->delete(ike_sa) != DESTROY_ME)
286 {
287 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
288 /* delete failed */
289 return FAILED;
290 }
291 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
292 return SUCCESS;
293 }
294
295 /**
296 * Implementation of controller_t.terminate_ike.
297 */
298 static status_t terminate_ike(controller_t *this, u_int32_t unique_id,
299 controller_cb_t callback, void *param)
300 {
301 ike_sa_t *ike_sa;
302 interface_job_t job = {
303 .listener = {
304 .public = {
305 .log = (void*)listener_log,
306 .ike_state_change = (void*)listener_ike_state,
307 .child_state_change = (void*)listener_child_state,
308 },
309 .callback = callback,
310 .param = param,
311 .status = FAILED,
312 .id = unique_id,
313 },
314 .public = {
315 .execute = (void*)terminate_ike_execute,
316 .destroy = (void*)recheckin,
317 },
318 };
319
320 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
321 unique_id, FALSE);
322 if (ike_sa == NULL)
323 {
324 DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id);
325 return NOT_FOUND;
326 }
327 job.listener.ike_sa = ike_sa;
328
329 if (callback == NULL)
330 {
331 return terminate_ike_execute(&job);
332 }
333 charon->bus->listen(charon->bus, &job.listener.public, (job_t*)&job);
334 return job.listener.status;
335 }
336
337 /**
338 * execute function for terminate_child
339 */
340 static status_t terminate_child_execute(interface_job_t *job)
341 {
342 interface_listener_t *listener = &job->listener;
343 ike_sa_t *ike_sa = listener->ike_sa;
344 child_sa_t *child_sa = listener->child_sa;
345
346 charon->bus->set_sa(charon->bus, ike_sa);
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 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
351 return SUCCESS;
352 }
353 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
354 return FAILED;
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 * See header
425 */
426 bool controller_cb_empty(void *param, debug_t group, level_t level,
427 ike_sa_t *ike_sa, char *format, va_list args)
428 {
429 return TRUE;
430 }
431
432 /**
433 * Implementation of stroke_t.destroy.
434 */
435 static void destroy(private_controller_t *this)
436 {
437 free(this);
438 }
439
440 /*
441 * Described in header-file
442 */
443 controller_t *controller_create(void)
444 {
445 private_controller_t *this = malloc_thing(private_controller_t);
446
447 this->public.create_ike_sa_enumerator = (enumerator_t*(*)(controller_t*))create_ike_sa_enumerator;
448 this->public.initiate = (status_t(*)(controller_t*,peer_cfg_t*,child_cfg_t*,controller_cb_t,void*))initiate;
449 this->public.terminate_ike = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void*))terminate_ike;
450 this->public.terminate_child = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void *param))terminate_child;
451 this->public.destroy = (void (*)(controller_t*))destroy;
452
453 return &this->public;
454 }
455