preparations to include certreqs in policy decisions
[strongswan.git] / src / charon / config / policies / local_policy_store.c
1 /**
2 * @file local_policy_store.c
3 *
4 * @brief Implementation of local_policy_store_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_policy_store.h"
26
27 #include <daemon.h>
28 #include <utils/linked_list.h>
29
30
31 typedef struct private_local_policy_store_t private_local_policy_store_t;
32
33 /**
34 * Private data of an local_policy_store_t object
35 */
36 struct private_local_policy_store_t {
37
38 /**
39 * Public part
40 */
41 local_policy_store_t public;
42
43 /**
44 * list of policy_t's
45 */
46 linked_list_t *policies;
47
48 /**
49 * Mutex to exclusivly access list
50 */
51 pthread_mutex_t mutex;
52 };
53
54 /**
55 * Implementation of policy_store_t.add_policy.
56 */
57 static void add_policy(private_local_policy_store_t *this, policy_t *policy)
58 {
59 pthread_mutex_lock(&(this->mutex));
60 this->policies->insert_last(this->policies, (void*)policy);
61 pthread_mutex_unlock(&(this->mutex));
62 }
63
64 /**
65 * Check if a policy contains traffic selectors
66 */
67 static bool contains_traffic_selectors(policy_t *policy, bool mine,
68 linked_list_t *ts, host_t *host)
69 {
70 linked_list_t *selected;
71 bool contains = FALSE;
72
73 if (mine)
74 {
75 selected = policy->select_my_traffic_selectors(policy, ts, host);
76 }
77 else
78 {
79 selected = policy->select_other_traffic_selectors(policy, ts, host);
80 }
81 if (selected->get_count(selected))
82 {
83 contains = TRUE;
84 }
85 selected->destroy_offset(selected, offsetof(traffic_selector_t, destroy));
86 return contains;
87 }
88
89 /**
90 * Implementation of policy_store_t.get_policy.
91 */
92 static policy_t *get_policy(private_local_policy_store_t *this,
93 identification_t *my_id, identification_t *other_id,
94 linked_list_t *my_ts, linked_list_t *other_ts,
95 host_t *my_host, host_t *other_host,
96 linked_list_t *requested_ca_keyids)
97 {
98 typedef enum {
99 PRIO_UNDEFINED = 0x00,
100 PRIO_ID_ANY = 0x01,
101 PRIO_ID_MATCH = PRIO_ID_ANY + MAX_WILDCARDS,
102 } prio_t;
103
104 prio_t best_prio = PRIO_UNDEFINED;
105
106 iterator_t *iterator;
107 policy_t *candidate;
108 policy_t *found = NULL;
109
110 DBG2(DBG_CFG, "searching policy for ID pair %D...%D", my_id, other_id);
111
112 pthread_mutex_lock(&(this->mutex));
113 iterator = this->policies->create_iterator(this->policies, TRUE);
114
115 /* determine closest matching policy */
116 while (iterator->iterate(iterator, (void**)&candidate))
117 {
118 identification_t *candidate_my_id;
119 identification_t *candidate_other_id;
120 int wildcards;
121
122 candidate_my_id = candidate->get_my_id(candidate);
123 candidate_other_id = candidate->get_other_id(candidate);
124
125 /* my_id is either %any or if set must match exactly */
126 if (candidate_my_id->matches(candidate_my_id, my_id, &wildcards))
127 {
128 prio_t prio = PRIO_UNDEFINED;
129
130 /* wildcard match for other_id */
131 if (other_id->matches(other_id, candidate_other_id, &wildcards))
132 {
133 prio = PRIO_ID_MATCH - wildcards;
134 }
135
136 /* only accept if traffic selectors match */
137 if (!contains_traffic_selectors(candidate, TRUE, my_ts, my_host) ||
138 !contains_traffic_selectors(candidate, FALSE, other_ts, other_host))
139 {
140 DBG2(DBG_CFG, "candidate '%s' inacceptable due traffic "
141 "selector mismatch", candidate->get_name(candidate));
142 continue;
143 }
144
145 DBG2(DBG_CFG, "candidate policy '%s': %D...%D (prio=%d)",
146 candidate->get_name(candidate),
147 candidate_my_id, candidate_other_id, prio);
148
149 if (prio > best_prio)
150 {
151 found = candidate;
152 best_prio = prio;
153 }
154 }
155 }
156 iterator->destroy(iterator);
157
158 if (found)
159 {
160 identification_t *found_my_id = found->get_my_id(found);
161 identification_t *found_other_id = found->get_other_id(found);
162
163 DBG1(DBG_CFG, "found matching policy '%s': %D...%D (prio=%d)",
164 found->get_name(found), found_my_id, found_other_id, best_prio);
165 /* give out a new reference to it */
166 found->get_ref(found);
167 }
168 pthread_mutex_unlock(&(this->mutex));
169 return found;
170 }
171
172 /**
173 * Implementation of policy_store_t.get_policy_by_name.
174 */
175 static policy_t *get_policy_by_name(private_local_policy_store_t *this, char *name)
176 {
177 iterator_t *iterator;
178 policy_t *current, *found = NULL;
179
180 DBG2(DBG_CFG, "looking for policy '%s'", name);
181
182 pthread_mutex_lock(&(this->mutex));
183 iterator = this->policies->create_iterator(this->policies, TRUE);
184 while (iterator->iterate(iterator, (void **)&current))
185 {
186 if (strcmp(current->get_name(current), name) == 0)
187 {
188 found = current;
189 }
190 }
191 iterator->destroy(iterator);
192 pthread_mutex_unlock(&(this->mutex));
193
194 /* give out a new reference */
195 found->get_ref(found);
196 return found;
197 }
198
199 /**
200 * Implementation of policy_store_t.delete_policy.
201 */
202 static status_t delete_policy(private_local_policy_store_t *this, char *name)
203 {
204 iterator_t *iterator;
205 policy_t *current;
206 bool found = FALSE;
207
208 pthread_mutex_lock(&(this->mutex));
209 iterator = this->policies->create_iterator(this->policies, TRUE);
210 while (iterator->iterate(iterator, (void **)&current))
211 {
212 if (strcmp(current->get_name(current), name) == 0)
213 {
214 /* remove policy from list, and destroy it */
215 iterator->remove(iterator);
216 current->destroy(current);
217 found = TRUE;
218 /* we do not break here, as there may be multipe policies */
219 }
220 }
221 iterator->destroy(iterator);
222 pthread_mutex_unlock(&(this->mutex));
223 if (found)
224 {
225 return SUCCESS;
226 }
227 return NOT_FOUND;
228 }
229
230 /**
231 * Implementation of policy_store_t.create_iterator.
232 */
233 static iterator_t* create_iterator(private_local_policy_store_t *this)
234 {
235 return this->policies->create_iterator_locked(this->policies,
236 &this->mutex);
237 }
238
239 /**
240 * Implementation of policy_store_t.destroy.
241 */
242 static void destroy(private_local_policy_store_t *this)
243 {
244 pthread_mutex_lock(&(this->mutex));
245 this->policies->destroy_offset(this->policies, offsetof(policy_t, destroy));
246 pthread_mutex_unlock(&(this->mutex));
247 free(this);
248 }
249
250 /**
251 * Described in header.
252 */
253 local_policy_store_t *local_policy_store_create(void)
254 {
255 private_local_policy_store_t *this = malloc_thing(private_local_policy_store_t);
256
257 this->public.policy_store.add_policy = (void (*) (policy_store_t*,policy_t*))add_policy;
258 this->public.policy_store.get_policy = (policy_t* (*) (policy_store_t*,identification_t*,identification_t*,
259 linked_list_t*,linked_list_t*,host_t*,host_t*,linked_list_t*))get_policy;
260 this->public.policy_store.get_policy_by_name = (policy_t* (*) (policy_store_t*,char*))get_policy_by_name;
261 this->public.policy_store.delete_policy = (status_t (*) (policy_store_t*,char*))delete_policy;
262 this->public.policy_store.create_iterator = (iterator_t* (*) (policy_store_t*))create_iterator;
263 this->public.policy_store.destroy = (void (*) (policy_store_t*))destroy;
264
265 /* private variables */
266 this->policies = linked_list_create();
267 pthread_mutex_init(&(this->mutex), NULL);
268
269 return (&this->public);
270 }