added close_action as a seperate config option to dpd_action
[strongswan.git] / src / charon / plugins / sql / sql_config.c
1 /*
2 * Copyright (C) 2006-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 <string.h>
19
20 #include "sql_config.h"
21
22 #include <daemon.h>
23
24 typedef struct private_sql_config_t private_sql_config_t;
25
26 /**
27 * Private data of an sql_config_t object
28 */
29 struct private_sql_config_t {
30
31 /**
32 * Public part
33 */
34 sql_config_t public;
35
36 /**
37 * database connection
38 */
39 database_t *db;
40 };
41
42 /**
43 * forward declaration
44 */
45 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
46 identification_t *me, identification_t *other);
47
48 /**
49 * build a traffic selector from a SQL query
50 */
51 static traffic_selector_t *build_traffic_selector(private_sql_config_t *this,
52 enumerator_t *e, bool *local)
53 {
54 int type, protocol, start_port, end_port;
55 chunk_t start_addr, end_addr;
56 traffic_selector_t *ts;
57 enum {
58 TS_LOCAL = 0,
59 TS_REMOTE = 1,
60 TS_LOCAL_DYNAMIC = 2,
61 TS_REMOTE_DYNAMIC = 3,
62 } kind;
63
64 while (e->enumerate(e, &kind, &type, &protocol,
65 &start_addr, &end_addr, &start_port, &end_port))
66 {
67 *local = FALSE;
68 switch (kind)
69 {
70 case TS_LOCAL:
71 *local = TRUE;
72 /* FALL */
73 case TS_REMOTE:
74 ts = traffic_selector_create_from_bytes(protocol, type,
75 start_addr, start_port, end_addr, end_port);
76 break;
77 case TS_LOCAL_DYNAMIC:
78 *local = TRUE;
79 /* FALL */
80 case TS_REMOTE_DYNAMIC:
81 ts = traffic_selector_create_dynamic(protocol,
82 start_port, end_port);
83 break;
84 default:
85 continue;
86 }
87 if (ts)
88 {
89 return ts;
90 }
91 }
92 return NULL;
93 }
94
95 /**
96 * Add traffic selectors to a child config
97 */
98 static void add_traffic_selectors(private_sql_config_t *this,
99 child_cfg_t *child, int id)
100 {
101 enumerator_t *e;
102 traffic_selector_t *ts;
103 bool local;
104
105 e = this->db->query(this->db,
106 "SELECT kind, type, protocol, "
107 "start_addr, end_addr, start_port, end_port "
108 "FROM traffic_selectors JOIN child_config_traffic_selector "
109 "ON id = traffic_selector WHERE child_cfg = ?",
110 DB_INT, id,
111 DB_INT, DB_INT, DB_INT,
112 DB_BLOB, DB_BLOB, DB_INT, DB_INT);
113 if (e)
114 {
115 while ((ts = build_traffic_selector(this, e, &local)))
116 {
117 child->add_traffic_selector(child, local, ts);
118 }
119 e->destroy(e);
120 }
121 }
122
123 /**
124 * build a Child configuration from a SQL query
125 */
126 static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
127 {
128 int id, lifetime, rekeytime, jitter, hostaccess, mode;
129 char *name, *updown;
130 child_cfg_t *child_cfg;
131
132 if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter,
133 &updown, &hostaccess, &mode))
134 {
135 child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter,
136 updown, hostaccess, mode,
137 ACTION_NONE, ACTION_NONE);
138 /* TODO: read proposal from db */
139 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
140 add_traffic_selectors(this, child_cfg, id);
141 return child_cfg;
142 }
143 return NULL;
144 }
145
146 /**
147 * Add child configs to peer config
148 */
149 static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id)
150 {
151 enumerator_t *e;
152 child_cfg_t *child_cfg;
153
154 e = this->db->query(this->db,
155 "SELECT id, name, lifetime, rekeytime, jitter, "
156 "updown, hostaccess, mode "
157 "FROM child_configs JOIN peer_config_child_config ON id = child_cfg "
158 "WHERE peer_cfg = ?",
159 DB_INT, id,
160 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT,
161 DB_TEXT, DB_INT, DB_INT);
162 if (e)
163 {
164 while ((child_cfg = build_child_cfg(this, e)))
165 {
166 peer->add_child_cfg(peer, child_cfg);
167 }
168 e->destroy(e);
169 }
170 }
171
172 /**
173 * build a ike configuration from a SQL query
174 */
175 static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
176 host_t *my_host, host_t *other_host)
177 {
178 int certreq, force_encap;
179 char *local, *remote;
180
181 while (e->enumerate(e, &certreq, &force_encap, &local, &remote))
182 {
183 host_t *me, *other;
184 ike_cfg_t *ike_cfg;
185
186 me = host_create_from_string(local, 500);
187 if (!me)
188 {
189 continue;
190 }
191 if (my_host && !me->is_anyaddr(me) &&
192 !me->ip_equals(me, my_host))
193 {
194 me->destroy(me);
195 continue;
196 }
197 other = host_create_from_string(remote, 500);
198 if (!other)
199 {
200 me->destroy(me);
201 continue;
202 }
203 if (other_host && !other->is_anyaddr(other) &&
204 !other->ip_equals(other, other_host))
205 {
206 me->destroy(me);
207 other->destroy(other);
208 continue;
209 }
210 ike_cfg = ike_cfg_create(certreq, force_encap, me, other);
211 /* TODO: read proposal from db */
212 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
213 return ike_cfg;
214 }
215 return NULL;
216 }
217
218 /**
219 * Query a IKE config by its id
220 */
221 static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id)
222 {
223 enumerator_t *e;
224 ike_cfg_t *ike_cfg = NULL;
225
226 e = this->db->query(this->db,
227 "SELECT certreq, force_encap, local, remote "
228 "FROM ike_configs WHERE id = ?",
229 DB_INT, id,
230 DB_INT, DB_INT, DB_TEXT, DB_TEXT);
231 if (e)
232 {
233 ike_cfg = build_ike_cfg(this, e, NULL, NULL);
234 e->destroy(e);
235 }
236 return ike_cfg;
237 }
238
239 /**
240 * Query a peer config by its id
241 */
242 static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
243 {
244 enumerator_t *e;
245 peer_cfg_t *peer_cfg = NULL;
246
247 e = this->db->query(this->db,
248 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
249 "cert_policy, auth_method, eap_type, eap_vendor, keyingtries, "
250 "rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, "
251 "dpd_action, mediation, mediated_by, COALESCE(p.type, 0), p.data "
252 "FROM peer_configs AS c "
253 "JOIN identities AS l ON local_id = l.id "
254 "JOIN identities AS r ON remote_id = r.id "
255 "LEFT JOIN identities AS p ON peer_id = p.id "
256 "WHERE id = ?",
257 DB_INT, id,
258 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
259 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
260 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
261 DB_INT, DB_INT, DB_INT, DB_INT, DB_BLOB);
262 if (e)
263 {
264 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
265 e->destroy(e);
266 }
267 return peer_cfg;
268 }
269
270 /**
271 * build a peer configuration from a SQL query
272 */
273 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
274 identification_t *me, identification_t *other)
275 {
276 int id, ike_cfg, l_type, r_type,
277 cert_policy, auth_method, eap_type, eap_vendor, keyingtries,
278 rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay,
279 dpd_action, mediation, mediated_by, p_type;
280 chunk_t l_data, r_data, p_data;
281 char *name;
282
283 while (e->enumerate(e,
284 &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data,
285 &cert_policy, &auth_method, &eap_type, &eap_vendor, &keyingtries,
286 &rekeytime, &reauthtime, &jitter, &overtime, &mobike, &dpd_delay,
287 &dpd_action, &mediation, &mediated_by, &p_type, &p_data))
288 {
289 identification_t *local_id, *remote_id, *peer_id = NULL;
290 peer_cfg_t *peer_cfg, *mediated_cfg;
291 ike_cfg_t *ike;
292
293 local_id = identification_create_from_encoding(l_type, l_data);
294 remote_id = identification_create_from_encoding(r_type, r_data);
295 if ((me && !me->matches(me, local_id)) ||
296 (other && !other->matches(other, remote_id)))
297 {
298 local_id->destroy(local_id);
299 remote_id->destroy(remote_id);
300 continue;
301 }
302 ike = get_ike_cfg_by_id(this, ike_cfg);
303 mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
304 if (p_type)
305 {
306 peer_id = identification_create_from_encoding(p_type, p_data);
307 }
308
309 if (ike)
310 {
311 peer_cfg = peer_cfg_create(
312 name, 2, ike, local_id, remote_id, cert_policy,
313 auth_method, eap_type, eap_vendor, keyingtries,
314 rekeytime, reauthtime, jitter, overtime, mobike,
315 dpd_delay, NULL, NULL,
316 mediation, mediated_cfg, peer_id);
317 add_child_cfgs(this, peer_cfg, id);
318 return peer_cfg;
319 }
320 DESTROY_IF(ike);
321 DESTROY_IF(mediated_cfg);
322 DESTROY_IF(peer_id);
323 DESTROY_IF(local_id);
324 DESTROY_IF(remote_id);
325 }
326 return NULL;
327 }
328
329 /**
330 * implements backend_t.get_peer_cfg_by_name.
331 */
332 static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name)
333 {
334 enumerator_t *e;
335 peer_cfg_t *peer_cfg = NULL;
336
337 e = this->db->query(this->db,
338 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
339 "cert_policy, auth_method, eap_type, eap_vendor, keyingtries, "
340 "rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, "
341 "dpd_action, mediation, mediated_by, COALESCE(p.type, 0), p.data "
342 "FROM peer_configs AS c "
343 "JOIN identities AS l ON local_id = l.id "
344 "JOIN identities AS r ON remote_id = r.id "
345 "LEFT JOIN identities AS p ON peer_id = p.id "
346 "WHERE ike_version = ? AND name = ?",
347 DB_INT, 2, DB_TEXT, name,
348 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
349 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
350 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
351 DB_INT, DB_INT, DB_INT, DB_INT, DB_BLOB);
352 if (e)
353 {
354 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
355 e->destroy(e);
356 }
357 return peer_cfg;
358 }
359
360 typedef struct {
361 /** implements enumerator */
362 enumerator_t public;
363 /** reference to context */
364 private_sql_config_t *this;
365 /** filtering own host */
366 host_t *me;
367 /** filtering remote host */
368 host_t *other;
369 /** inner SQL enumerator */
370 enumerator_t *inner;
371 /** currently enumerated peer config */
372 ike_cfg_t *current;
373 } ike_enumerator_t;
374
375 /**
376 * Implementation of ike_enumerator_t.public.enumerate
377 */
378 static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
379 {
380 DESTROY_IF(this->current);
381 this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
382 if (this->current)
383 {
384 *cfg = this->current;
385 return TRUE;
386 }
387 return FALSE;
388 }
389
390 /**
391 * Implementation of ike_enumerator_t.public.destroy
392 */
393 static void ike_enumerator_destroy(ike_enumerator_t *this)
394 {
395 DESTROY_IF(this->current);
396 this->inner->destroy(this->inner);
397 free(this);
398 }
399
400 /**
401 * Implementation of backend_t.create_ike_cfg_enumerator.
402 */
403 static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this,
404 host_t *me, host_t *other)
405 {
406 ike_enumerator_t *e = malloc_thing(ike_enumerator_t);
407
408 e->this = this;
409 e->me = me;
410 e->other = other;
411 e->current = NULL;
412 e->public.enumerate = (void*)ike_enumerator_enumerate;
413 e->public.destroy = (void*)ike_enumerator_destroy;
414
415 e->inner = this->db->query(this->db,
416 "SELECT certreq, force_encap, local, remote "
417 "FROM ike_configs",
418 DB_INT, DB_INT, DB_TEXT, DB_TEXT);
419 if (!e->inner)
420 {
421 free(e);
422 return NULL;
423 }
424 return &e->public;
425 }
426
427
428 typedef struct {
429 /** implements enumerator */
430 enumerator_t public;
431 /** reference to context */
432 private_sql_config_t *this;
433 /** filtering own identity */
434 identification_t *me;
435 /** filtering remote identity */
436 identification_t *other;
437 /** inner SQL enumerator */
438 enumerator_t *inner;
439 /** currently enumerated peer config */
440 peer_cfg_t *current;
441 } peer_enumerator_t;
442
443 /**
444 * Implementation of peer_enumerator_t.public.enumerate
445 */
446 static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
447 {
448 DESTROY_IF(this->current);
449 this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
450 if (this->current)
451 {
452 *cfg = this->current;
453 return TRUE;
454 }
455 return FALSE;
456 }
457
458 /**
459 * Implementation of peer_enumerator_t.public.destroy
460 */
461 static void peer_enumerator_destroy(peer_enumerator_t *this)
462 {
463 DESTROY_IF(this->current);
464 this->inner->destroy(this->inner);
465 free(this);
466 }
467
468 /**
469 * Implementation of backend_t.create_peer_cfg_enumerator.
470 */
471 static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this,
472 identification_t *me,
473 identification_t *other)
474 {
475 peer_enumerator_t *e = malloc_thing(peer_enumerator_t);
476
477 e->this = this;
478 e->me = me;
479 e->other = other;
480 e->current = NULL;
481 e->public.enumerate = (void*)peer_enumerator_enumerate;
482 e->public.destroy = (void*)peer_enumerator_destroy;
483
484 /* TODO: only get configs whose IDs match exactly or contain wildcards */
485 e->inner = this->db->query(this->db,
486 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
487 "cert_policy, auth_method, eap_type, eap_vendor, keyingtries, "
488 "rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, "
489 "dpd_action, mediation, mediated_by, COALESCE(p.type, 0), p.data "
490 "FROM peer_configs AS c "
491 "JOIN identities AS l ON local_id = l.id "
492 "JOIN identities AS r ON remote_id = r.id "
493 "LEFT JOIN identities AS p ON peer_id = p.id "
494 "WHERE ike_version = ?",
495 DB_INT, 2,
496 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
497 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
498 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
499 DB_INT, DB_INT, DB_INT, DB_INT, DB_BLOB);
500 if (!e->inner)
501 {
502 free(e);
503 return NULL;
504 }
505 return &e->public;
506 }
507
508 /**
509 * Implementation of sql_config_t.destroy.
510 */
511 static void destroy(private_sql_config_t *this)
512 {
513 free(this);
514 }
515
516 /**
517 * Described in header.
518 */
519 sql_config_t *sql_config_create(database_t *db)
520 {
521 private_sql_config_t *this = malloc_thing(private_sql_config_t);
522
523 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
524 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
525 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
526 this->public.destroy = (void(*)(sql_config_t*))destroy;
527
528 this->db = db;
529
530 return &this->public;
531 }
532