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