renamed algorithm to proposal
[strongswan.git] / src / libcharon / plugins / sql / sql_config.c
1 /*
2 * Copyright (C) 2006-2008 Martin Willi
3 * Copyright (C) 2010 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <string.h>
18
19 #include "sql_config.h"
20
21 #include <daemon.h>
22
23 typedef struct private_sql_config_t private_sql_config_t;
24
25 /**
26 * Private data of an sql_config_t object
27 */
28 struct private_sql_config_t {
29
30 /**
31 * Public part
32 */
33 sql_config_t public;
34
35 /**
36 * database connection
37 */
38 database_t *db;
39 };
40
41 /**
42 * Forward declaration
43 */
44 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
45 identification_t *me, identification_t *other);
46
47 /**
48 * Build a traffic selector from an SQL query
49 */
50 static traffic_selector_t *build_traffic_selector(private_sql_config_t *this,
51 enumerator_t *e, bool *local)
52 {
53 int type, protocol, start_port, end_port;
54 chunk_t start_addr, end_addr;
55 traffic_selector_t *ts;
56 enum {
57 TS_LOCAL = 0,
58 TS_REMOTE = 1,
59 TS_LOCAL_DYNAMIC = 2,
60 TS_REMOTE_DYNAMIC = 3,
61 } kind;
62
63 while (e->enumerate(e, &kind, &type, &protocol,
64 &start_addr, &end_addr, &start_port, &end_port))
65 {
66 *local = FALSE;
67 switch (kind)
68 {
69 case TS_LOCAL:
70 *local = TRUE;
71 /* FALL */
72 case TS_REMOTE:
73 ts = traffic_selector_create_from_bytes(protocol, type,
74 start_addr, start_port, end_addr, end_port);
75 break;
76 case TS_LOCAL_DYNAMIC:
77 *local = TRUE;
78 /* FALL */
79 case TS_REMOTE_DYNAMIC:
80 ts = traffic_selector_create_dynamic(protocol,
81 start_port, end_port);
82 break;
83 default:
84 continue;
85 }
86 if (ts)
87 {
88 return ts;
89 }
90 }
91 return NULL;
92 }
93
94 /**
95 * Add traffic selectors to a child config
96 */
97 static void add_traffic_selectors(private_sql_config_t *this,
98 child_cfg_t *child, int id)
99 {
100 enumerator_t *e;
101 traffic_selector_t *ts;
102 bool local;
103
104 e = this->db->query(this->db,
105 "SELECT kind, type, protocol, "
106 "start_addr, end_addr, start_port, end_port "
107 "FROM traffic_selectors JOIN child_config_traffic_selector "
108 "ON id = traffic_selector WHERE child_cfg = ?",
109 DB_INT, id,
110 DB_INT, DB_INT, DB_INT,
111 DB_BLOB, DB_BLOB, DB_INT, DB_INT);
112 if (e)
113 {
114 while ((ts = build_traffic_selector(this, e, &local)))
115 {
116 child->add_traffic_selector(child, local, ts);
117 }
118 e->destroy(e);
119 }
120 }
121
122 /**
123 * Add ESP proposals to a child config
124 */
125 static void add_esp_proposals(private_sql_config_t *this,
126 child_cfg_t *child, int id)
127 {
128 enumerator_t *e;
129 proposal_t *proposal;
130 char *prop;
131 bool use_default = TRUE;
132
133 e = this->db->query(this->db,
134 "SELECT proposal "
135 "FROM proposals JOIN child_config_proposal ON id = prop "
136 "WHERE child_cfg = ? ORDER BY prio",
137 DB_INT, id, DB_TEXT);
138 if (e)
139 {
140 while (e->enumerate(e, &prop))
141 {
142 proposal = proposal_create_from_string(PROTO_ESP, prop);
143 child->add_proposal(child, proposal);
144 use_default = FALSE;
145 }
146 e->destroy(e);
147 }
148 if (use_default)
149 {
150 child->add_proposal(child, proposal_create_default(PROTO_ESP));
151 }
152 }
153
154 /**
155 * Build a child config from an SQL query
156 */
157 static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
158 {
159 int id, lifetime, rekeytime, jitter, hostaccess, mode, ipcomp;
160 int start, dpd, close;
161 char *name, *updown;
162 child_cfg_t *child_cfg;
163
164 if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, &updown,
165 &hostaccess, &mode, &start, &dpd, &close, &ipcomp))
166 {
167 lifetime_cfg_t lft = {
168 .time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter }
169 };
170 child_cfg = child_cfg_create(name, &lft, updown, hostaccess, mode,
171 start, dpd, close, ipcomp, 0, 0, NULL, NULL);
172 add_esp_proposals(this, child_cfg, id);
173 add_traffic_selectors(this, child_cfg, id);
174 return child_cfg;
175 }
176 return NULL;
177 }
178
179 /**
180 * Add child configs to peer config
181 */
182 static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id)
183 {
184 enumerator_t *e;
185 child_cfg_t *child_cfg;
186
187 e = this->db->query(this->db,
188 "SELECT id, name, lifetime, rekeytime, jitter, updown, "
189 "hostaccess, mode, start_action, dpd_action, close_action, ipcomp "
190 "FROM child_configs JOIN peer_config_child_config ON id = child_cfg "
191 "WHERE peer_cfg = ?",
192 DB_INT, id,
193 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_TEXT,
194 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
195 if (e)
196 {
197 while ((child_cfg = build_child_cfg(this, e)))
198 {
199 peer->add_child_cfg(peer, child_cfg);
200 }
201 e->destroy(e);
202 }
203 }
204
205 /**
206 * Add IKE proposals to an IKE config
207 */
208 static void add_ike_proposals(private_sql_config_t *this,
209 ike_cfg_t *ike_cfg, int id)
210 {
211 enumerator_t *e;
212 proposal_t *proposal;
213 char *prop;
214 bool use_default = TRUE;
215
216 e = this->db->query(this->db,
217 "SELECT proposal "
218 "FROM proposals JOIN ike_config_proposal ON id = prop "
219 "WHERE ike_cfg = ? ORDER BY prio",
220 DB_INT, id, DB_TEXT);
221 if (e)
222 {
223 while (e->enumerate(e, &prop))
224 {
225 proposal = proposal_create_from_string(PROTO_IKE, prop);
226 ike_cfg->add_proposal(ike_cfg, proposal);
227 use_default = FALSE;
228 }
229 e->destroy(e);
230 }
231 if (use_default)
232 {
233 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
234 }
235 }
236
237 /**
238 * Build an IKE config from an SQL query
239 */
240 static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
241 host_t *my_host, host_t *other_host)
242 {
243 int id, certreq, force_encap;
244 char *local, *remote;
245
246 while (e->enumerate(e, &id, &certreq, &force_encap, &local, &remote))
247 {
248 ike_cfg_t *ike_cfg;
249
250 ike_cfg = ike_cfg_create(certreq, force_encap,
251 local, IKEV2_UDP_PORT, remote, IKEV2_UDP_PORT);
252 add_ike_proposals(this, ike_cfg, id);
253 return ike_cfg;
254 }
255 return NULL;
256 }
257
258 /**
259 * Query an IKE config by its id
260 */
261 static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id)
262 {
263 enumerator_t *e;
264 ike_cfg_t *ike_cfg = NULL;
265
266 e = this->db->query(this->db,
267 "SELECT id, certreq, force_encap, local, remote "
268 "FROM ike_configs WHERE id = ?",
269 DB_INT, id,
270 DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
271 if (e)
272 {
273 ike_cfg = build_ike_cfg(this, e, NULL, NULL);
274 e->destroy(e);
275 }
276 return ike_cfg;
277 }
278
279 /**
280 * Query a peer config by its id
281 */
282 static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
283 {
284 enumerator_t *e;
285 peer_cfg_t *peer_cfg = NULL;
286
287 e = this->db->query(this->db,
288 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
289 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
290 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
291 "dpd_delay, virtual, pool, "
292 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
293 "FROM peer_configs AS c "
294 "JOIN identities AS l ON local_id = l.id "
295 "JOIN identities AS r ON remote_id = r.id "
296 "LEFT JOIN identities AS p ON peer_id = p.id "
297 "WHERE id = ?",
298 DB_INT, id,
299 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
300 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
301 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
302 DB_INT, DB_TEXT, DB_TEXT,
303 DB_INT, DB_INT, DB_INT, DB_BLOB);
304 if (e)
305 {
306 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
307 e->destroy(e);
308 }
309 return peer_cfg;
310 }
311
312 /**
313 * Build a peer config from an SQL query
314 */
315 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
316 identification_t *me, identification_t *other)
317 {
318 int id, ike_cfg, l_type, r_type,
319 cert_policy, uniqueid, auth_method, eap_type, eap_vendor, keyingtries,
320 rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay,
321 mediation, mediated_by, p_type;
322 chunk_t l_data, r_data, p_data;
323 char *name, *virtual, *pool;
324
325 while (e->enumerate(e,
326 &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data,
327 &cert_policy, &uniqueid, &auth_method, &eap_type, &eap_vendor,
328 &keyingtries, &rekeytime, &reauthtime, &jitter, &overtime, &mobike,
329 &dpd_delay, &virtual, &pool,
330 &mediation, &mediated_by, &p_type, &p_data))
331 {
332 identification_t *local_id, *remote_id, *peer_id = NULL;
333 peer_cfg_t *peer_cfg, *mediated_cfg;
334 ike_cfg_t *ike;
335 host_t *vip = NULL;
336 auth_cfg_t *auth;
337
338 local_id = identification_create_from_encoding(l_type, l_data);
339 remote_id = identification_create_from_encoding(r_type, r_data);
340 if ((me && !me->matches(me, local_id)) ||
341 (other && !other->matches(other, remote_id)))
342 {
343 local_id->destroy(local_id);
344 remote_id->destroy(remote_id);
345 continue;
346 }
347 ike = get_ike_cfg_by_id(this, ike_cfg);
348 mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
349 if (p_type)
350 {
351 peer_id = identification_create_from_encoding(p_type, p_data);
352 }
353 if (virtual)
354 {
355 vip = host_create_from_string(virtual, 0);
356 }
357 if (ike)
358 {
359 peer_cfg = peer_cfg_create(
360 name, 2, ike, cert_policy, uniqueid,
361 keyingtries, rekeytime, reauthtime, jitter, overtime,
362 mobike, dpd_delay, vip, pool,
363 mediation, mediated_cfg, peer_id);
364 auth = auth_cfg_create();
365 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method);
366 auth->add(auth, AUTH_RULE_IDENTITY, local_id);
367 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
368 auth = auth_cfg_create();
369 auth->add(auth, AUTH_RULE_IDENTITY, remote_id);
370 if (eap_type)
371 {
372 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
373 auth->add(auth, AUTH_RULE_EAP_TYPE, eap_type);
374 if (eap_vendor)
375 {
376 auth->add(auth, AUTH_RULE_EAP_VENDOR, eap_vendor);
377 }
378 }
379 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
380 add_child_cfgs(this, peer_cfg, id);
381 return peer_cfg;
382 }
383 DESTROY_IF(ike);
384 DESTROY_IF(mediated_cfg);
385 DESTROY_IF(peer_id);
386 DESTROY_IF(local_id);
387 DESTROY_IF(remote_id);
388 }
389 return NULL;
390 }
391
392 /**
393 * implements backend_t.get_peer_cfg_by_name.
394 */
395 static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name)
396 {
397 enumerator_t *e;
398 peer_cfg_t *peer_cfg = NULL;
399
400 e = this->db->query(this->db,
401 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
402 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
403 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
404 "dpd_delay, virtual, pool, "
405 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
406 "FROM peer_configs AS c "
407 "JOIN identities AS l ON local_id = l.id "
408 "JOIN identities AS r ON remote_id = r.id "
409 "LEFT JOIN identities AS p ON peer_id = p.id "
410 "WHERE ike_version = ? AND name = ?",
411 DB_INT, 2, DB_TEXT, name,
412 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
413 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
414 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
415 DB_INT, DB_TEXT, DB_TEXT,
416 DB_INT, DB_INT, DB_INT, DB_BLOB);
417 if (e)
418 {
419 peer_cfg = build_peer_cfg(this, e, NULL, NULL);
420 e->destroy(e);
421 }
422 return peer_cfg;
423 }
424
425 typedef struct {
426 /** implements enumerator */
427 enumerator_t public;
428 /** reference to context */
429 private_sql_config_t *this;
430 /** filtering own host */
431 host_t *me;
432 /** filtering remote host */
433 host_t *other;
434 /** inner SQL enumerator */
435 enumerator_t *inner;
436 /** currently enumerated peer config */
437 ike_cfg_t *current;
438 } ike_enumerator_t;
439
440 /**
441 * Implementation of ike_enumerator_t.public.enumerate
442 */
443 static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
444 {
445 DESTROY_IF(this->current);
446 this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
447 if (this->current)
448 {
449 *cfg = this->current;
450 return TRUE;
451 }
452 return FALSE;
453 }
454
455 /**
456 * Implementation of ike_enumerator_t.public.destroy
457 */
458 static void ike_enumerator_destroy(ike_enumerator_t *this)
459 {
460 DESTROY_IF(this->current);
461 this->inner->destroy(this->inner);
462 free(this);
463 }
464
465 /**
466 * Implementation of backend_t.create_ike_cfg_enumerator.
467 */
468 static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this,
469 host_t *me, host_t *other)
470 {
471 ike_enumerator_t *e = malloc_thing(ike_enumerator_t);
472
473 e->this = this;
474 e->me = me;
475 e->other = other;
476 e->current = NULL;
477 e->public.enumerate = (void*)ike_enumerator_enumerate;
478 e->public.destroy = (void*)ike_enumerator_destroy;
479
480 e->inner = this->db->query(this->db,
481 "SELECT id, certreq, force_encap, local, remote "
482 "FROM ike_configs",
483 DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
484 if (!e->inner)
485 {
486 free(e);
487 return NULL;
488 }
489 return &e->public;
490 }
491
492
493 typedef struct {
494 /** implements enumerator */
495 enumerator_t public;
496 /** reference to context */
497 private_sql_config_t *this;
498 /** filtering own identity */
499 identification_t *me;
500 /** filtering remote identity */
501 identification_t *other;
502 /** inner SQL enumerator */
503 enumerator_t *inner;
504 /** currently enumerated peer config */
505 peer_cfg_t *current;
506 } peer_enumerator_t;
507
508 /**
509 * Implementation of peer_enumerator_t.public.enumerate
510 */
511 static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
512 {
513 DESTROY_IF(this->current);
514 this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
515 if (this->current)
516 {
517 *cfg = this->current;
518 return TRUE;
519 }
520 return FALSE;
521 }
522
523 /**
524 * Implementation of peer_enumerator_t.public.destroy
525 */
526 static void peer_enumerator_destroy(peer_enumerator_t *this)
527 {
528 DESTROY_IF(this->current);
529 this->inner->destroy(this->inner);
530 free(this);
531 }
532
533 /**
534 * Implementation of backend_t.create_peer_cfg_enumerator.
535 */
536 static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this,
537 identification_t *me,
538 identification_t *other)
539 {
540 peer_enumerator_t *e = malloc_thing(peer_enumerator_t);
541
542 e->this = this;
543 e->me = me;
544 e->other = other;
545 e->current = NULL;
546 e->public.enumerate = (void*)peer_enumerator_enumerate;
547 e->public.destroy = (void*)peer_enumerator_destroy;
548
549 /* TODO: only get configs whose IDs match exactly or contain wildcards */
550 e->inner = this->db->query(this->db,
551 "SELECT c.id, name, ike_cfg, l.type, l.data, r.type, r.data, "
552 "cert_policy, uniqueid, auth_method, eap_type, eap_vendor, "
553 "keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, "
554 "dpd_delay, virtual, pool, "
555 "mediation, mediated_by, COALESCE(p.type, 0), p.data "
556 "FROM peer_configs AS c "
557 "JOIN identities AS l ON local_id = l.id "
558 "JOIN identities AS r ON remote_id = r.id "
559 "LEFT JOIN identities AS p ON peer_id = p.id "
560 "WHERE ike_version = ?",
561 DB_INT, 2,
562 DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
563 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
564 DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
565 DB_INT, DB_TEXT, DB_TEXT,
566 DB_INT, DB_INT, DB_INT, DB_BLOB);
567 if (!e->inner)
568 {
569 free(e);
570 return NULL;
571 }
572 return &e->public;
573 }
574
575 /**
576 * Implementation of sql_config_t.destroy.
577 */
578 static void destroy(private_sql_config_t *this)
579 {
580 free(this);
581 }
582
583 /**
584 * Described in header.
585 */
586 sql_config_t *sql_config_create(database_t *db)
587 {
588 private_sql_config_t *this = malloc_thing(private_sql_config_t);
589
590 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
591 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
592 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
593 this->public.destroy = (void(*)(sql_config_t*))destroy;
594
595 this->db = db;
596
597 return &this->public;
598 }
599