fixed double free bug
[strongswan.git] / src / charon / config / policies / policy.c
1 /**
2 * @file policy.c
3 *
4 * @brief Implementation of policy_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <time.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "policy.h"
29
30 #include <daemon.h>
31 #include <utils/linked_list.h>
32 #include <utils/identification.h>
33
34 ENUM(dpd_action_names, DPD_NONE, DPD_RESTART,
35 "DPD_NONE",
36 "DPD_CLEAR",
37 "DPD_ROUTE",
38 "DPD_RESTART"
39 );
40
41 ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
42 "TRANSPORT",
43 "TUNNEL",
44 "2",
45 "3",
46 "BEET"
47 );
48
49 typedef struct private_policy_t private_policy_t;
50
51 /**
52 * Private data of an policy_t object
53 */
54 struct private_policy_t {
55
56 /**
57 * Public part
58 */
59 policy_t public;
60
61 /**
62 * Number of references hold by others to this policy
63 */
64 refcount_t refcount;
65
66 /**
67 * Name of the policy, used to query it
68 */
69 char *name;
70
71 /**
72 * id to use to identify us
73 */
74 identification_t *my_id;
75
76 /**
77 * allowed id for other
78 */
79 identification_t *other_id;
80
81 /**
82 * virtual IP to use locally
83 */
84 host_t *my_virtual_ip;
85
86 /**
87 * virtual IP to use remotly
88 */
89 host_t *other_virtual_ip;
90
91 /**
92 * Method to use for own authentication data
93 */
94 auth_method_t auth_method;
95
96 /**
97 * EAP type to use for peer authentication
98 */
99 eap_type_t eap_type;
100
101 /**
102 * we have a cert issued by this CA
103 */
104 identification_t *my_ca;
105
106 /**
107 * we require the other end to have a cert issued by this CA
108 */
109 identification_t *other_ca;
110
111 /**
112 * updown script
113 */
114 char *updown;
115
116 /**
117 * allow host access
118 */
119 bool hostaccess;
120
121 /**
122 * list for all proposals
123 */
124 linked_list_t *proposals;
125
126 /**
127 * list for traffic selectors for my site
128 */
129 linked_list_t *my_ts;
130
131 /**
132 * list for traffic selectors for others site
133 */
134 linked_list_t *other_ts;
135
136 /**
137 * Time before an SA gets invalid
138 */
139 u_int32_t soft_lifetime;
140
141 /**
142 * Time before an SA gets rekeyed
143 */
144 u_int32_t hard_lifetime;
145
146 /**
147 * Time, which specifies the range of a random value
148 * substracted from soft_lifetime.
149 */
150 u_int32_t jitter;
151
152 /**
153 * What to do with an SA when other peer seams to be dead?
154 */
155 bool dpd_action;
156
157 /**
158 * Mode to propose for a initiated CHILD: tunnel/transport
159 */
160 mode_t mode;
161 };
162
163 /**
164 * Implementation of policy_t.get_name
165 */
166 static char *get_name(private_policy_t *this)
167 {
168 return this->name;
169 }
170
171 /**
172 * Implementation of policy_t.get_my_id
173 */
174 static identification_t *get_my_id(private_policy_t *this)
175 {
176 return this->my_id;
177 }
178
179 /**
180 * Implementation of policy_t.get_other_id
181 */
182 static identification_t *get_other_id(private_policy_t *this)
183 {
184 return this->other_id;
185 }
186
187 /**
188 * Implementation of policy_t.get_my_ca
189 */
190 static identification_t *get_my_ca(private_policy_t *this)
191 {
192 return this->my_ca;
193 }
194
195 /**
196 * Implementation of policy_t.get_other_ca
197 */
198 static identification_t *get_other_ca(private_policy_t *this)
199 {
200 return this->other_ca;
201 }
202
203 /**
204 * Implementation of connection_t.auth_method_t.
205 */
206 static auth_method_t get_auth_method(private_policy_t *this)
207 {
208 return this->auth_method;
209 }
210
211 /**
212 * Implementation of connection_t.get_eap_type.
213 */
214 static eap_type_t get_eap_type(private_policy_t *this)
215 {
216 return this->eap_type;
217 }
218
219 /**
220 * Get traffic selectors, with wildcard-address update
221 */
222 static linked_list_t *get_traffic_selectors(private_policy_t *this,
223 linked_list_t *list, host_t *host)
224 {
225 iterator_t *iterator;
226 traffic_selector_t *current;
227 linked_list_t *result = linked_list_create();
228
229 iterator = list->create_iterator(list, TRUE);
230
231 while (iterator->iterate(iterator, (void**)&current))
232 {
233 /* we make a copy of the TS, this allows us to update wildcard
234 * addresses in it. We won't pollute the shared policy. */
235 current = current->clone(current);
236 if (host)
237 {
238 current->set_address(current, host);
239 }
240
241 result->insert_last(result, (void*)current);
242 }
243 iterator->destroy(iterator);
244 return result;
245 }
246
247 /**
248 * Implementation of policy_t.get_my_traffic_selectors
249 */
250 static linked_list_t *get_my_traffic_selectors(private_policy_t *this, host_t *me)
251 {
252 return get_traffic_selectors(this, this->my_ts, me);
253 }
254
255 /**
256 * Implementation of policy_t.get_other_traffic_selectors
257 */
258 static linked_list_t *get_other_traffic_selectors(private_policy_t *this, host_t *other)
259 {
260 return get_traffic_selectors(this, this->other_ts, other);
261 }
262
263 /**
264 * Narrow traffic selectors, with wildcard-address update in "stored".
265 */
266 static linked_list_t *select_traffic_selectors(private_policy_t *this,
267 linked_list_t *stored,
268 linked_list_t *supplied,
269 host_t *host)
270 {
271 iterator_t *supplied_iter, *stored_iter, *i1, *i2;
272 traffic_selector_t *supplied_ts, *stored_ts, *selected_ts, *ts1, *ts2;
273 linked_list_t *selected = linked_list_create();
274
275 DBG2(DBG_CFG, "selecting traffic selectors");
276
277 stored_iter = stored->create_iterator(stored, TRUE);
278 supplied_iter = supplied->create_iterator(supplied, TRUE);
279
280 /* iterate over all stored selectors */
281 while (stored_iter->iterate(stored_iter, (void**)&stored_ts))
282 {
283 /* we make a copy of the TS, this allows us to update wildcard
284 * addresses in it. We won't pollute the shared policy. */
285 stored_ts = stored_ts->clone(stored_ts);
286 if (host)
287 {
288 stored_ts->set_address(stored_ts, host);
289 }
290
291 supplied_iter->reset(supplied_iter);
292 /* iterate over all supplied traffic selectors */
293 while (supplied_iter->iterate(supplied_iter, (void**)&supplied_ts))
294 {
295 DBG2(DBG_CFG, "stored %R <=> %R received",
296 stored_ts, supplied_ts);
297
298 selected_ts = stored_ts->get_subset(stored_ts, supplied_ts);
299 if (selected_ts)
300 {
301 /* got a match, add to list */
302 selected->insert_last(selected, (void*)selected_ts);
303
304 DBG2(DBG_CFG, "found traffic selector for %s: %R",
305 stored == this->my_ts ? "us" : "other", selected_ts);
306 }
307 }
308 stored_ts->destroy(stored_ts);
309 }
310 stored_iter->destroy(stored_iter);
311 supplied_iter->destroy(supplied_iter);
312
313 /* remove any redundant traffic selectors in the list */
314 i1 = selected->create_iterator(selected, TRUE);
315 i2 = selected->create_iterator(selected, TRUE);
316 while (i1->iterate(i1, (void**)&ts1))
317 {
318 while (i2->iterate(i2, (void**)&ts2))
319 {
320 if (ts1 != ts2 && ts2->is_contained_in(ts2, ts1))
321 {
322 i2->remove(i2);
323 ts2->destroy(ts2);
324 i1->reset(i1);
325 break;
326 }
327 }
328 }
329 i1->destroy(i1);
330 i2->destroy(i2);
331
332
333 return selected;
334 }
335
336 /**
337 * Implementation of private_policy_t.select_my_traffic_selectors
338 */
339 static linked_list_t *select_my_traffic_selectors(private_policy_t *this,
340 linked_list_t *supplied,
341 host_t *me)
342 {
343 return select_traffic_selectors(this, this->my_ts, supplied, me);
344 }
345
346 /**
347 * Implementation of private_policy_t.select_other_traffic_selectors
348 */
349 static linked_list_t *select_other_traffic_selectors(private_policy_t *this,
350 linked_list_t *supplied,
351 host_t* other)
352 {
353 return select_traffic_selectors(this, this->other_ts, supplied, other);
354 }
355
356 /**
357 * Implementation of policy_t.get_proposal_iterator
358 */
359 static linked_list_t *get_proposals(private_policy_t *this)
360 {
361 iterator_t *iterator;
362 proposal_t *current;
363 linked_list_t *proposals = linked_list_create();
364
365 iterator = this->proposals->create_iterator(this->proposals, TRUE);
366 while (iterator->iterate(iterator, (void**)&current))
367 {
368 current = current->clone(current);
369 proposals->insert_last(proposals, (void*)current);
370 }
371 iterator->destroy(iterator);
372
373 return proposals;
374 }
375
376 /**
377 * Implementation of policy_t.select_proposal
378 */
379 static proposal_t *select_proposal(private_policy_t *this, linked_list_t *proposals)
380 {
381 iterator_t *stored_iter, *supplied_iter;
382 proposal_t *stored, *supplied, *selected;
383
384 stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
385 supplied_iter = proposals->create_iterator(proposals, TRUE);
386
387 /* compare all stored proposals with all supplied. Stored ones are preferred. */
388 while (stored_iter->iterate(stored_iter, (void**)&stored))
389 {
390 supplied_iter->reset(supplied_iter);
391 while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
392 {
393 selected = stored->select(stored, supplied);
394 if (selected)
395 {
396 /* they match, return */
397 stored_iter->destroy(stored_iter);
398 supplied_iter->destroy(supplied_iter);
399 return selected;
400 }
401 }
402 }
403
404 /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
405 stored_iter->destroy(stored_iter);
406 supplied_iter->destroy(supplied_iter);
407
408 return NULL;
409 }
410
411 /**
412 * Implementation of policy_t.add_authorities
413 */
414 static void add_authorities(private_policy_t *this, identification_t *my_ca, identification_t *other_ca)
415 {
416 this->my_ca = my_ca;
417 this->other_ca = other_ca;
418 }
419
420 /**
421 * Implementation of policy_t.get_updown
422 */
423 static char* get_updown(private_policy_t *this)
424 {
425 return this->updown;
426 }
427
428 /**
429 * Implementation of policy_t.get_hostaccess
430 */
431 static bool get_hostaccess(private_policy_t *this)
432 {
433 return this->hostaccess;
434 }
435
436 /**
437 * Implements policy_t.get_dpd_action
438 */
439 static dpd_action_t get_dpd_action(private_policy_t *this)
440 {
441 return this->dpd_action;
442 }
443
444 /**
445 * Implementation of policy_t.add_my_traffic_selector
446 */
447 static void add_my_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
448 {
449 this->my_ts->insert_last(this->my_ts, (void*)traffic_selector);
450 }
451
452 /**
453 * Implementation of policy_t.add_other_traffic_selector
454 */
455 static void add_other_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
456 {
457 this->other_ts->insert_last(this->other_ts, (void*)traffic_selector);
458 }
459
460 /**
461 * Implementation of policy_t.add_proposal
462 */
463 static void add_proposal(private_policy_t *this, proposal_t *proposal)
464 {
465 this->proposals->insert_last(this->proposals, (void*)proposal);
466 }
467
468 /**
469 * Implementation of policy_t.get_soft_lifetime
470 */
471 static u_int32_t get_soft_lifetime(private_policy_t *this)
472 {
473 if (this->jitter == 0)
474 {
475 return this->soft_lifetime ;
476 }
477 return this->soft_lifetime - (random() % this->jitter);
478 }
479
480 /**
481 * Implementation of policy_t.get_hard_lifetime
482 */
483 static u_int32_t get_hard_lifetime(private_policy_t *this)
484 {
485 return this->hard_lifetime;
486 }
487
488 /**
489 * Implementation of policy_t.get_mode.
490 */
491 static mode_t get_mode(private_policy_t *this)
492 {
493 return this->mode;
494 }
495
496 /**
497 * Implementation of policy_t.get_virtual_ip.
498 */
499 static host_t* get_virtual_ip(private_policy_t *this, host_t *suggestion)
500 {
501 if (suggestion == NULL)
502 {
503 if (this->my_virtual_ip)
504 {
505 return this->my_virtual_ip->clone(this->my_virtual_ip);
506 }
507 return NULL;
508 }
509 if (this->other_virtual_ip)
510 {
511 return this->other_virtual_ip->clone(this->other_virtual_ip);
512 }
513 if (suggestion->is_anyaddr(suggestion))
514 {
515 return NULL;
516 }
517 return suggestion->clone(suggestion);
518 }
519
520 /**
521 * Implements policy_t.get_ref.
522 */
523 static void get_ref(private_policy_t *this)
524 {
525 ref_get(&this->refcount);
526 }
527
528 /**
529 * Implements policy_t.destroy.
530 */
531 static void destroy(private_policy_t *this)
532 {
533 if (ref_put(&this->refcount))
534 {
535
536 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
537 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
538 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
539
540 /* delete certification authorities */
541 DESTROY_IF(this->my_ca);
542 DESTROY_IF(this->other_ca);
543
544 /* delete updown script */
545 if (this->updown)
546 {
547 free(this->updown);
548 }
549
550 /* delete ids */
551 this->my_id->destroy(this->my_id);
552 this->other_id->destroy(this->other_id);
553 DESTROY_IF(this->my_virtual_ip);
554 DESTROY_IF(this->other_virtual_ip);
555
556 free(this->name);
557 free(this);
558 }
559 }
560
561 /*
562 * Described in header-file
563 */
564 policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
565 host_t *my_virtual_ip, host_t *other_virtual_ip,
566 auth_method_t auth_method, eap_type_t eap_type,
567 u_int32_t hard_lifetime, u_int32_t soft_lifetime,
568 u_int32_t jitter, char *updown, bool hostaccess,
569 mode_t mode, dpd_action_t dpd_action)
570 {
571 private_policy_t *this = malloc_thing(private_policy_t);
572
573 /* public functions */
574 this->public.get_name = (char* (*) (policy_t*))get_name;
575 this->public.get_my_id = (identification_t* (*) (policy_t*))get_my_id;
576 this->public.get_other_id = (identification_t* (*) (policy_t*))get_other_id;
577 this->public.get_my_ca = (identification_t* (*) (policy_t*))get_my_ca;
578 this->public.get_other_ca = (identification_t* (*) (policy_t*))get_other_ca;
579 this->public.get_auth_method = (auth_method_t (*) (policy_t*)) get_auth_method;
580 this->public.get_eap_type = (eap_type_t (*) (policy_t*)) get_eap_type;
581 this->public.get_my_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_my_traffic_selectors;
582 this->public.get_other_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_other_traffic_selectors;
583 this->public.select_my_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors;
584 this->public.select_other_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_other_traffic_selectors;
585 this->public.get_proposals = (linked_list_t* (*) (policy_t*))get_proposals;
586 this->public.select_proposal = (proposal_t* (*) (policy_t*,linked_list_t*))select_proposal;
587 this->public.add_my_traffic_selector = (void (*) (policy_t*,traffic_selector_t*))add_my_traffic_selector;
588 this->public.add_other_traffic_selector = (void (*) (policy_t*,traffic_selector_t*))add_other_traffic_selector;
589 this->public.add_proposal = (void (*) (policy_t*,proposal_t*))add_proposal;
590 this->public.add_authorities = (void (*) (policy_t*,identification_t*,identification_t*))add_authorities;
591 this->public.get_updown = (char* (*) (policy_t*))get_updown;
592 this->public.get_hostaccess = (bool (*) (policy_t*))get_hostaccess;
593 this->public.get_dpd_action = (dpd_action_t (*) (policy_t*))get_dpd_action;
594 this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
595 this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
596 this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
597 this->public.get_virtual_ip = (host_t* (*)(policy_t*,host_t*))get_virtual_ip;
598 this->public.get_ref = (void (*) (policy_t*))get_ref;
599 this->public.destroy = (void (*) (policy_t*))destroy;
600
601 /* apply init values */
602 this->name = strdup(name);
603 this->my_id = my_id;
604 this->other_id = other_id;
605 this->my_virtual_ip = my_virtual_ip;
606 this->other_virtual_ip = other_virtual_ip;
607 this->auth_method = auth_method;
608 this->eap_type = eap_type;
609 this->hard_lifetime = hard_lifetime;
610 this->soft_lifetime = soft_lifetime;
611 this->jitter = jitter;
612 this->updown = (updown == NULL) ? NULL : strdup(updown);
613 this->hostaccess = hostaccess;
614 this->dpd_action = dpd_action;
615 this->mode = mode;
616
617 /* initialize private members*/
618 this->refcount = 1;
619 this->my_ca = NULL;
620 this->other_ca = NULL;
621 this->proposals = linked_list_create();
622 this->my_ts = linked_list_create();
623 this->other_ts = linked_list_create();
624
625 return &this->public;
626 }