2 * Copyright (C) 2006-2008 Martin Willi
3 * Copyright (C) 2010 Andreas Steffen
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include "sql_config.h"
24 typedef struct private_sql_config_t private_sql_config_t
;
27 * Private data of an sql_config_t object
29 struct private_sql_config_t
{
45 static peer_cfg_t
*build_peer_cfg(private_sql_config_t
*this, enumerator_t
*e
,
46 identification_t
*me
, identification_t
*other
);
49 * Build a traffic selector from an SQL query
51 static traffic_selector_t
*build_traffic_selector(private_sql_config_t
*this,
52 enumerator_t
*e
, bool *local
)
54 int type
, protocol
, start_port
, end_port
;
55 chunk_t start_addr
, end_addr
;
56 traffic_selector_t
*ts
;
61 TS_REMOTE_DYNAMIC
= 3,
64 while (e
->enumerate(e
, &kind
, &type
, &protocol
,
65 &start_addr
, &end_addr
, &start_port
, &end_port
))
74 ts
= traffic_selector_create_from_bytes(protocol
, type
,
75 start_addr
, start_port
, end_addr
, end_port
);
77 case TS_LOCAL_DYNAMIC
:
80 case TS_REMOTE_DYNAMIC
:
81 ts
= traffic_selector_create_dynamic(protocol
,
82 start_port
, end_port
);
96 * Add traffic selectors to a child config
98 static void add_traffic_selectors(private_sql_config_t
*this,
99 child_cfg_t
*child
, int id
)
102 traffic_selector_t
*ts
;
105 e
= this->db
->query(this->db
,
106 "SELECT ct.kind, t.type, t.protocol, "
107 "t.start_addr, t.end_addr, t.start_port, t.end_port "
108 "FROM traffic_selectors AS t "
109 "JOIN child_config_traffic_selector AS ct "
110 "ON t.id = ct.traffic_selector WHERE ct.child_cfg = ?",
112 DB_INT
, DB_INT
, DB_INT
,
113 DB_BLOB
, DB_BLOB
, DB_INT
, DB_INT
);
116 while ((ts
= build_traffic_selector(this, e
, &local
)))
118 child
->add_traffic_selector(child
, local
, ts
);
125 * Add ESP proposals to a child config
127 static void add_esp_proposals(private_sql_config_t
*this,
128 child_cfg_t
*child
, int id
)
131 proposal_t
*proposal
;
133 bool use_default
= TRUE
;
135 e
= this->db
->query(this->db
,
137 "FROM proposals AS p JOIN child_config_proposal AS cp "
138 "ON p.id = cp.prop WHERE cp.child_cfg = ? ORDER BY cp.prio",
139 DB_INT
, id
, DB_TEXT
);
142 while (e
->enumerate(e
, &prop
))
144 proposal
= proposal_create_from_string(PROTO_ESP
, prop
);
147 DBG1(DBG_CFG
, "could not create ESP proposal from '%s'", prop
);
150 child
->add_proposal(child
, proposal
);
157 child
->add_proposal(child
, proposal_create_default_aead(PROTO_ESP
));
158 child
->add_proposal(child
, proposal_create_default(PROTO_ESP
));
163 * Build a child config from an SQL query
165 static child_cfg_t
*build_child_cfg(private_sql_config_t
*this, enumerator_t
*e
)
167 int id
, lifetime
, rekeytime
, jitter
, hostaccess
, mode
, ipcomp
, reqid
;
168 int start
, dpd
, close
;
170 child_cfg_t
*child_cfg
;
172 if (e
->enumerate(e
, &id
, &name
, &lifetime
, &rekeytime
, &jitter
, &updown
,
173 &hostaccess
, &mode
, &start
, &dpd
, &close
, &ipcomp
, &reqid
))
175 child_cfg_create_t child
= {
178 .options
= (ipcomp
? OPT_IPCOMP
: 0) |
179 (hostaccess
? OPT_HOSTACCESS
: 0),
182 .life
= lifetime
, .rekey
= rekeytime
, .jitter
= jitter
185 .start_action
= start
,
187 .close_action
= close
,
190 child_cfg
= child_cfg_create(name
, &child
);
191 add_esp_proposals(this, child_cfg
, id
);
192 add_traffic_selectors(this, child_cfg
, id
);
199 * Add child configs to peer config
201 static void add_child_cfgs(private_sql_config_t
*this, peer_cfg_t
*peer
, int id
)
204 child_cfg_t
*child_cfg
;
206 e
= this->db
->query(this->db
,
207 "SELECT c.id, c.name, c.lifetime, c.rekeytime, c.jitter, c.updown, "
208 "c.hostaccess, c.mode, c.start_action, c.dpd_action, "
209 "c.close_action, c.ipcomp, c.reqid "
210 "FROM child_configs AS c JOIN peer_config_child_config AS pc "
211 "ON c.id = pc.child_cfg WHERE pc.peer_cfg = ?",
213 DB_INT
, DB_TEXT
, DB_INT
, DB_INT
, DB_INT
, DB_TEXT
, DB_INT
,
214 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
);
217 while ((child_cfg
= build_child_cfg(this, e
)))
219 peer
->add_child_cfg(peer
, child_cfg
);
226 * Add IKE proposals to an IKE config
228 static void add_ike_proposals(private_sql_config_t
*this,
229 ike_cfg_t
*ike_cfg
, int id
)
232 proposal_t
*proposal
;
234 bool use_default
= TRUE
;
236 e
= this->db
->query(this->db
,
238 "FROM proposals AS p "
239 "JOIN ike_config_proposal AS ip ON p.id = ip.prop "
240 "WHERE ip.ike_cfg = ? ORDER BY ip.prio",
241 DB_INT
, id
, DB_TEXT
);
244 while (e
->enumerate(e
, &prop
))
246 proposal
= proposal_create_from_string(PROTO_IKE
, prop
);
249 DBG1(DBG_CFG
, "could not create IKE proposal from '%s'", prop
);
252 ike_cfg
->add_proposal(ike_cfg
, proposal
);
259 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
260 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default_aead(PROTO_IKE
));
265 * Build an IKE config from an SQL query
267 static ike_cfg_t
*build_ike_cfg(private_sql_config_t
*this, enumerator_t
*e
,
268 host_t
*my_host
, host_t
*other_host
)
270 int id
, certreq
, force_encap
;
271 char *local
, *remote
;
273 while (e
->enumerate(e
, &id
, &certreq
, &force_encap
, &local
, &remote
))
276 ike_cfg_create_t ike
= {
279 .local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
),
281 .remote_port
= IKEV2_UDP_PORT
,
282 .no_certreq
= !certreq
,
283 .force_encap
= force_encap
,
284 .fragmentation
= FRAGMENTATION_YES
,
287 ike_cfg
= ike_cfg_create(&ike
);
288 add_ike_proposals(this, ike_cfg
, id
);
295 * Query an IKE config by its id
297 static ike_cfg_t
* get_ike_cfg_by_id(private_sql_config_t
*this, int id
)
300 ike_cfg_t
*ike_cfg
= NULL
;
302 e
= this->db
->query(this->db
,
303 "SELECT c.id, c.certreq, c.force_encap, c.local, c.remote "
304 "FROM ike_configs AS c WHERE c.id = ?",
306 DB_INT
, DB_INT
, DB_INT
, DB_TEXT
, DB_TEXT
);
309 ike_cfg
= build_ike_cfg(this, e
, NULL
, NULL
);
317 * Query a peer config by its id
319 static peer_cfg_t
*get_peer_cfg_by_id(private_sql_config_t
*this, int id
)
322 peer_cfg_t
*peer_cfg
= NULL
;
324 e
= this->db
->query(this->db
,
325 "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
326 "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
327 "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
328 "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
329 "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
330 "FROM peer_configs AS c "
331 "JOIN identities AS l ON c.local_id = l.id "
332 "JOIN identities AS r ON c.remote_id = r.id "
333 "LEFT JOIN identities AS p ON c.peer_id = p.id "
336 DB_INT
, DB_TEXT
, DB_INT
, DB_INT
, DB_BLOB
, DB_INT
, DB_BLOB
,
337 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
338 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
339 DB_INT
, DB_TEXT
, DB_TEXT
,
340 DB_INT
, DB_INT
, DB_INT
, DB_BLOB
);
343 peer_cfg
= build_peer_cfg(this, e
, NULL
, NULL
);
351 * Check if the two IDs match (the first one is optional)
353 static inline bool id_matches(identification_t
*id
, identification_t
*sql_id
)
355 return !id
|| id
->matches(id
, sql_id
) || sql_id
->matches(sql_id
, id
);
359 * Build a peer config from an SQL query
361 static peer_cfg_t
*build_peer_cfg(private_sql_config_t
*this, enumerator_t
*e
,
362 identification_t
*me
, identification_t
*other
)
364 int id
, ike_cfg
, l_type
, r_type
,
365 cert_policy
, uniqueid
, auth_method
, eap_type
, eap_vendor
, keyingtries
,
366 rekeytime
, reauthtime
, jitter
, overtime
, mobike
, dpd_delay
,
367 mediation
, mediated_by
, p_type
;
368 chunk_t l_data
, r_data
, p_data
;
369 char *name
, *virtual, *pool
;
370 enumerator_t
*enumerator
;
372 while (e
->enumerate(e
,
373 &id
, &name
, &ike_cfg
, &l_type
, &l_data
, &r_type
, &r_data
,
374 &cert_policy
, &uniqueid
, &auth_method
, &eap_type
, &eap_vendor
,
375 &keyingtries
, &rekeytime
, &reauthtime
, &jitter
, &overtime
, &mobike
,
376 &dpd_delay
, &virtual, &pool
,
377 &mediation
, &mediated_by
, &p_type
, &p_data
))
379 identification_t
*local_id
, *remote_id
, *peer_id
= NULL
;
380 peer_cfg_t
*peer_cfg
, *mediated_cfg
= NULL
;
385 local_id
= identification_create_from_encoding(l_type
, l_data
);
386 remote_id
= identification_create_from_encoding(r_type
, r_data
);
387 if (!id_matches(me
, local_id
) || !id_matches(other
, remote_id
))
389 local_id
->destroy(local_id
);
390 remote_id
->destroy(remote_id
);
393 ike
= get_ike_cfg_by_id(this, ike_cfg
);
396 mediated_cfg
= mediated_by
? get_peer_cfg_by_id(this, mediated_by
)
400 peer_id
= identification_create_from_encoding(p_type
, p_data
);
406 vip
= host_create_from_string(virtual, 0);
410 peer_cfg_create_t peer
= {
411 .cert_policy
= cert_policy
,
413 .keyingtries
= keyingtries
,
414 .rekey_time
= rekeytime
,
415 .reauth_time
= reauthtime
,
416 .jitter_time
= jitter
,
417 .over_time
= overtime
,
418 .no_mobike
= !mobike
,
421 .mediation
= mediation
,
422 .mediated_by
= mediated_cfg
?
423 mediated_cfg
->get_name(mediated_cfg
) : NULL
,
428 peer_cfg
= peer_cfg_create(name
, ike
, &peer
);
431 peer_cfg
->add_virtual_ip(peer_cfg
, vip
);
435 /* attr-sql used comma separated pools, but we now completely
436 * support multiple pools directly. Support old SQL configs: */
437 enumerator
= enumerator_create_token(pool
, ",", " ");
438 while (enumerator
->enumerate(enumerator
, &pool
))
440 peer_cfg
->add_pool(peer_cfg
, pool
);
442 enumerator
->destroy(enumerator
);
444 auth
= auth_cfg_create();
445 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, auth_method
);
446 auth
->add(auth
, AUTH_RULE_IDENTITY
, local_id
);
447 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, TRUE
);
448 auth
= auth_cfg_create();
449 auth
->add(auth
, AUTH_RULE_IDENTITY
, remote_id
);
452 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
453 auth
->add(auth
, AUTH_RULE_EAP_TYPE
, eap_type
);
456 auth
->add(auth
, AUTH_RULE_EAP_VENDOR
, eap_vendor
);
459 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, FALSE
);
460 add_child_cfgs(this, peer_cfg
, id
);
461 DESTROY_IF(mediated_cfg
);
465 DESTROY_IF(mediated_cfg
);
467 DESTROY_IF(local_id
);
468 DESTROY_IF(remote_id
);
473 METHOD(backend_t
, get_peer_cfg_by_name
, peer_cfg_t
*,
474 private_sql_config_t
*this, char *name
)
477 peer_cfg_t
*peer_cfg
= NULL
;
479 e
= this->db
->query(this->db
,
480 "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
481 "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
482 "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
483 "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
484 "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
485 "FROM peer_configs AS c "
486 "JOIN identities AS l ON c.local_id = l.id "
487 "JOIN identities AS r ON c.remote_id = r.id "
488 "LEFT JOIN identities AS p ON c.peer_id = p.id "
489 "WHERE c.ike_version = ? AND c.name = ?",
490 DB_INT
, 2, DB_TEXT
, name
,
491 DB_INT
, DB_TEXT
, DB_INT
, DB_INT
, DB_BLOB
, DB_INT
, DB_BLOB
,
492 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
493 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
494 DB_INT
, DB_TEXT
, DB_TEXT
,
495 DB_INT
, DB_INT
, DB_INT
, DB_BLOB
);
498 peer_cfg
= build_peer_cfg(this, e
, NULL
, NULL
);
505 /** implements enumerator */
507 /** reference to context */
508 private_sql_config_t
*this;
509 /** filtering own host */
511 /** filtering remote host */
513 /** inner SQL enumerator */
515 /** currently enumerated peer config */
519 METHOD(enumerator_t
, ike_enumerator_enumerate
, bool,
520 ike_enumerator_t
*this, va_list args
)
524 VA_ARGS_VGET(args
, cfg
);
525 DESTROY_IF(this->current
);
526 this->current
= build_ike_cfg(this->this, this->inner
, this->me
, this->other
);
529 *cfg
= this->current
;
535 METHOD(enumerator_t
, ike_enumerator_destroy
, void,
536 ike_enumerator_t
*this)
538 DESTROY_IF(this->current
);
539 this->inner
->destroy(this->inner
);
543 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
544 private_sql_config_t
*this, host_t
*me
, host_t
*other
)
550 .enumerate
= enumerator_enumerate_default
,
551 .venumerate
= _ike_enumerator_enumerate
,
552 .destroy
= _ike_enumerator_destroy
,
558 e
->inner
= this->db
->query(this->db
,
559 "SELECT c.id, c.certreq, c.force_encap, "
560 "c.local, c.remote FROM ike_configs AS c",
561 DB_INT
, DB_INT
, DB_INT
, DB_TEXT
, DB_TEXT
);
572 /** implements enumerator */
574 /** reference to context */
575 private_sql_config_t
*this;
576 /** filtering own identity */
577 identification_t
*me
;
578 /** filtering remote identity */
579 identification_t
*other
;
580 /** inner SQL enumerator */
582 /** currently enumerated peer config */
586 METHOD(enumerator_t
, peer_enumerator_enumerate
, bool,
587 peer_enumerator_t
*this, va_list args
)
591 VA_ARGS_VGET(args
, cfg
);
592 DESTROY_IF(this->current
);
593 this->current
= build_peer_cfg(this->this, this->inner
, this->me
, this->other
);
596 *cfg
= this->current
;
602 METHOD(enumerator_t
, peer_enumerator_destroy
, void,
603 peer_enumerator_t
*this)
605 DESTROY_IF(this->current
);
606 this->inner
->destroy(this->inner
);
610 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
611 private_sql_config_t
*this, identification_t
*me
, identification_t
*other
)
613 peer_enumerator_t
*e
;
617 .enumerate
= enumerator_enumerate_default
,
618 .venumerate
= _peer_enumerator_enumerate
,
619 .destroy
= _peer_enumerator_destroy
,
626 /* TODO: only get configs whose IDs match exactly or contain wildcards */
627 e
->inner
= this->db
->query(this->db
,
628 "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
629 "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
630 "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
631 "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
632 "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
633 "FROM peer_configs AS c "
634 "JOIN identities AS l ON c.local_id = l.id "
635 "JOIN identities AS r ON c.remote_id = r.id "
636 "LEFT JOIN identities AS p ON c.peer_id = p.id "
637 "WHERE c.ike_version = ?",
639 DB_INT
, DB_TEXT
, DB_INT
, DB_INT
, DB_BLOB
, DB_INT
, DB_BLOB
,
640 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
641 DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
, DB_INT
,
642 DB_INT
, DB_TEXT
, DB_TEXT
,
643 DB_INT
, DB_INT
, DB_INT
, DB_BLOB
);
652 METHOD(sql_config_t
, destroy
, void,
653 private_sql_config_t
*this)
659 * Described in header.
661 sql_config_t
*sql_config_create(database_t
*db
)
663 private_sql_config_t
*this;
668 .create_peer_cfg_enumerator
= _create_peer_cfg_enumerator
,
669 .create_ike_cfg_enumerator
= _create_ike_cfg_enumerator
,
670 .get_peer_cfg_by_name
= _get_peer_cfg_by_name
,
677 return &this->public;