prototype implemementation of an sqlite configuration backend
[strongswan.git] / src / charon / config / backends / local_backend.c
1 /**
2 * @file local_backend.c
3 *
4 * @brief Implementation of local_backend_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <string.h>
24
25 #include "local_backend.h"
26
27 #include <daemon.h>
28 #include <utils/linked_list.h>
29 #include <crypto/ca.h>
30
31
32 typedef struct private_local_backend_t private_local_backend_t;
33
34 /**
35 * Private data of an local_backend_t object
36 */
37 struct private_local_backend_t {
38
39 /**
40 * Public part
41 */
42 local_backend_t public;
43
44 /**
45 * list of configs
46 */
47 linked_list_t *cfgs;
48
49 /**
50 * Mutex to exclusivly access list
51 */
52 pthread_mutex_t mutex;
53 };
54
55 /**
56 * implements backen_t.get_ike_cfg.
57 */
58 static ike_cfg_t *get_ike_cfg(private_local_backend_t *this,
59 host_t *my_host, host_t *other_host)
60 {
61 peer_cfg_t *peer;
62 ike_cfg_t *current, *found = NULL;
63 iterator_t *iterator;
64 host_t *my_candidate, *other_candidate;
65 enum {
66 MATCH_NONE = 0x00,
67 MATCH_ANY = 0x01,
68 MATCH_ME = 0x04,
69 MATCH_OTHER = 0x08,
70 } prio, best = MATCH_ANY;
71
72 DBG2(DBG_CFG, "looking for a config for %H...%H",
73 my_host, other_host);
74
75 iterator = this->cfgs->create_iterator_locked(this->cfgs, &this->mutex);
76 while (iterator->iterate(iterator, (void**)&peer))
77 {
78 prio = MATCH_NONE;
79 current = peer->get_ike_cfg(peer);
80 my_candidate = current->get_my_host(current);
81 other_candidate = current->get_other_host(current);
82
83 if (my_candidate->ip_equals(my_candidate, my_host))
84 {
85 prio += MATCH_ME;
86 }
87 else if (my_candidate->is_anyaddr(my_candidate))
88 {
89 prio += MATCH_ANY;
90 }
91
92 if (other_candidate->ip_equals(other_candidate, other_host))
93 {
94 prio += MATCH_OTHER;
95 }
96 else if (other_candidate->is_anyaddr(other_candidate))
97 {
98 prio += MATCH_ANY;
99 }
100
101 DBG2(DBG_CFG, " candidate '%s': %H...%H, prio %d",
102 peer->get_name(peer), my_candidate, other_candidate, prio);
103
104 /* we require at least two MATCH_ANY */
105 if (prio > best)
106 {
107 best = prio;
108 found = current;
109 }
110 }
111 if (found)
112 {
113 found->get_ref(found);
114 }
115 iterator->destroy(iterator);
116 return found;
117 }
118
119 #define PRIO_NO_MATCH_FOUND 256
120
121 /**
122 * implements backend_t.get_peer.
123 */
124 static peer_cfg_t *get_peer_cfg(private_local_backend_t *this,
125 identification_t *my_id, identification_t *other_id,
126 ca_info_t *other_ca_info)
127 {
128 peer_cfg_t *current, *found = NULL;
129 iterator_t *iterator;
130 identification_t *my_candidate, *other_candidate;
131 int best = PRIO_NO_MATCH_FOUND;
132
133 DBG2(DBG_CFG, "looking for a config for %D...%D", my_id, other_id);
134
135 iterator = this->cfgs->create_iterator_locked(this->cfgs, &this->mutex);
136 while (iterator->iterate(iterator, (void**)&current))
137 {
138 int wc1, wc2;
139
140 my_candidate = current->get_my_id(current);
141 other_candidate = current->get_other_id(current);
142
143 if (my_candidate->matches(my_candidate, my_id, &wc1)
144 && other_id->matches(other_id, other_candidate, &wc2))
145 {
146 int prio = (wc1 + wc2) * (MAX_CA_PATH_LEN + 1);
147 int pathlen = 0;
148 identification_t *other_candidate_ca = current->get_other_ca(current);
149 linked_list_t *groups = current->get_groups(current);
150
151 /* is a group membership required? */
152 if (groups->get_count(groups) > 0)
153 {
154 DBG1(DBG_CFG, " group membership required");
155 }
156
157 /* are there any ca constraints? */
158 if (other_candidate_ca->get_type(other_candidate_ca) != ID_ANY)
159 {
160 ca_info_t *ca_info = other_ca_info;
161
162 for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
163 {
164 if (ca_info == NULL)
165 {
166 prio = PRIO_NO_MATCH_FOUND;
167 break;
168 }
169 else
170 {
171 x509_t *cacert = ca_info->get_certificate(ca_info);
172 identification_t *other_ca = cacert->get_subject(cacert);
173
174 if (other_candidate_ca->equals(other_candidate_ca, other_ca))
175 {
176 /* found a ca match */
177 break;
178 }
179 if (cacert->is_self_signed(cacert))
180 {
181 /* reached the root ca without a match */
182 prio = PRIO_NO_MATCH_FOUND;
183 break;
184 }
185 /* move a level upward in the trust path hierarchy */
186 ca_info = charon->credentials->get_issuer(charon->credentials, cacert);
187 }
188 }
189 if (pathlen == MAX_CA_PATH_LEN)
190 {
191 DBG1(DBG_CFG, "maximum ca path length of %d levels reached", MAX_CA_PATH_LEN);
192 prio = PRIO_NO_MATCH_FOUND;
193 }
194 }
195 if (prio == PRIO_NO_MATCH_FOUND)
196 {
197 DBG2(DBG_CFG, " candidate '%s': %D...%D, no ca match",
198 current->get_name(current), my_candidate, other_candidate);
199 }
200 else
201 {
202 prio += pathlen;
203 DBG2(DBG_CFG, " candidate '%s': %D...%D, prio %d",
204 current->get_name(current), my_candidate, other_candidate, prio);
205
206 if (prio < best)
207 {
208 found = current;
209 best = prio;
210 }
211 }
212 }
213 }
214 if (found)
215 {
216 DBG1(DBG_CFG, "found matching config \"%s\": %D...%D, prio %d",
217 found->get_name(found),
218 found->get_my_id(found),
219 found->get_other_id(found),
220 best);
221 found->get_ref(found);
222 }
223 iterator->destroy(iterator);
224 return found;
225 }
226
227 /**
228 * implements backend_t.get_peer_cfg_by_name.
229 */
230 static peer_cfg_t *get_peer_cfg_by_name(private_local_backend_t *this, char *name)
231 {
232 iterator_t *i1, *i2;
233 peer_cfg_t *current, *found = NULL;
234 child_cfg_t *child;
235
236 i1 = this->cfgs->create_iterator(this->cfgs, TRUE);
237 while (i1->iterate(i1, (void**)&current))
238 {
239 /* compare peer_cfgs name first */
240 if (streq(current->get_name(current), name))
241 {
242 found = current;
243 found->get_ref(found);
244 break;
245 }
246 /* compare all child_cfg names otherwise */
247 i2 = current->create_child_cfg_iterator(current);
248 while (i2->iterate(i2, (void**)&child))
249 {
250 if (streq(child->get_name(child), name))
251 {
252 found = current;
253 found->get_ref(found);
254 break;
255 }
256 }
257 i2->destroy(i2);
258 if (found)
259 {
260 break;
261 }
262 }
263 i1->destroy(i1);
264 return found;
265 }
266
267 /**
268 * Implementation of backend_t.is_writable.
269 */
270 static bool is_writeable(private_local_backend_t *this)
271 {
272 return TRUE;
273 }
274
275 /**
276 * Implementation of writable_backend_t.create_iterator.
277 */
278 static iterator_t* create_iterator(private_local_backend_t *this)
279 {
280 return this->cfgs->create_iterator_locked(this->cfgs, &this->mutex);
281 }
282
283 /**
284 * Implementation of writable_backend_t.add_peer_cfg.
285 */
286 static void add_cfg(private_local_backend_t *this, peer_cfg_t *config)
287 {
288 pthread_mutex_lock(&this->mutex);
289 this->cfgs->insert_last(this->cfgs, config);
290 pthread_mutex_unlock(&this->mutex);
291 }
292
293 /**
294 * Implementation of backend_t.destroy.
295 */
296 static void destroy(private_local_backend_t *this)
297 {
298 this->cfgs->destroy_offset(this->cfgs, offsetof(peer_cfg_t, destroy));
299 free(this);
300 }
301
302 /**
303 * Described in header.
304 */
305 backend_t *backend_create(void)
306 {
307 private_local_backend_t *this = malloc_thing(private_local_backend_t);
308
309 this->public.backend.backend.get_ike_cfg = (ike_cfg_t* (*)(backend_t*, host_t*, host_t*))get_ike_cfg;
310 this->public.backend.backend.get_peer_cfg = (peer_cfg_t* (*)(backend_t*,identification_t*,identification_t*,ca_info_t*))get_peer_cfg;
311 this->public.backend.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
312 this->public.backend.backend.is_writeable = (bool(*) (backend_t*))is_writeable;
313 this->public.backend.backend.destroy = (void (*)(backend_t*))destroy;
314 this->public.backend.create_iterator = (iterator_t* (*)(writeable_backend_t*))create_iterator;
315 this->public.backend.add_cfg = (void (*)(writeable_backend_t*,peer_cfg_t*))add_cfg;
316
317 /* private variables */
318 this->cfgs = linked_list_create();
319 pthread_mutex_init(&this->mutex, NULL);
320
321 return &this->public.backend.backend;
322 }