fixed crash if crl fetching fails
[strongswan.git] / src / charon / config / child_cfg.c
1 /*
2 * Copyright (C) 2005-2007 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
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 * $Id$
17 */
18
19 #include "child_cfg.h"
20
21 #include <daemon.h>
22
23 ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
24 "TRANSPORT",
25 "TUNNEL",
26 "2",
27 "3",
28 "BEET",
29 );
30
31 typedef struct private_child_cfg_t private_child_cfg_t;
32
33 /**
34 * Private data of an child_cfg_t object
35 */
36 struct private_child_cfg_t {
37
38 /**
39 * Public part
40 */
41 child_cfg_t public;
42
43 /**
44 * Number of references hold by others to this child_cfg
45 */
46 refcount_t refcount;
47
48 /**
49 * Name of the child_cfg, used to query it
50 */
51 char *name;
52
53 /**
54 * list for all proposals
55 */
56 linked_list_t *proposals;
57
58 /**
59 * list for traffic selectors for my site
60 */
61 linked_list_t *my_ts;
62
63 /**
64 * list for traffic selectors for others site
65 */
66 linked_list_t *other_ts;
67
68 /**
69 * updown script
70 */
71 char *updown;
72
73 /**
74 * allow host access
75 */
76 bool hostaccess;
77
78 /**
79 * Mode to propose for a initiated CHILD: tunnel/transport
80 */
81 mode_t mode;
82
83 /**
84 * Time before an SA gets invalid
85 */
86 u_int32_t lifetime;
87
88 /**
89 * Time before an SA gets rekeyed
90 */
91 u_int32_t rekeytime;
92
93 /**
94 * Time, which specifies the range of a random value
95 * substracted from rekeytime.
96 */
97 u_int32_t jitter;
98 };
99
100 /**
101 * Implementation of child_cfg_t.get_name
102 */
103 static char *get_name(private_child_cfg_t *this)
104 {
105 return this->name;
106 }
107
108 /**
109 * Implementation of child_cfg_t.add_proposal
110 */
111 static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
112 {
113 this->proposals->insert_last(this->proposals, proposal);
114 }
115
116 /**
117 * Implementation of child_cfg_t.get_proposals
118 */
119 static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
120 {
121 enumerator_t *enumerator;
122 proposal_t *current;
123 linked_list_t *proposals = linked_list_create();
124
125 enumerator = this->proposals->create_enumerator(this->proposals);
126 while (enumerator->enumerate(enumerator, &current))
127 {
128 current = current->clone(current);
129 if (strip_dh)
130 {
131 current->strip_dh(current);
132 }
133 proposals->insert_last(proposals, current);
134 }
135 enumerator->destroy(enumerator);
136
137 return proposals;
138 }
139
140 /**
141 * Implementation of child_cfg_t.get_name
142 */
143 static proposal_t* select_proposal(private_child_cfg_t*this,
144 linked_list_t *proposals, bool strip_dh)
145 {
146 enumerator_t *stored_enum, *supplied_enum;
147 proposal_t *stored, *supplied, *selected = NULL;
148
149 stored_enum = this->proposals->create_enumerator(this->proposals);
150 supplied_enum = proposals->create_enumerator(proposals);
151
152 /* compare all stored proposals with all supplied. Stored ones are preferred. */
153 while (stored_enum->enumerate(stored_enum, &stored))
154 {
155 stored = stored->clone(stored);
156 while (supplied_enum->enumerate(supplied_enum, &supplied))
157 {
158 if (strip_dh)
159 {
160 stored->strip_dh(stored);
161 }
162 selected = stored->select(stored, supplied);
163 if (selected)
164 {
165 break;
166 }
167 }
168 stored->destroy(stored);
169 if (selected)
170 {
171 break;
172 }
173 supplied_enum->destroy(supplied_enum);
174 supplied_enum = proposals->create_enumerator(proposals);
175 }
176 stored_enum->destroy(stored_enum);
177 supplied_enum->destroy(supplied_enum);
178 return selected;
179 }
180
181 /**
182 * Implementation of child_cfg_t.get_name
183 */
184 static void add_traffic_selector(private_child_cfg_t *this, bool local,
185 traffic_selector_t *ts)
186 {
187 if (local)
188 {
189 this->my_ts->insert_last(this->my_ts, ts);
190 }
191 else
192 {
193 this->other_ts->insert_last(this->other_ts, ts);
194 }
195 }
196
197 /**
198 * Implementation of child_cfg_t.get_name
199 */
200 static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
201 linked_list_t *supplied,
202 host_t *host)
203 {
204 enumerator_t *e1, *e2;
205 traffic_selector_t *ts1, *ts2, *selected;
206 linked_list_t *result = linked_list_create();
207
208 if (local)
209 {
210 e1 = this->my_ts->create_enumerator(this->my_ts);
211 }
212 else
213 {
214 e1 = this->other_ts->create_enumerator(this->other_ts);
215 }
216
217 /* no list supplied, just fetch the stored traffic selectors */
218 if (supplied == NULL)
219 {
220 DBG2(DBG_CFG, "proposing traffic selectors for %s:",
221 local ? "us" : "other");
222 while (e1->enumerate(e1, &ts1))
223 {
224 /* we make a copy of the TS, this allows us to update dynamic TS' */
225 selected = ts1->clone(ts1);
226 if (host)
227 {
228 selected->set_address(selected, host);
229 }
230 DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
231 result->insert_last(result, selected);
232 }
233 e1->destroy(e1);
234 }
235 else
236 {
237 DBG2(DBG_CFG, "selecting traffic selectors for %s:",
238 local ? "us" : "other");
239 e2 = supplied->create_enumerator(supplied);
240 /* iterate over all stored selectors */
241 while (e1->enumerate(e1, &ts1))
242 {
243 /* we make a copy of the TS, as we have to update dynamic TS' */
244 ts1 = ts1->clone(ts1);
245 if (host)
246 {
247 ts1->set_address(ts1, host);
248 }
249
250 /* iterate over all supplied traffic selectors */
251 while (e2->enumerate(e2, &ts2))
252 {
253 selected = ts1->get_subset(ts1, ts2);
254 if (selected)
255 {
256 DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
257 ts1, ts2, selected);
258 result->insert_last(result, selected);
259 }
260 else
261 {
262 DBG2(DBG_CFG, " config: %R, received: %R => no match",
263 ts1, ts2, selected);
264 }
265 }
266 e2->destroy(e2);
267 e2 = supplied->create_enumerator(supplied);
268 ts1->destroy(ts1);
269 }
270 e1->destroy(e1);
271 e2->destroy(e2);
272 }
273
274 /* remove any redundant traffic selectors in the list */
275 e1 = result->create_enumerator(result);
276 e2 = result->create_enumerator(result);
277 while (e1->enumerate(e1, &ts1))
278 {
279 while (e2->enumerate(e2, &ts2))
280 {
281 if (ts1 != ts2)
282 {
283 if (ts2->is_contained_in(ts2, ts1))
284 {
285 result->remove_at(result, e2);
286 ts2->destroy(ts2);
287 e1->destroy(e1);
288 e1 = result->create_enumerator(result);
289 break;
290 }
291 if (ts1->is_contained_in(ts1, ts2))
292 {
293 result->remove_at(result, e1);
294 ts1->destroy(ts1);
295 e2->destroy(e2);
296 e2 = result->create_enumerator(result);
297 break;
298 }
299 }
300 }
301 }
302 e1->destroy(e1);
303 e2->destroy(e2);
304
305 return result;
306 }
307
308 /**
309 * Implementation of child_cfg_t.get_name
310 */
311 static char* get_updown(private_child_cfg_t *this)
312 {
313 return this->updown;
314 }
315
316 /**
317 * Implementation of child_cfg_t.get_name
318 */
319 static bool get_hostaccess(private_child_cfg_t *this)
320 {
321 return this->hostaccess;
322 }
323
324 /**
325 * Implementation of child_cfg_t.get_name
326 */
327 static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey)
328 {
329 if (rekey)
330 {
331 if (this->jitter == 0)
332 {
333 return this->rekeytime;
334 }
335 return this->rekeytime - (random() % this->jitter);
336 }
337 return this->lifetime;
338 }
339
340 /**
341 * Implementation of child_cfg_t.get_name
342 */
343 static mode_t get_mode(private_child_cfg_t *this)
344 {
345 return this->mode;
346 }
347
348 /**
349 * Implementation of child_cfg_t.get_dh_group.
350 */
351 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
352 {
353 enumerator_t *enumerator;
354 proposal_t *proposal;
355 u_int16_t dh_group = MODP_NONE;
356
357 enumerator = this->proposals->create_enumerator(this->proposals);
358 while (enumerator->enumerate(enumerator, &proposal))
359 {
360 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
361 {
362 break;
363 }
364 }
365 enumerator->destroy(enumerator);
366 return dh_group;
367 }
368
369 /**
370 * Implementation of child_cfg_t.get_name
371 */
372 static void get_ref(private_child_cfg_t *this)
373 {
374 ref_get(&this->refcount);
375 }
376
377 /**
378 * Implements child_cfg_t.destroy.
379 */
380 static void destroy(private_child_cfg_t *this)
381 {
382 if (ref_put(&this->refcount))
383 {
384 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
385 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
386 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
387 if (this->updown)
388 {
389 free(this->updown);
390 }
391 free(this->name);
392 free(this);
393 }
394 }
395
396 /*
397 * Described in header-file
398 */
399 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
400 u_int32_t rekeytime, u_int32_t jitter,
401 char *updown, bool hostaccess, mode_t mode)
402 {
403 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
404
405 /* public functions */
406 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
407 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
408 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
409 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
410 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
411 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
412 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
413 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
414 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
415 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
416 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
417 this->public.get_ref = (void (*) (child_cfg_t*))get_ref;
418 this->public.destroy = (void (*) (child_cfg_t*))destroy;
419
420 /* apply init values */
421 this->name = strdup(name);
422 this->lifetime = lifetime;
423 this->rekeytime = rekeytime;
424 this->jitter = jitter;
425 this->updown = updown ? strdup(updown) : NULL;
426 this->hostaccess = hostaccess;
427 this->mode = mode;
428
429 /* initialize private members*/
430 this->refcount = 1;
431 this->proposals = linked_list_create();
432 this->my_ts = linked_list_create();
433 this->other_ts = linked_list_create();
434
435 return &this->public;
436 }