eaa9da5effe3eec190c9bd914762b366a5220762
[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 char *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_string(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, type,
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_TEXT, DB_TEXT, 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 /* TODO: read proposal from db */
138 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
139 add_traffic_selectors(this, child_cfg, id);
140 return child_cfg;
141 }
142 return NULL;
143 }
144
145 /**
146 * Add child configs to peer config
147 */
148 static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id)
149 {
150 enumerator_t *e;
151 child_cfg_t *child_cfg;
152
153 e = this->db->query(this->db,
154 "SELECT id, name, lifetime, rekeytime, jitter, "
155 "updown, hostaccess, mode "
156 "FROM child_configs JOIN peer_config_child_config ON id = child_cfg "
157 "WHERE peer_cfg = ?",
158 DB_INT, id,
159 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT,
160 DB_TEXT, DB_INT, DB_INT);
161 if (e)
162 {
163 while ((child_cfg = build_child_cfg(this, e)))
164 {
165 peer->add_child_cfg(peer, child_cfg);
166 }
167 e->destroy(e);
168 }
169 }
170
171 /**
172 * build a ike configuration from a SQL query
173 */
174 static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
175 host_t *my_host, host_t *other_host)
176 {
177 int certreq, force_encap;
178 char *local, *remote;
179
180 while (e->enumerate(e, &certreq, &force_encap, &local, &remote))
181 {
182 host_t *me, *other;
183 ike_cfg_t *ike_cfg;
184
185 me = host_create_from_string(local, 500);
186 if (!me)
187 {
188 continue;
189 }
190 if (my_host && !me->is_anyaddr(me) &&
191 !me->ip_equals(me, my_host))
192 {
193 me->destroy(me);
194 continue;
195 }
196 other = host_create_from_string(remote, 500);
197 if (!other)
198 {
199 me->destroy(me);
200 continue;
201 }
202 if (other_host && !other->is_anyaddr(other) &&
203 !other->ip_equals(other, other_host))
204 {
205 me->destroy(me);
206 other->destroy(other);
207 continue;
208 }
209 ike_cfg = ike_cfg_create(certreq, force_encap, me, other);
210 /* TODO: read proposal from db */
211 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
212 return ike_cfg;
213 }
214 return NULL;
215 }
216
217 /**
218 * Query a IKE config by its id
219 */
220 static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id)
221 {
222 enumerator_t *e;
223 ike_cfg_t *ike_cfg = NULL;
224
225 e = this->db->query(this->db,
226 "SELECT certreq, force_encap, local, remote "
227 "FROM ike_configs WHERE id = ?",
228 DB_INT, id,
229 DB_INT, DB_INT, DB_TEXT, DB_TEXT);
230 if (e)
231 {
232 ike_cfg = build_ike_cfg(this, e, NULL, NULL);
233 e->destroy(e);
234 }
235 return ike_cfg;
236 }
237
238 /**
239 * Query a peer config by its id
240 */
241 static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
242 {
243 enumerator_t *e;
244 peer_cfg_t *peer_cfg = NULL;
245
246 e = this->db->query(this->db,
247 "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, "
248 "auth_method, eap_type, eap_vendor, keyingtries, "
249 "rekeytime, reauthtime, jitter, overtime, mobike, "
250 "dpd_delay, dpd_action, local_vip, remote_vip, "
251 "mediation, mediated_by, peer_id "
252 "FROM peer_configs WHERE id = ?",
253 DB_INT, id,
254 DB_INT, DB_INT, DB_TEXT, DB_TEXT, DB_INT,
255 DB_INT, DB_INT, DB_INT, DB_INT,
256 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
257 DB_INT, DB_INT, DB_TEXT, DB_TEXT,
258 DB_INT, DB_INT, DB_TEXT);
259 if (e)
260 {
261 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
262 e->destroy(e);
263 }
264 return peer_cfg;
265 }
266
267 /**
268 * build a peer configuration from a SQL query
269 */
270 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
271 identification_t *me, identification_t *other)
272 {
273 int id, ike_cfg, cert_policy, auth_method, eap_type, eap_vendor,
274 keyingtries, rekeytime, reauthtime, jitter, overtime, mobike,
275 dpd_delay, dpd_action, mediation, mediated_by;
276 char *local_id, *remote_id, *local_vip, *remote_vip, *peer_id, *name;
277
278 while (e->enumerate(e, &id, &name, &ike_cfg, &local_id, &remote_id, &cert_policy,
279 &auth_method, &eap_type, &eap_vendor, &keyingtries,
280 &rekeytime, &reauthtime, &jitter, &overtime, &mobike,
281 &dpd_delay, &dpd_action, &local_vip, &remote_vip,
282 &mediation, &mediated_by, &peer_id))
283 {
284 ike_cfg_t *ike;
285 peer_cfg_t *peer_cfg, *mediated_cfg;
286 identification_t *my_id, *other_id, *peer;
287 host_t *my_vip, *other_vip;
288
289 my_id = identification_create_from_string(local_id);
290 if (!my_id)
291 {
292 continue;
293 }
294 if (me && !me->matches(me, my_id))
295 {
296 my_id->destroy(my_id);
297 continue;
298 }
299 other_id = identification_create_from_string(remote_id);
300 if (!other_id)
301 {
302 my_id->destroy(my_id);
303 continue;
304 }
305 if (other && !other->matches(other, other_id))
306 {
307 other_id->destroy(other_id);
308 my_id->destroy(my_id);
309 continue;
310 }
311 ike = get_ike_cfg_by_id(this, ike_cfg);
312 mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
313 peer = peer_id ? identification_create_from_string(peer_id) : NULL;
314 my_vip = local_vip ? host_create_from_string(local_vip, 0) : NULL;
315 other_vip = remote_vip ? host_create_from_string(remote_vip, 0) : NULL;
316
317 if (ike)
318 {
319 peer_cfg = peer_cfg_create(
320 name, 2, ike, my_id, other_id, cert_policy,
321 auth_method, eap_type, eap_vendor, keyingtries,
322 rekeytime, reauthtime, jitter, overtime, mobike,
323 dpd_delay, dpd_action, my_vip, other_vip,
324 mediation, mediated_cfg, peer);
325 add_child_cfgs(this, peer_cfg, id);
326 return peer_cfg;
327 }
328 DESTROY_IF(ike);
329 DESTROY_IF(mediated_cfg);
330 DESTROY_IF(peer);
331 DESTROY_IF(my_vip);
332 DESTROY_IF(other_vip);
333 DESTROY_IF(my_id);
334 DESTROY_IF(other_id);
335 }
336 return NULL;
337 }
338
339 /**
340 * implements backend_t.get_peer_cfg_by_name.
341 */
342 static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name)
343 {
344 enumerator_t *e;
345 peer_cfg_t *peer_cfg = NULL;
346
347 e = this->db->query(this->db,
348 "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, "
349 "auth_method, eap_type, eap_vendor, keyingtries, "
350 "rekeytime, reauthtime, jitter, overtime, mobike, "
351 "dpd_delay, dpd_action, local_vip, remote_vip, "
352 "mediation, mediated_by, peer_id "
353 "FROM peer_configs WHERE ike_version = ? AND name = ?",
354 DB_INT, 2, DB_TEXT, name,
355 DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_TEXT, DB_INT,
356 DB_INT, DB_INT, DB_INT, DB_INT,
357 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
358 DB_INT, DB_INT, DB_TEXT, DB_TEXT,
359 DB_INT, DB_INT, DB_TEXT);
360 if (e)
361 {
362 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
363 e->destroy(e);
364 }
365 return peer_cfg;
366 }
367
368 typedef struct {
369 /** implements enumerator */
370 enumerator_t public;
371 /** reference to context */
372 private_sql_config_t *this;
373 /** filtering own host */
374 host_t *me;
375 /** filtering remote host */
376 host_t *other;
377 /** inner SQL enumerator */
378 enumerator_t *inner;
379 /** currently enumerated peer config */
380 ike_cfg_t *current;
381 } ike_enumerator_t;
382
383 /**
384 * Implementation of ike_enumerator_t.public.enumerate
385 */
386 static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
387 {
388 DESTROY_IF(this->current);
389 this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
390 if (this->current)
391 {
392 *cfg = this->current;
393 return TRUE;
394 }
395 return FALSE;
396 }
397
398 /**
399 * Implementation of ike_enumerator_t.public.destroy
400 */
401 static void ike_enumerator_destroy(ike_enumerator_t *this)
402 {
403 DESTROY_IF(this->current);
404 this->inner->destroy(this->inner);
405 free(this);
406 }
407
408 /**
409 * Implementation of backend_t.create_ike_cfg_enumerator.
410 */
411 static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this,
412 host_t *me, host_t *other)
413 {
414 ike_enumerator_t *e = malloc_thing(ike_enumerator_t);
415
416 e->this = this;
417 e->me = me;
418 e->other = other;
419 e->current = NULL;
420 e->public.enumerate = (void*)ike_enumerator_enumerate;
421 e->public.destroy = (void*)ike_enumerator_destroy;
422
423 e->inner = this->db->query(this->db,
424 "SELECT certreq, force_encap, local, remote "
425 "FROM ike_configs",
426 DB_INT, DB_INT, DB_TEXT, DB_TEXT);
427 if (!e->inner)
428 {
429 free(e);
430 return NULL;
431 }
432 return &e->public;
433 }
434
435
436 typedef struct {
437 /** implements enumerator */
438 enumerator_t public;
439 /** reference to context */
440 private_sql_config_t *this;
441 /** filtering own identity */
442 identification_t *me;
443 /** filtering remote identity */
444 identification_t *other;
445 /** inner SQL enumerator */
446 enumerator_t *inner;
447 /** currently enumerated peer config */
448 peer_cfg_t *current;
449 } peer_enumerator_t;
450
451 /**
452 * Implementation of peer_enumerator_t.public.enumerate
453 */
454 static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
455 {
456 DESTROY_IF(this->current);
457 this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
458 if (this->current)
459 {
460 *cfg = this->current;
461 return TRUE;
462 }
463 return FALSE;
464 }
465
466 /**
467 * Implementation of peer_enumerator_t.public.destroy
468 */
469 static void peer_enumerator_destroy(peer_enumerator_t *this)
470 {
471 DESTROY_IF(this->current);
472 this->inner->destroy(this->inner);
473 free(this);
474 }
475
476 /**
477 * Implementation of backend_t.create_peer_cfg_enumerator.
478 */
479 static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this,
480 identification_t *me,
481 identification_t *other)
482 {
483 peer_enumerator_t *e = malloc_thing(peer_enumerator_t);
484
485 e->this = this;
486 e->me = me;
487 e->other = other;
488 e->current = NULL;
489 e->public.enumerate = (void*)peer_enumerator_enumerate;
490 e->public.destroy = (void*)peer_enumerator_destroy;
491
492 /* TODO: only get configs whose IDs match exactly or contain wildcards */
493 e->inner = this->db->query(this->db,
494 "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, "
495 "auth_method, eap_type, eap_vendor, keyingtries, "
496 "rekeytime, reauthtime, jitter, overtime, mobike, "
497 "dpd_delay, dpd_action, local_vip, remote_vip, "
498 "mediation, mediated_by, peer_id "
499 "FROM peer_configs WHERE ike_version = ? ",
500 DB_INT, 2,
501 DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_TEXT, DB_INT,
502 DB_INT, DB_INT, DB_INT, DB_INT,
503 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
504 DB_INT, DB_INT, DB_TEXT, DB_TEXT,
505 DB_INT, DB_INT, DB_TEXT);
506 if (!e->inner)
507 {
508 free(e);
509 return NULL;
510 }
511 return &e->public;
512 }
513
514 /**
515 * Implementation of sql_config_t.destroy.
516 */
517 static void destroy(private_sql_config_t *this)
518 {
519 free(this);
520 }
521
522 /**
523 * Described in header.
524 */
525 sql_config_t *sql_config_create(database_t *db)
526 {
527 private_sql_config_t *this = malloc_thing(private_sql_config_t);
528
529 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
530 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
531 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
532 this->public.destroy = (void(*)(sql_config_t*))destroy;
533
534 this->db = db;
535
536 return &this->public;
537 }
538