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