bc562c2bf8f41f7ebbeac1d7a608808f0383b6f3
[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 an 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 * Add ESP proposals to a child config
123 */
124 static void add_esp_proposals(private_sql_config_t *this,
125 child_cfg_t *child, int id)
126 {
127 enumerator_t *e;
128 proposal_t *proposal;
129 char *alg;
130 bool use_default = TRUE;
131
132 e = this->db->query(this->db,
133 "SELECT algorithm "
134 "FROM algorithms JOIN child_config_algorithm ON id = alg "
135 "WHERE child_cfg = ? ORDER BY prio",
136 DB_INT, id, DB_TEXT);
137 if (e)
138 {
139 while (e->enumerate(e, &alg))
140 {
141 proposal = proposal_create_from_string(PROTO_ESP, alg);
142 child->add_proposal(child, proposal);
143 use_default = FALSE;
144 }
145 e->destroy(e);
146 }
147 if (use_default)
148 {
149 child->add_proposal(child, proposal_create_default(PROTO_ESP));
150 }
151 }
152
153 /**
154 * Build a child config from an SQL query
155 */
156 static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
157 {
158 int id, lifetime, rekeytime, jitter, hostaccess, mode, ipcomp;
159 int start, dpd, close;
160 char *name, *updown;
161 child_cfg_t *child_cfg;
162
163 if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, &updown,
164 &hostaccess, &mode, &start, &dpd, &close, &ipcomp))
165 {
166 lifetime_cfg_t lft = {
167 .time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter }
168 };
169 child_cfg = child_cfg_create(name, &lft, updown, hostaccess, mode,
170 start, dpd, close, ipcomp, 0, 0, NULL, NULL);
171 add_esp_proposals(this, child_cfg, id);
172 add_traffic_selectors(this, child_cfg, id);
173 return child_cfg;
174 }
175 return NULL;
176 }
177
178 /**
179 * Add child configs to peer config
180 */
181 static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id)
182 {
183 enumerator_t *e;
184 child_cfg_t *child_cfg;
185
186 e = this->db->query(this->db,
187 "SELECT id, name, lifetime, rekeytime, jitter, updown, "
188 "hostaccess, mode, start_action, dpd_action, close_action, ipcomp "
189 "FROM child_configs JOIN peer_config_child_config ON id = child_cfg "
190 "WHERE peer_cfg = ?",
191 DB_INT, id,
192 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_TEXT,
193 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
194 if (e)
195 {
196 while ((child_cfg = build_child_cfg(this, e)))
197 {
198 peer->add_child_cfg(peer, child_cfg);
199 }
200 e->destroy(e);
201 }
202 }
203
204 /**
205 * Add IKE proposals to an IKE config
206 */
207 static void add_ike_proposals(private_sql_config_t *this,
208 ike_cfg_t *ike_cfg, int id)
209 {
210 enumerator_t *e;
211 proposal_t *proposal;
212 char *alg;
213 bool use_default = TRUE;
214
215 e = this->db->query(this->db,
216 "SELECT algorithm "
217 "FROM algorithms JOIN ike_config_algorithm ON id = alg "
218 "WHERE ike_cfg = ? ORDER BY prio",
219 DB_INT, id, DB_TEXT);
220 if (e)
221 {
222 while (e->enumerate(e, &alg))
223 {
224 proposal = proposal_create_from_string(PROTO_IKE, alg);
225 ike_cfg->add_proposal(ike_cfg, proposal);
226 use_default = FALSE;
227 }
228 e->destroy(e);
229 }
230 if (use_default)
231 {
232 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
233 }
234 }
235
236 /**
237 * Build an IKE config from an SQL query
238 */
239 static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
240 host_t *my_host, host_t *other_host)
241 {
242 int id, certreq, force_encap;
243 char *local, *remote;
244
245 while (e->enumerate(e, &id, &certreq, &force_encap, &local, &remote))
246 {
247 ike_cfg_t *ike_cfg;
248
249 ike_cfg = ike_cfg_create(certreq, force_encap,
250 local, IKEV2_UDP_PORT, remote, IKEV2_UDP_PORT);
251 add_ike_proposals(this, ike_cfg, id);
252 return ike_cfg;
253 }
254 return NULL;
255 }
256
257 /**
258 * Query an IKE config by its id
259 */
260 static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id)
261 {
262 enumerator_t *e;
263 ike_cfg_t *ike_cfg = NULL;
264
265 e = this->db->query(this->db,
266 "SELECT id, certreq, force_encap, local, remote "
267 "FROM ike_configs WHERE id = ?",
268 DB_INT, id,
269 DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
270 if (e)
271 {
272 ike_cfg = build_ike_cfg(this, e, NULL, NULL);
273 e->destroy(e);
274 }
275 return ike_cfg;
276 }
277
278 /**
279 * Query a peer config by its id
280 */
281 static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
282 {
283 enumerator_t *e;
284 peer_cfg_t *peer_cfg = NULL;
285
286 e = this->db->query(this->db,
287 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
288 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
289 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
290 "dpd_delay, virtual, pool, "
291 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
292 "FROM peer_configs AS c "
293 "JOIN identities AS l ON local_id = l.id "
294 "JOIN identities AS r ON remote_id = r.id "
295 "LEFT JOIN identities AS p ON peer_id = p.id "
296 "WHERE id = ?",
297 DB_INT, id,
298 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
299 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
300 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
301 DB_INT, DB_TEXT, DB_TEXT,
302 DB_INT, DB_INT, DB_INT, DB_BLOB);
303 if (e)
304 {
305 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
306 e->destroy(e);
307 }
308 return peer_cfg;
309 }
310
311 /**
312 * Build a peer config from an SQL query
313 */
314 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
315 identification_t *me, identification_t *other)
316 {
317 int id, ike_cfg, l_type, r_type,
318 cert_policy, uniqueid, auth_method, eap_type, eap_vendor, keyingtries,
319 rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay,
320 mediation, mediated_by, p_type;
321 chunk_t l_data, r_data, p_data;
322 char *name, *virtual, *pool;
323
324 while (e->enumerate(e,
325 &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data,
326 &cert_policy, &uniqueid, &auth_method, &eap_type, &eap_vendor,
327 &keyingtries, &rekeytime, &reauthtime, &jitter, &overtime, &mobike,
328 &dpd_delay, &virtual, &pool,
329 &mediation, &mediated_by, &p_type, &p_data))
330 {
331 identification_t *local_id, *remote_id, *peer_id = NULL;
332 peer_cfg_t *peer_cfg, *mediated_cfg;
333 ike_cfg_t *ike;
334 host_t *vip = NULL;
335 auth_cfg_t *auth;
336
337 local_id = identification_create_from_encoding(l_type, l_data);
338 remote_id = identification_create_from_encoding(r_type, r_data);
339 if ((me && !me->matches(me, local_id)) ||
340 (other && !other->matches(other, remote_id)))
341 {
342 local_id->destroy(local_id);
343 remote_id->destroy(remote_id);
344 continue;
345 }
346 ike = get_ike_cfg_by_id(this, ike_cfg);
347 mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
348 if (p_type)
349 {
350 peer_id = identification_create_from_encoding(p_type, p_data);
351 }
352 if (virtual)
353 {
354 vip = host_create_from_string(virtual, 0);
355 }
356 if (ike)
357 {
358 peer_cfg = peer_cfg_create(
359 name, 2, ike, cert_policy, uniqueid,
360 keyingtries, rekeytime, reauthtime, jitter, overtime,
361 mobike, dpd_delay, vip, pool,
362 mediation, mediated_cfg, peer_id);
363 auth = auth_cfg_create();
364 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method);
365 auth->add(auth, AUTH_RULE_IDENTITY, local_id);
366 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
367 auth = auth_cfg_create();
368 auth->add(auth, AUTH_RULE_IDENTITY, remote_id);
369 if (eap_type)
370 {
371 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
372 auth->add(auth, AUTH_RULE_EAP_TYPE, eap_type);
373 if (eap_vendor)
374 {
375 auth->add(auth, AUTH_RULE_EAP_VENDOR, eap_vendor);
376 }
377 }
378 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
379 add_child_cfgs(this, peer_cfg, id);
380 return peer_cfg;
381 }
382 DESTROY_IF(ike);
383 DESTROY_IF(mediated_cfg);
384 DESTROY_IF(peer_id);
385 DESTROY_IF(local_id);
386 DESTROY_IF(remote_id);
387 }
388 return NULL;
389 }
390
391 /**
392 * implements backend_t.get_peer_cfg_by_name.
393 */
394 static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name)
395 {
396 enumerator_t *e;
397 peer_cfg_t *peer_cfg = NULL;
398
399 e = this->db->query(this->db,
400 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
401 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
402 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
403 "dpd_delay, virtual, pool, "
404 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
405 "FROM peer_configs AS c "
406 "JOIN identities AS l ON local_id = l.id "
407 "JOIN identities AS r ON remote_id = r.id "
408 "LEFT JOIN identities AS p ON peer_id = p.id "
409 "WHERE ike_version = ? AND name = ?",
410 DB_INT, 2, DB_TEXT, name,
411 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
412 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
413 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
414 DB_INT, DB_TEXT, DB_TEXT,
415 DB_INT, DB_INT, DB_INT, DB_BLOB);
416 if (e)
417 {
418 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
419 e->destroy(e);
420 }
421 return peer_cfg;
422 }
423
424 typedef struct {
425 /** implements enumerator */
426 enumerator_t public;
427 /** reference to context */
428 private_sql_config_t *this;
429 /** filtering own host */
430 host_t *me;
431 /** filtering remote host */
432 host_t *other;
433 /** inner SQL enumerator */
434 enumerator_t *inner;
435 /** currently enumerated peer config */
436 ike_cfg_t *current;
437 } ike_enumerator_t;
438
439 /**
440 * Implementation of ike_enumerator_t.public.enumerate
441 */
442 static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
443 {
444 DESTROY_IF(this->current);
445 this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
446 if (this->current)
447 {
448 *cfg = this->current;
449 return TRUE;
450 }
451 return FALSE;
452 }
453
454 /**
455 * Implementation of ike_enumerator_t.public.destroy
456 */
457 static void ike_enumerator_destroy(ike_enumerator_t *this)
458 {
459 DESTROY_IF(this->current);
460 this->inner->destroy(this->inner);
461 free(this);
462 }
463
464 /**
465 * Implementation of backend_t.create_ike_cfg_enumerator.
466 */
467 static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this,
468 host_t *me, host_t *other)
469 {
470 ike_enumerator_t *e = malloc_thing(ike_enumerator_t);
471
472 e->this = this;
473 e->me = me;
474 e->other = other;
475 e->current = NULL;
476 e->public.enumerate = (void*)ike_enumerator_enumerate;
477 e->public.destroy = (void*)ike_enumerator_destroy;
478
479 e->inner = this->db->query(this->db,
480 "SELECT id, certreq, force_encap, local, remote "
481 "FROM ike_configs",
482 DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
483 if (!e->inner)
484 {
485 free(e);
486 return NULL;
487 }
488 return &e->public;
489 }
490
491
492 typedef struct {
493 /** implements enumerator */
494 enumerator_t public;
495 /** reference to context */
496 private_sql_config_t *this;
497 /** filtering own identity */
498 identification_t *me;
499 /** filtering remote identity */
500 identification_t *other;
501 /** inner SQL enumerator */
502 enumerator_t *inner;
503 /** currently enumerated peer config */
504 peer_cfg_t *current;
505 } peer_enumerator_t;
506
507 /**
508 * Implementation of peer_enumerator_t.public.enumerate
509 */
510 static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
511 {
512 DESTROY_IF(this->current);
513 this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
514 if (this->current)
515 {
516 *cfg = this->current;
517 return TRUE;
518 }
519 return FALSE;
520 }
521
522 /**
523 * Implementation of peer_enumerator_t.public.destroy
524 */
525 static void peer_enumerator_destroy(peer_enumerator_t *this)
526 {
527 DESTROY_IF(this->current);
528 this->inner->destroy(this->inner);
529 free(this);
530 }
531
532 /**
533 * Implementation of backend_t.create_peer_cfg_enumerator.
534 */
535 static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this,
536 identification_t *me,
537 identification_t *other)
538 {
539 peer_enumerator_t *e = malloc_thing(peer_enumerator_t);
540
541 e->this = this;
542 e->me = me;
543 e->other = other;
544 e->current = NULL;
545 e->public.enumerate = (void*)peer_enumerator_enumerate;
546 e->public.destroy = (void*)peer_enumerator_destroy;
547
548 /* TODO: only get configs whose IDs match exactly or contain wildcards */
549 e->inner = this->db->query(this->db,
550 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
551 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
552 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
553 "dpd_delay, virtual, pool, "
554 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
555 "FROM peer_configs AS c "
556 "JOIN identities AS l ON local_id = l.id "
557 "JOIN identities AS r ON remote_id = r.id "
558 "LEFT JOIN identities AS p ON peer_id = p.id "
559 "WHERE ike_version = ?",
560 DB_INT, 2,
561 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
562 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
563 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
564 DB_INT, DB_TEXT, DB_TEXT,
565 DB_INT, DB_INT, DB_INT, DB_BLOB);
566 if (!e->inner)
567 {
568 free(e);
569 return NULL;
570 }
571 return &e->public;
572 }
573
574 /**
575 * Implementation of sql_config_t.destroy.
576 */
577 static void destroy(private_sql_config_t *this)
578 {
579 free(this);
580 }
581
582 /**
583 * Described in header.
584 */
585 sql_config_t *sql_config_create(database_t *db)
586 {
587 private_sql_config_t *this = malloc_thing(private_sql_config_t);
588
589 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
590 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
591 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
592 this->public.destroy = (void(*)(sql_config_t*))destroy;
593
594 this->db = db;
595
596 return &this->public;
597 }
598