b52ae33ac48c3d8665f882d3ccd9e17aacf588ed
[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 typedef struct private_policy_t private_policy_t;
42
43 /**
44 * Private data of an policy_t object
45 */
46 struct private_policy_t {
47
48 /**
49 * Public part
50 */
51 policy_t public;
52
53 /**
54 * Number of references hold by others to this policy
55 */
56 refcount_t refcount;
57
58 /**
59 * Name of the policy, used to query it
60 */
61 char *name;
62
63 /**
64 * id to use to identify us
65 */
66 identification_t *my_id;
67
68 /**
69 * allowed id for other
70 */
71 identification_t *other_id;
72
73 /**
74 * Method to use for own authentication data
75 */
76 auth_method_t auth_method;
77
78 /**
79 * we have a cert issued by this CA
80 */
81 identification_t *my_ca;
82
83 /**
84 * we require the other end to have a cert issued by this CA
85 */
86 identification_t *other_ca;
87
88 /**
89 * updown script
90 */
91 char *updown;
92
93 /**
94 * allow host access
95 */
96 bool hostaccess;
97
98 /**
99 * list for all proposals
100 */
101 linked_list_t *proposals;
102
103 /**
104 * list for traffic selectors for my site
105 */
106 linked_list_t *my_ts;
107
108 /**
109 * list for traffic selectors for others site
110 */
111 linked_list_t *other_ts;
112
113 /**
114 * Time before an SA gets invalid
115 */
116 u_int32_t soft_lifetime;
117
118 /**
119 * Time before an SA gets rekeyed
120 */
121 u_int32_t hard_lifetime;
122
123 /**
124 * Time, which specifies the range of a random value
125 * substracted from soft_lifetime.
126 */
127 u_int32_t jitter;
128
129 /**
130 * What to do with an SA when other peer seams to be dead?
131 */
132 bool dpd_action;
133 };
134
135 /**
136 * Implementation of policy_t.get_name
137 */
138 static char *get_name(private_policy_t *this)
139 {
140 return this->name;
141 }
142
143 /**
144 * Implementation of policy_t.get_my_id
145 */
146 static identification_t *get_my_id(private_policy_t *this)
147 {
148 return this->my_id;
149 }
150
151 /**
152 * Implementation of policy_t.get_other_id
153 */
154 static identification_t *get_other_id(private_policy_t *this)
155 {
156 return this->other_id;
157 }
158
159 /**
160 * Implementation of policy_t.get_my_ca
161 */
162 static identification_t *get_my_ca(private_policy_t *this)
163 {
164 return this->my_ca;
165 }
166
167 /**
168 * Implementation of policy_t.get_other_ca
169 */
170 static identification_t *get_other_ca(private_policy_t *this)
171 {
172 return this->other_ca;
173 }
174
175 /**
176 * Implementation of connection_t.auth_method_t.
177 */
178 static auth_method_t get_auth_method(private_policy_t *this)
179 {
180 return this->auth_method;
181 }
182
183 /**
184 * Get traffic selectors, with wildcard-address update
185 */
186 static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host)
187 {
188 iterator_t *iterator;
189 traffic_selector_t *current;
190 linked_list_t *result = linked_list_create();
191
192 iterator = list->create_iterator(list, TRUE);
193
194 while (iterator->iterate(iterator, (void**)&current))
195 {
196 /* we make a copy of the TS, this allows us to update wildcard
197 * addresses in it. We won't pollute the shared policy. */
198 current = current->clone(current);
199 current->update_address_range(current, host);
200
201 result->insert_last(result, (void*)current);
202 }
203 iterator->destroy(iterator);
204 return result;
205 }
206
207 /**
208 * Implementation of policy_t.get_my_traffic_selectors
209 */
210 static linked_list_t *get_my_traffic_selectors(private_policy_t *this, host_t *me)
211 {
212 return get_traffic_selectors(this, this->my_ts, me);
213 }
214
215 /**
216 * Implementation of policy_t.get_other_traffic_selectors
217 */
218 static linked_list_t *get_other_traffic_selectors(private_policy_t *this, host_t *other)
219 {
220 return get_traffic_selectors(this, this->other_ts, other);
221 }
222
223 /**
224 * Narrow traffic selectors, with wildcard-address update in "stored".
225 */
226 static linked_list_t *select_traffic_selectors(private_policy_t *this,
227 linked_list_t *stored,
228 linked_list_t *supplied,
229 host_t *host)
230 {
231 iterator_t *supplied_iter, *stored_iter;
232 traffic_selector_t *supplied_ts, *stored_ts, *selected_ts;
233 linked_list_t *selected = linked_list_create();
234
235 DBG2(DBG_CFG, "selecting traffic selectors");
236
237 stored_iter = stored->create_iterator(stored, TRUE);
238 supplied_iter = supplied->create_iterator(supplied, TRUE);
239
240 /* iterate over all stored selectors */
241 while (stored_iter->iterate(stored_iter, (void**)&stored_ts))
242 {
243 /* we make a copy of the TS, this allows us to update wildcard
244 * addresses in it. We won't pollute the shared policy. */
245 stored_ts = stored_ts->clone(stored_ts);
246 stored_ts->update_address_range(stored_ts, host);
247
248 supplied_iter->reset(supplied_iter);
249 /* iterate over all supplied traffic selectors */
250 while (supplied_iter->iterate(supplied_iter, (void**)&supplied_ts))
251 {
252 DBG2(DBG_CFG, "stored %R <=> %R received",
253 stored_ts, supplied_ts);
254
255 selected_ts = stored_ts->get_subset(stored_ts, supplied_ts);
256 if (selected_ts)
257 {
258 /* got a match, add to list */
259 selected->insert_last(selected, (void*)selected_ts);
260
261 DBG2(DBG_CFG, "found traffic selector for %s: %R",
262 stored == this->my_ts ? "us" : "other", selected_ts);
263 }
264 }
265 stored_ts->destroy(stored_ts);
266 }
267 stored_iter->destroy(stored_iter);
268 supplied_iter->destroy(supplied_iter);
269
270 return selected;
271 }
272
273 /**
274 * Implementation of private_policy_t.select_my_traffic_selectors
275 */
276 static linked_list_t *select_my_traffic_selectors(private_policy_t *this,
277 linked_list_t *supplied,
278 host_t *me)
279 {
280 return select_traffic_selectors(this, this->my_ts, supplied, me);
281 }
282
283 /**
284 * Implementation of private_policy_t.select_other_traffic_selectors
285 */
286 static linked_list_t *select_other_traffic_selectors(private_policy_t *this,
287 linked_list_t *supplied,
288 host_t* other)
289 {
290 return select_traffic_selectors(this, this->other_ts, supplied, other);
291 }
292
293 /**
294 * Implementation of policy_t.get_proposal_iterator
295 */
296 static linked_list_t *get_proposals(private_policy_t *this)
297 {
298 iterator_t *iterator;
299 proposal_t *current;
300 linked_list_t *proposals = linked_list_create();
301
302 iterator = this->proposals->create_iterator(this->proposals, TRUE);
303 while (iterator->iterate(iterator, (void**)&current))
304 {
305 current = current->clone(current);
306 proposals->insert_last(proposals, (void*)current);
307 }
308 iterator->destroy(iterator);
309
310 return proposals;
311 }
312
313 /**
314 * Implementation of policy_t.select_proposal
315 */
316 static proposal_t *select_proposal(private_policy_t *this, linked_list_t *proposals)
317 {
318 iterator_t *stored_iter, *supplied_iter;
319 proposal_t *stored, *supplied, *selected;
320
321 stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
322 supplied_iter = proposals->create_iterator(proposals, TRUE);
323
324 /* compare all stored proposals with all supplied. Stored ones are preferred. */
325 while (stored_iter->iterate(stored_iter, (void**)&stored))
326 {
327 supplied_iter->reset(supplied_iter);
328 while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
329 {
330 selected = stored->select(stored, supplied);
331 if (selected)
332 {
333 /* they match, return */
334 stored_iter->destroy(stored_iter);
335 supplied_iter->destroy(supplied_iter);
336 return selected;
337 }
338 }
339 }
340
341 /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
342 stored_iter->destroy(stored_iter);
343 supplied_iter->destroy(supplied_iter);
344
345 return NULL;
346 }
347
348 /**
349 * Implementation of policy_t.add_authorities
350 */
351 static void add_authorities(private_policy_t *this, identification_t *my_ca, identification_t *other_ca)
352 {
353 this->my_ca = my_ca;
354 this->other_ca = other_ca;
355 }
356
357 /**
358 * Implementation of policy_t.get_updown
359 */
360 static char* get_updown(private_policy_t *this)
361 {
362 return this->updown;
363 }
364
365 /**
366 * Implementation of policy_t.get_hostaccess
367 */
368 static bool get_hostaccess(private_policy_t *this)
369 {
370 return this->hostaccess;
371 }
372
373 /**
374 * Implements policy_t.get_dpd_action
375 */
376 static dpd_action_t get_dpd_action(private_policy_t *this)
377 {
378 return this->dpd_action;
379 }
380
381
382 /**
383 * Implementation of policy_t.add_my_traffic_selector
384 */
385 static void add_my_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
386 {
387 this->my_ts->insert_last(this->my_ts, (void*)traffic_selector);
388 }
389
390 /**
391 * Implementation of policy_t.add_other_traffic_selector
392 */
393 static void add_other_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
394 {
395 this->other_ts->insert_last(this->other_ts, (void*)traffic_selector);
396 }
397
398 /**
399 * Implementation of policy_t.add_proposal
400 */
401 static void add_proposal(private_policy_t *this, proposal_t *proposal)
402 {
403 this->proposals->insert_last(this->proposals, (void*)proposal);
404 }
405
406 /**
407 * Implementation of policy_t.get_soft_lifetime
408 */
409 static u_int32_t get_soft_lifetime(private_policy_t *this)
410 {
411 if (this->jitter == 0)
412 {
413 return this->soft_lifetime ;
414 }
415 return this->soft_lifetime - (random() % this->jitter);
416 }
417
418 /**
419 * Implementation of policy_t.get_hard_lifetime
420 */
421 static u_int32_t get_hard_lifetime(private_policy_t *this)
422 {
423 return this->hard_lifetime;
424 }
425
426 /**
427 * Implements policy_t.get_ref.
428 */
429 static void get_ref(private_policy_t *this)
430 {
431 ref_get(&this->refcount);
432 }
433
434 /**
435 * Implements policy_t.destroy.
436 */
437 static void destroy(private_policy_t *this)
438 {
439 if (ref_put(&this->refcount))
440 {
441
442 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
443 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
444 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
445
446 /* delete certification authorities */
447 if (this->my_ca)
448 {
449 this->my_ca->destroy(this->my_ca);
450 }
451 if (this->other_ca)
452 {
453 this->other_ca->destroy(this->other_ca);
454 }
455
456 /* delete updown script */
457 if (this->updown)
458 {
459 free(this->updown);
460 }
461
462 /* delete ids */
463 this->my_id->destroy(this->my_id);
464 this->other_id->destroy(this->other_id);
465
466 free(this->name);
467 free(this);
468 }
469 }
470
471 /*
472 * Described in header-file
473 */
474 policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
475 auth_method_t auth_method,
476 u_int32_t hard_lifetime, u_int32_t soft_lifetime,
477 u_int32_t jitter, char *updown, bool hostaccess,
478 dpd_action_t dpd_action)
479 {
480 private_policy_t *this = malloc_thing(private_policy_t);
481
482 /* public functions */
483 this->public.get_name = (char* (*) (policy_t*))get_name;
484 this->public.get_my_id = (identification_t* (*) (policy_t*))get_my_id;
485 this->public.get_other_id = (identification_t* (*) (policy_t*))get_other_id;
486 this->public.get_my_ca = (identification_t* (*) (policy_t*))get_my_ca;
487 this->public.get_other_ca = (identification_t* (*) (policy_t*))get_other_ca;
488 this->public.get_auth_method = (auth_method_t (*) (policy_t*)) get_auth_method;
489 this->public.get_my_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_my_traffic_selectors;
490 this->public.get_other_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_other_traffic_selectors;
491 this->public.select_my_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors;
492 this->public.select_other_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_other_traffic_selectors;
493 this->public.get_proposals = (linked_list_t* (*) (policy_t*))get_proposals;
494 this->public.select_proposal = (proposal_t* (*) (policy_t*,linked_list_t*))select_proposal;
495 this->public.add_my_traffic_selector = (void (*) (policy_t*,traffic_selector_t*))add_my_traffic_selector;
496 this->public.add_other_traffic_selector = (void (*) (policy_t*,traffic_selector_t*))add_other_traffic_selector;
497 this->public.add_proposal = (void (*) (policy_t*,proposal_t*))add_proposal;
498 this->public.add_authorities = (void (*) (policy_t*,identification_t*,identification_t*))add_authorities;
499 this->public.get_updown = (char* (*) (policy_t*))get_updown;
500 this->public.get_hostaccess = (bool (*) (policy_t*))get_hostaccess;
501 this->public.get_dpd_action = (dpd_action_t (*) (policy_t*))get_dpd_action;
502 this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
503 this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
504 this->public.get_ref = (void (*) (policy_t*))get_ref;
505 this->public.destroy = (void (*) (policy_t*))destroy;
506
507 /* apply init values */
508 this->name = strdup(name);
509 this->my_id = my_id;
510 this->other_id = other_id;
511 this->auth_method = auth_method;
512 this->hard_lifetime = hard_lifetime;
513 this->soft_lifetime = soft_lifetime;
514 this->jitter = jitter;
515 this->updown = (updown == NULL) ? NULL : strdup(updown);
516 this->hostaccess = hostaccess;
517 this->dpd_action = dpd_action;
518
519 /* initialize private members*/
520 this->refcount = 1;
521 this->my_ca = NULL;
522 this->other_ca = NULL;
523 this->proposals = linked_list_create();
524 this->my_ts = linked_list_create();
525 this->other_ts = linked_list_create();
526
527 return &this->public;
528 }