![]() ![]() | ![]() |
1.1 misho 1: /*
2: * Copyright (C) 2006-2008 Martin Willi
3: * Copyright (C) 2010 Andreas Steffen
4: * HSR 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 ct.kind, t.type, t.protocol, "
106: "t.start_addr, t.end_addr, t.start_port, t.end_port "
107: "FROM traffic_selectors AS t "
108: "JOIN child_config_traffic_selector AS ct "
109: "ON t.id = ct.traffic_selector WHERE ct.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: * Add ESP proposals to a child config
125: */
126: static void add_esp_proposals(private_sql_config_t *this,
127: child_cfg_t *child, int id)
128: {
129: enumerator_t *e;
130: proposal_t *proposal;
131: char *prop;
132: bool use_default = TRUE;
133:
134: e = this->db->query(this->db,
135: "SELECT p.proposal "
136: "FROM proposals AS p JOIN child_config_proposal AS cp "
137: "ON p.id = cp.prop WHERE cp.child_cfg = ? ORDER BY cp.prio",
138: DB_INT, id, DB_TEXT);
139: if (e)
140: {
141: while (e->enumerate(e, &prop))
142: {
143: proposal = proposal_create_from_string(PROTO_ESP, prop);
144: if (!proposal)
145: {
146: DBG1(DBG_CFG, "could not create ESP proposal from '%s'", prop);
147: break;
148: }
149: child->add_proposal(child, proposal);
150: use_default = FALSE;
151: }
152: e->destroy(e);
153: }
154: if (use_default)
155: {
156: child->add_proposal(child, proposal_create_default_aead(PROTO_ESP));
1.1.1.2 ! misho 157: child->add_proposal(child, proposal_create_default(PROTO_ESP));
1.1 misho 158: }
159: }
160:
161: /**
162: * Build a child config from an SQL query
163: */
164: static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
165: {
166: int id, lifetime, rekeytime, jitter, hostaccess, mode, ipcomp, reqid;
167: int start, dpd, close;
168: char *name, *updown;
169: child_cfg_t *child_cfg;
170:
171: if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, &updown,
172: &hostaccess, &mode, &start, &dpd, &close, &ipcomp, &reqid))
173: {
174: child_cfg_create_t child = {
175: .mode = mode,
176: .reqid = reqid,
177: .options = (ipcomp ? OPT_IPCOMP : 0) |
178: (hostaccess ? OPT_HOSTACCESS : 0),
179: .lifetime = {
180: .time = {
181: .life = lifetime, .rekey = rekeytime, .jitter = jitter
182: },
183: },
184: .start_action = start,
185: .dpd_action = dpd,
186: .close_action = close,
187: .updown = updown,
188: };
189: child_cfg = child_cfg_create(name, &child);
190: add_esp_proposals(this, child_cfg, id);
191: add_traffic_selectors(this, child_cfg, id);
192: return child_cfg;
193: }
194: return NULL;
195: }
196:
197: /**
198: * Add child configs to peer config
199: */
200: static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id)
201: {
202: enumerator_t *e;
203: child_cfg_t *child_cfg;
204:
205: e = this->db->query(this->db,
206: "SELECT c.id, c.name, c.lifetime, c.rekeytime, c.jitter, c.updown, "
207: "c.hostaccess, c.mode, c.start_action, c.dpd_action, "
208: "c.close_action, c.ipcomp, c.reqid "
209: "FROM child_configs AS c JOIN peer_config_child_config AS pc "
210: "ON c.id = pc.child_cfg WHERE pc.peer_cfg = ?",
211: DB_INT, id,
212: DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_TEXT, DB_INT,
213: DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
214: if (e)
215: {
216: while ((child_cfg = build_child_cfg(this, e)))
217: {
218: peer->add_child_cfg(peer, child_cfg);
219: }
220: e->destroy(e);
221: }
222: }
223:
224: /**
225: * Add IKE proposals to an IKE config
226: */
227: static void add_ike_proposals(private_sql_config_t *this,
228: ike_cfg_t *ike_cfg, int id)
229: {
230: enumerator_t *e;
231: proposal_t *proposal;
232: char *prop;
233: bool use_default = TRUE;
234:
235: e = this->db->query(this->db,
236: "SELECT p.proposal "
237: "FROM proposals AS p "
238: "JOIN ike_config_proposal AS ip ON p.id = ip.prop "
239: "WHERE ip.ike_cfg = ? ORDER BY ip.prio",
240: DB_INT, id, DB_TEXT);
241: if (e)
242: {
243: while (e->enumerate(e, &prop))
244: {
245: proposal = proposal_create_from_string(PROTO_IKE, prop);
246: if (!proposal)
247: {
248: DBG1(DBG_CFG, "could not create IKE proposal from '%s'", prop);
249: break;
250: }
251: ike_cfg->add_proposal(ike_cfg, proposal);
252: use_default = FALSE;
253: }
254: e->destroy(e);
255: }
256: if (use_default)
257: {
258: ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
259: ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
260: }
261: }
262:
263: /**
264: * Build an IKE config from an SQL query
265: */
266: static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
267: host_t *my_host, host_t *other_host)
268: {
269: int id, certreq, force_encap;
270: char *local, *remote;
271:
272: while (e->enumerate(e, &id, &certreq, &force_encap, &local, &remote))
273: {
274: ike_cfg_t *ike_cfg;
275: ike_cfg_create_t ike = {
276: .version = IKEV2,
277: .local = local,
278: .local_port = charon->socket->get_port(charon->socket, FALSE),
279: .remote = remote,
280: .remote_port = IKEV2_UDP_PORT,
281: .no_certreq = !certreq,
282: .force_encap = force_encap,
283: .fragmentation = FRAGMENTATION_YES,
284: };
285:
286: ike_cfg = ike_cfg_create(&ike);
287: add_ike_proposals(this, ike_cfg, id);
288: return ike_cfg;
289: }
290: return NULL;
291: }
292:
293: /**
294: * Query an IKE config by its id
295: */
296: static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id)
297: {
298: enumerator_t *e;
299: ike_cfg_t *ike_cfg = NULL;
300:
301: e = this->db->query(this->db,
302: "SELECT c.id, c.certreq, c.force_encap, c.local, c.remote "
303: "FROM ike_configs AS c WHERE c.id = ?",
304: DB_INT, id,
305: DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
306: if (e)
307: {
308: ike_cfg = build_ike_cfg(this, e, NULL, NULL);
309: e->destroy(e);
310: }
311: return ike_cfg;
312: }
313:
314: #ifdef ME
315: /**
316: * Query a peer config by its id
317: */
318: static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
319: {
320: enumerator_t *e;
321: peer_cfg_t *peer_cfg = NULL;
322:
323: e = this->db->query(this->db,
324: "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
325: "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
326: "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
327: "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
328: "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
329: "FROM peer_configs AS c "
330: "JOIN identities AS l ON c.local_id = l.id "
331: "JOIN identities AS r ON c.remote_id = r.id "
332: "LEFT JOIN identities AS p ON c.peer_id = p.id "
333: "WHERE c.id = ?",
334: DB_INT, id,
335: DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
336: DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
337: DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
338: DB_INT, DB_TEXT, DB_TEXT,
339: DB_INT, DB_INT, DB_INT, DB_BLOB);
340: if (e)
341: {
342: peer_cfg = build_peer_cfg(this, e, NULL, NULL);
343: e->destroy(e);
344: }
345: return peer_cfg;
346: }
347: #endif /* ME */
348:
349: /**
350: * Check if the two IDs match (the first one is optional)
351: */
352: static inline bool id_matches(identification_t *id, identification_t *sql_id)
353: {
354: return !id || id->matches(id, sql_id) || sql_id->matches(sql_id, id);
355: }
356:
357: /**
358: * Build a peer config from an SQL query
359: */
360: static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
361: identification_t *me, identification_t *other)
362: {
363: int id, ike_cfg, l_type, r_type,
364: cert_policy, uniqueid, auth_method, eap_type, eap_vendor, keyingtries,
365: rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay,
366: mediation, mediated_by, p_type;
367: chunk_t l_data, r_data, p_data;
368: char *name, *virtual, *pool;
369: enumerator_t *enumerator;
370:
371: while (e->enumerate(e,
372: &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data,
373: &cert_policy, &uniqueid, &auth_method, &eap_type, &eap_vendor,
374: &keyingtries, &rekeytime, &reauthtime, &jitter, &overtime, &mobike,
375: &dpd_delay, &virtual, &pool,
376: &mediation, &mediated_by, &p_type, &p_data))
377: {
378: identification_t *local_id, *remote_id, *peer_id = NULL;
379: peer_cfg_t *peer_cfg, *mediated_cfg = NULL;
380: ike_cfg_t *ike;
381: host_t *vip = NULL;
382: auth_cfg_t *auth;
383:
384: local_id = identification_create_from_encoding(l_type, l_data);
385: remote_id = identification_create_from_encoding(r_type, r_data);
386: if (!id_matches(me, local_id) || !id_matches(other, remote_id))
387: {
388: local_id->destroy(local_id);
389: remote_id->destroy(remote_id);
390: continue;
391: }
392: ike = get_ike_cfg_by_id(this, ike_cfg);
393:
394: #ifdef ME
395: mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by)
396: : NULL;
397: if (p_type)
398: {
399: peer_id = identification_create_from_encoding(p_type, p_data);
400: }
401: #endif /* ME */
402:
403: if (virtual)
404: {
405: vip = host_create_from_string(virtual, 0);
406: }
407: if (ike)
408: {
409: peer_cfg_create_t peer = {
410: .cert_policy = cert_policy,
411: .unique = uniqueid,
412: .keyingtries = keyingtries,
413: .rekey_time = rekeytime,
414: .reauth_time = reauthtime,
415: .jitter_time = jitter,
416: .over_time = overtime,
417: .no_mobike = !mobike,
418: .dpd = dpd_delay,
419: #ifdef ME
420: .mediation = mediation,
421: .mediated_by = mediated_cfg ?
422: mediated_cfg->get_name(mediated_cfg) : NULL,
423: .peer_id = peer_id,
424: #endif /* ME */
425: };
426:
427: peer_cfg = peer_cfg_create(name, ike, &peer);
428: if (vip)
429: {
430: peer_cfg->add_virtual_ip(peer_cfg, vip);
431: }
432: if (pool)
433: {
434: /* attr-sql used comma separated pools, but we now completely
435: * support multiple pools directly. Support old SQL configs: */
436: enumerator = enumerator_create_token(pool, ",", " ");
437: while (enumerator->enumerate(enumerator, &pool))
438: {
439: peer_cfg->add_pool(peer_cfg, pool);
440: }
441: enumerator->destroy(enumerator);
442: }
443: auth = auth_cfg_create();
444: auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method);
445: auth->add(auth, AUTH_RULE_IDENTITY, local_id);
446: peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
447: auth = auth_cfg_create();
448: auth->add(auth, AUTH_RULE_IDENTITY, remote_id);
449: if (eap_type)
450: {
451: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
452: auth->add(auth, AUTH_RULE_EAP_TYPE, eap_type);
453: if (eap_vendor)
454: {
455: auth->add(auth, AUTH_RULE_EAP_VENDOR, eap_vendor);
456: }
457: }
458: peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
459: add_child_cfgs(this, peer_cfg, id);
460: DESTROY_IF(mediated_cfg);
461: return peer_cfg;
462: }
463: DESTROY_IF(ike);
464: DESTROY_IF(mediated_cfg);
465: DESTROY_IF(peer_id);
466: DESTROY_IF(local_id);
467: DESTROY_IF(remote_id);
468: }
469: return NULL;
470: }
471:
472: METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
473: private_sql_config_t *this, char *name)
474: {
475: enumerator_t *e;
476: peer_cfg_t *peer_cfg = NULL;
477:
478: e = this->db->query(this->db,
479: "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
480: "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
481: "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
482: "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
483: "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
484: "FROM peer_configs AS c "
485: "JOIN identities AS l ON c.local_id = l.id "
486: "JOIN identities AS r ON c.remote_id = r.id "
487: "LEFT JOIN identities AS p ON c.peer_id = p.id "
488: "WHERE c.ike_version = ? AND c.name = ?",
489: DB_INT, 2, DB_TEXT, name,
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)
496: {
497: peer_cfg = build_peer_cfg(this, e, NULL, NULL);
498: e->destroy(e);
499: }
500: return peer_cfg;
501: }
502:
503: typedef struct {
504: /** implements enumerator */
505: enumerator_t public;
506: /** reference to context */
507: private_sql_config_t *this;
508: /** filtering own host */
509: host_t *me;
510: /** filtering remote host */
511: host_t *other;
512: /** inner SQL enumerator */
513: enumerator_t *inner;
514: /** currently enumerated peer config */
515: ike_cfg_t *current;
516: } ike_enumerator_t;
517:
518: METHOD(enumerator_t, ike_enumerator_enumerate, bool,
519: ike_enumerator_t *this, va_list args)
520: {
521: ike_cfg_t **cfg;
522:
523: VA_ARGS_VGET(args, cfg);
524: DESTROY_IF(this->current);
525: this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
526: if (this->current)
527: {
528: *cfg = this->current;
529: return TRUE;
530: }
531: return FALSE;
532: }
533:
534: METHOD(enumerator_t, ike_enumerator_destroy, void,
535: ike_enumerator_t *this)
536: {
537: DESTROY_IF(this->current);
538: this->inner->destroy(this->inner);
539: free(this);
540: }
541:
542: METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
543: private_sql_config_t *this, host_t *me, host_t *other)
544: {
545: ike_enumerator_t *e;
546:
547: INIT(e,
548: .public = {
549: .enumerate = enumerator_enumerate_default,
550: .venumerate = _ike_enumerator_enumerate,
551: .destroy = _ike_enumerator_destroy,
552: },
553: .this = this,
554: .me = me,
555: .other = other,
556: );
557: e->inner = this->db->query(this->db,
558: "SELECT c.id, c.certreq, c.force_encap, "
559: "c.local, c.remote FROM ike_configs AS c",
560: DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
561: if (!e->inner)
562: {
563: free(e);
564: return NULL;
565: }
566: return &e->public;
567: }
568:
569:
570: typedef struct {
571: /** implements enumerator */
572: enumerator_t public;
573: /** reference to context */
574: private_sql_config_t *this;
575: /** filtering own identity */
576: identification_t *me;
577: /** filtering remote identity */
578: identification_t *other;
579: /** inner SQL enumerator */
580: enumerator_t *inner;
581: /** currently enumerated peer config */
582: peer_cfg_t *current;
583: } peer_enumerator_t;
584:
585: METHOD(enumerator_t, peer_enumerator_enumerate, bool,
586: peer_enumerator_t *this, va_list args)
587: {
588: peer_cfg_t **cfg;
589:
590: VA_ARGS_VGET(args, cfg);
591: DESTROY_IF(this->current);
592: this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
593: if (this->current)
594: {
595: *cfg = this->current;
596: return TRUE;
597: }
598: return FALSE;
599: }
600:
601: METHOD(enumerator_t, peer_enumerator_destroy, void,
602: peer_enumerator_t *this)
603: {
604: DESTROY_IF(this->current);
605: this->inner->destroy(this->inner);
606: free(this);
607: }
608:
609: METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
610: private_sql_config_t *this, identification_t *me, identification_t *other)
611: {
612: peer_enumerator_t *e;
613:
614: INIT(e,
615: .public = {
616: .enumerate = enumerator_enumerate_default,
617: .venumerate = _peer_enumerator_enumerate,
618: .destroy = _peer_enumerator_destroy,
619: },
620: .this = this,
621: .me = me,
622: .other = other,
623: );
624:
625: /* TODO: only get configs whose IDs match exactly or contain wildcards */
626: e->inner = this->db->query(this->db,
627: "SELECT c.id, c.name, c.ike_cfg, l.type, l.data, r.type, r.data, "
628: "c.cert_policy, c.uniqueid, c.auth_method, c.eap_type, "
629: "c.eap_vendor, c.keyingtries, c.rekeytime, c.reauthtime, c.jitter, "
630: "c.overtime, c.mobike, c.dpd_delay, c.virtual, c.pool, "
631: "c.mediation, c.mediated_by, COALESCE(p.type, 0), p.data "
632: "FROM peer_configs AS c "
633: "JOIN identities AS l ON c.local_id = l.id "
634: "JOIN identities AS r ON c.remote_id = r.id "
635: "LEFT JOIN identities AS p ON c.peer_id = p.id "
636: "WHERE c.ike_version = ?",
637: DB_INT, 2,
638: DB_INT, DB_TEXT, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB,
639: DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
640: DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT,
641: DB_INT, DB_TEXT, DB_TEXT,
642: DB_INT, DB_INT, DB_INT, DB_BLOB);
643: if (!e->inner)
644: {
645: free(e);
646: return NULL;
647: }
648: return &e->public;
649: }
650:
651: METHOD(sql_config_t, destroy, void,
652: private_sql_config_t *this)
653: {
654: free(this);
655: }
656:
657: /**
658: * Described in header.
659: */
660: sql_config_t *sql_config_create(database_t *db)
661: {
662: private_sql_config_t *this;
663:
664: INIT(this,
665: .public = {
666: .backend = {
667: .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
668: .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
669: .get_peer_cfg_by_name = _get_peer_cfg_by_name,
670: },
671: .destroy = _destroy,
672: },
673: .db = db
674: );
675:
676: return &this->public;
677: }