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