ike_sa_manager enumerable, not iterable
[strongswan.git] / src / charon / plugins / stroke / stroke_control.c
1 /*
2 * Copyright (C) 2008 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 "stroke_control.h"
19
20 #include <daemon.h>
21
22 typedef struct private_stroke_control_t private_stroke_control_t;
23
24 /**
25 * private data of stroke_control
26 */
27 struct private_stroke_control_t {
28
29 /**
30 * public functions
31 */
32 stroke_control_t public;
33 };
34
35
36 typedef struct stroke_log_info_t stroke_log_info_t;
37
38 /**
39 * helper struct to say what and where to log when using controller callback
40 */
41 struct stroke_log_info_t {
42
43 /**
44 * level to log up to
45 */
46 level_t level;
47
48 /**
49 * where to write log
50 */
51 FILE* out;
52 };
53
54 /**
55 * logging to the stroke interface
56 */
57 static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level,
58 ike_sa_t *ike_sa, char *format, va_list args)
59 {
60 if (level <= info->level)
61 {
62 if (vfprintf(info->out, format, args) < 0 ||
63 fprintf(info->out, "\n") < 0 ||
64 fflush(info->out) != 0)
65 {
66 return FALSE;
67 }
68 }
69 return TRUE;
70 }
71
72 /**
73 * get the child_cfg with the same name as the peer cfg
74 */
75 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
76 {
77 child_cfg_t *current, *found = NULL;
78 enumerator_t *enumerator;
79
80 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
81 while (enumerator->enumerate(enumerator, &current))
82 {
83 if (streq(current->get_name(current), name))
84 {
85 found = current;
86 found->get_ref(found);
87 break;
88 }
89 }
90 enumerator->destroy(enumerator);
91 return found;
92 }
93
94 /**
95 * Implementation of stroke_control_t.initiate.
96 */
97 static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
98 {
99 peer_cfg_t *peer_cfg;
100 child_cfg_t *child_cfg;
101 stroke_log_info_t info;
102
103 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
104 msg->initiate.name);
105 if (peer_cfg == NULL)
106 {
107 DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name);
108 return;
109 }
110 if (peer_cfg->get_ike_version(peer_cfg) != 2)
111 {
112 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
113 peer_cfg->get_ike_version(peer_cfg));
114 peer_cfg->destroy(peer_cfg);
115 return;
116 }
117
118 child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
119 if (child_cfg == NULL)
120 {
121 DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name);
122 peer_cfg->destroy(peer_cfg);
123 return;
124 }
125
126 if (msg->output_verbosity < 0)
127 {
128 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
129 NULL, NULL);
130 }
131 else
132 {
133 info.out = out;
134 info.level = msg->output_verbosity;
135 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
136 (controller_cb_t)stroke_log, &info);
137 }
138 }
139
140 /**
141 * Implementation of stroke_control_t.terminate.
142 */
143 static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
144 {
145 char *string, *pos = NULL, *name = NULL;
146 u_int32_t id = 0;
147 bool child;
148 int len;
149 ike_sa_t *ike_sa;
150 enumerator_t *enumerator;
151 stroke_log_info_t info;
152
153 string = msg->terminate.name;
154
155 len = strlen(string);
156 if (len < 1)
157 {
158 DBG1(DBG_CFG, "error parsing string");
159 return;
160 }
161 switch (string[len-1])
162 {
163 case '}':
164 child = TRUE;
165 pos = strchr(string, '{');
166 break;
167 case ']':
168 child = FALSE;
169 pos = strchr(string, '[');
170 break;
171 default:
172 name = string;
173 child = FALSE;
174 break;
175 }
176
177 if (name)
178 {
179 /* is a single name */
180 }
181 else if (pos == string + len - 2)
182 { /* is name[] or name{} */
183 string[len-2] = '\0';
184 name = string;
185 }
186 else
187 { /* is name[123] or name{23} */
188 string[len-1] = '\0';
189 id = atoi(pos + 1);
190 if (id == 0)
191 {
192 DBG1(DBG_CFG, "error parsing string");
193 return;
194 }
195 }
196
197 info.out = out;
198 info.level = msg->output_verbosity;
199
200 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
201 while (enumerator->enumerate(enumerator, &ike_sa))
202 {
203 child_sa_t *child_sa;
204 iterator_t *children;
205
206 if (child)
207 {
208 children = ike_sa->create_child_sa_iterator(ike_sa);
209 while (children->iterate(children, (void**)&child_sa))
210 {
211 if ((name && streq(name, child_sa->get_name(child_sa))) ||
212 (id && id == child_sa->get_reqid(child_sa)))
213 {
214 id = child_sa->get_reqid(child_sa);
215 children->destroy(children);
216 enumerator->destroy(enumerator);
217
218 charon->controller->terminate_child(charon->controller, id,
219 (controller_cb_t)stroke_log, &info);
220 return;
221 }
222 }
223 children->destroy(children);
224 }
225 else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
226 (id && id == ike_sa->get_unique_id(ike_sa)))
227 {
228 id = ike_sa->get_unique_id(ike_sa);
229 /* unlock manager first */
230 enumerator->destroy(enumerator);
231
232 charon->controller->terminate_ike(charon->controller, id,
233 (controller_cb_t)stroke_log, &info);
234 return;
235 }
236
237 }
238 enumerator->destroy(enumerator);
239 DBG1(DBG_CFG, "no such SA found");
240 }
241
242 /**
243 * Implementation of stroke_control_t.route.
244 */
245 static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
246 {
247 peer_cfg_t *peer_cfg;
248 child_cfg_t *child_cfg;
249 stroke_log_info_t info;
250
251 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
252 msg->route.name);
253 if (peer_cfg == NULL)
254 {
255 fprintf(out, "no config named '%s'\n", msg->route.name);
256 return;
257 }
258 if (peer_cfg->get_ike_version(peer_cfg) != 2)
259 {
260 peer_cfg->destroy(peer_cfg);
261 return;
262 }
263
264 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
265 if (child_cfg == NULL)
266 {
267 fprintf(out, "no child config named '%s'\n", msg->route.name);
268 peer_cfg->destroy(peer_cfg);
269 return;
270 }
271
272 info.out = out;
273 info.level = msg->output_verbosity;
274 charon->controller->route(charon->controller, peer_cfg, child_cfg,
275 (controller_cb_t)stroke_log, &info);
276 peer_cfg->destroy(peer_cfg);
277 child_cfg->destroy(child_cfg);
278 }
279
280 /**
281 * Implementation of stroke_control_t.unroute.
282 */
283 static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
284 {
285 char *name;
286 ike_sa_t *ike_sa;
287 enumerator_t *enumerator;
288 stroke_log_info_t info;
289
290 name = msg->terminate.name;
291
292 info.out = out;
293 info.level = msg->output_verbosity;
294
295 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
296 while (enumerator->enumerate(enumerator, &ike_sa))
297 {
298 child_sa_t *child_sa;
299 iterator_t *children;
300 u_int32_t id;
301
302 children = ike_sa->create_child_sa_iterator(ike_sa);
303 while (children->iterate(children, (void**)&child_sa))
304 {
305 if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
306 streq(name, child_sa->get_name(child_sa)))
307 {
308 id = child_sa->get_reqid(child_sa);
309 children->destroy(children);
310 enumerator->destroy(enumerator);
311 charon->controller->unroute(charon->controller, id,
312 (controller_cb_t)stroke_log, &info);
313 return;
314 }
315 }
316 children->destroy(children);
317 }
318 enumerator->destroy(enumerator);
319 DBG1(DBG_CFG, "no such SA found");
320 }
321
322 /**
323 * Implementation of stroke_control_t.destroy
324 */
325 static void destroy(private_stroke_control_t *this)
326 {
327 free(this);
328 }
329
330 /*
331 * see header file
332 */
333 stroke_control_t *stroke_control_create()
334 {
335 private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
336
337 this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
338 this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
339 this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
340 this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
341 this->public.destroy = (void(*)(stroke_control_t*))destroy;
342
343 return &this->public;
344 }
345