ad9a63964705c081472d8654ddda56b58626f066
[strongswan.git] / src / libcharon / attributes / attribute_manager.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "attribute_manager.h"
17
18 #include <utils/debug.h>
19 #include <collections/linked_list.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_attribute_manager_t private_attribute_manager_t;
23
24 /**
25 * private data of attribute_manager
26 */
27 struct private_attribute_manager_t {
28
29 /**
30 * public functions
31 */
32 attribute_manager_t public;
33
34 /**
35 * list of registered providers
36 */
37 linked_list_t *providers;
38
39 /**
40 * list of registered handlers
41 */
42 linked_list_t *handlers;
43
44 /**
45 * rwlock provider list
46 */
47 rwlock_t *lock;
48 };
49
50 /**
51 * Data to pass to enumerator filters
52 */
53 typedef struct {
54 /** attribute group pools */
55 linked_list_t *pools;
56 /** associated IKE_SA */
57 ike_sa_t *ike_sa;
58 /** requesting/assigned virtual IPs */
59 linked_list_t *vips;
60 } enum_data_t;
61
62 METHOD(attribute_manager_t, acquire_address, host_t*,
63 private_attribute_manager_t *this, linked_list_t *pools,
64 ike_sa_t *ike_sa, host_t *requested)
65 {
66 enumerator_t *enumerator;
67 attribute_provider_t *current;
68 host_t *host = NULL;
69
70 this->lock->read_lock(this->lock);
71 enumerator = this->providers->create_enumerator(this->providers);
72 while (enumerator->enumerate(enumerator, &current))
73 {
74 host = current->acquire_address(current, pools, ike_sa, requested);
75 if (host)
76 {
77 break;
78 }
79 }
80 enumerator->destroy(enumerator);
81 this->lock->unlock(this->lock);
82
83 return host;
84 }
85
86 METHOD(attribute_manager_t, release_address, bool,
87 private_attribute_manager_t *this, linked_list_t *pools, host_t *address,
88 ike_sa_t *ike_sa)
89 {
90 enumerator_t *enumerator;
91 attribute_provider_t *current;
92 bool found = FALSE;
93
94 this->lock->read_lock(this->lock);
95 enumerator = this->providers->create_enumerator(this->providers);
96 while (enumerator->enumerate(enumerator, &current))
97 {
98 if (current->release_address(current, pools, address, ike_sa))
99 {
100 found = TRUE;
101 break;
102 }
103 }
104 enumerator->destroy(enumerator);
105 this->lock->unlock(this->lock);
106
107 return found;
108 }
109
110 /**
111 * inner enumerator constructor for responder attributes
112 */
113 static enumerator_t *responder_enum_create(attribute_provider_t *provider,
114 enum_data_t *data)
115 {
116 return provider->create_attribute_enumerator(provider, data->pools,
117 data->ike_sa, data->vips);
118 }
119
120 METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
121 private_attribute_manager_t *this, linked_list_t *pools,
122 ike_sa_t *ike_sa, linked_list_t *vips)
123 {
124 enum_data_t *data;
125
126 INIT(data,
127 .pools = pools,
128 .ike_sa = ike_sa,
129 .vips = vips,
130 );
131 this->lock->read_lock(this->lock);
132 return enumerator_create_cleaner(
133 enumerator_create_nested(
134 this->providers->create_enumerator(this->providers),
135 (void*)responder_enum_create, data, free),
136 (void*)this->lock->unlock, this->lock);
137 }
138
139 METHOD(attribute_manager_t, add_provider, void,
140 private_attribute_manager_t *this, attribute_provider_t *provider)
141 {
142 this->lock->write_lock(this->lock);
143 this->providers->insert_last(this->providers, provider);
144 this->lock->unlock(this->lock);
145 }
146
147 METHOD(attribute_manager_t, remove_provider, void,
148 private_attribute_manager_t *this, attribute_provider_t *provider)
149 {
150 this->lock->write_lock(this->lock);
151 this->providers->remove(this->providers, provider, NULL);
152 this->lock->unlock(this->lock);
153 }
154
155 METHOD(attribute_manager_t, handle, attribute_handler_t*,
156 private_attribute_manager_t *this, ike_sa_t *ike_sa,
157 attribute_handler_t *handler, configuration_attribute_type_t type,
158 chunk_t data)
159 {
160 enumerator_t *enumerator;
161 identification_t *server;
162 attribute_handler_t *current, *handled = NULL;
163
164 server = ike_sa->get_other_id(ike_sa);
165
166 this->lock->read_lock(this->lock);
167
168 /* try to find the passed handler */
169 enumerator = this->handlers->create_enumerator(this->handlers);
170 while (enumerator->enumerate(enumerator, &current))
171 {
172 if (current == handler && current->handle(current, server, type, data))
173 {
174 handled = current;
175 break;
176 }
177 }
178 enumerator->destroy(enumerator);
179 if (!handled)
180 { /* handler requesting this attribute not found, try any other */
181 enumerator = this->handlers->create_enumerator(this->handlers);
182 while (enumerator->enumerate(enumerator, &current))
183 {
184 if (current->handle(current, server, type, data))
185 {
186 handled = current;
187 break;
188 }
189 }
190 enumerator->destroy(enumerator);
191 }
192 this->lock->unlock(this->lock);
193
194 if (!handled)
195 {
196 DBG1(DBG_CFG, "handling %N attribute failed",
197 configuration_attribute_type_names, type);
198 }
199 return handled;
200 }
201
202 METHOD(attribute_manager_t, release, void,
203 private_attribute_manager_t *this, attribute_handler_t *handler,
204 ike_sa_t *ike_sa, configuration_attribute_type_t type, chunk_t data)
205 {
206 enumerator_t *enumerator;
207 attribute_handler_t *current;
208 identification_t *server;
209
210 server = ike_sa->get_other_id(ike_sa);
211
212 this->lock->read_lock(this->lock);
213 enumerator = this->handlers->create_enumerator(this->handlers);
214 while (enumerator->enumerate(enumerator, &current))
215 {
216 if (current == handler)
217 {
218 current->release(current, server, type, data);
219 break;
220 }
221 }
222 enumerator->destroy(enumerator);
223 this->lock->unlock(this->lock);
224 }
225
226 /**
227 * Enumerator implementation to enumerate nested initiator attributes
228 */
229 typedef struct {
230 /** implements enumerator_t */
231 enumerator_t public;
232 /** back ref */
233 private_attribute_manager_t *this;
234 /** currently processing handler */
235 attribute_handler_t *handler;
236 /** outer enumerator over handlers */
237 enumerator_t *outer;
238 /** inner enumerator over current handlers attributes */
239 enumerator_t *inner;
240 /** IKE_SA to request attributes for */
241 ike_sa_t *ike_sa;
242 /** virtual IPs we are requesting along with attriubutes */
243 linked_list_t *vips;
244 } initiator_enumerator_t;
245
246 /**
247 * Enumerator implementation for initiator attributes
248 */
249 static bool initiator_enumerate(initiator_enumerator_t *this,
250 attribute_handler_t **handler,
251 configuration_attribute_type_t *type,
252 chunk_t *value)
253 {
254 identification_t *id;
255
256 id = this->ike_sa->get_other_id(this->ike_sa);
257
258 /* enumerate inner attributes using outer handler enumerator */
259 while (!this->inner || !this->inner->enumerate(this->inner, type, value))
260 {
261 if (!this->outer->enumerate(this->outer, &this->handler))
262 {
263 return FALSE;
264 }
265 DESTROY_IF(this->inner);
266 this->inner = this->handler->create_attribute_enumerator(this->handler,
267 id, this->vips);
268 }
269 /* inject the handler as additional attribute */
270 *handler = this->handler;
271 return TRUE;
272 }
273
274 /**
275 * Cleanup function of initiator attribute enumerator
276 */
277 static void initiator_destroy(initiator_enumerator_t *this)
278 {
279 this->this->lock->unlock(this->this->lock);
280 this->outer->destroy(this->outer);
281 DESTROY_IF(this->inner);
282 free(this);
283 }
284
285 METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
286 private_attribute_manager_t *this, ike_sa_t *ike_sa, linked_list_t *vips)
287 {
288 initiator_enumerator_t *enumerator;
289
290 this->lock->read_lock(this->lock);
291
292 INIT(enumerator,
293 .public = {
294 .enumerate = (void*)initiator_enumerate,
295 .destroy = (void*)initiator_destroy,
296 },
297 .this = this,
298 .ike_sa = ike_sa,
299 .vips = vips,
300 .outer = this->handlers->create_enumerator(this->handlers),
301 );
302 return &enumerator->public;
303 }
304
305 METHOD(attribute_manager_t, add_handler, void,
306 private_attribute_manager_t *this, attribute_handler_t *handler)
307 {
308 this->lock->write_lock(this->lock);
309 this->handlers->insert_last(this->handlers, handler);
310 this->lock->unlock(this->lock);
311 }
312
313 METHOD(attribute_manager_t, remove_handler, void,
314 private_attribute_manager_t *this, attribute_handler_t *handler)
315 {
316 this->lock->write_lock(this->lock);
317 this->handlers->remove(this->handlers, handler, NULL);
318 this->lock->unlock(this->lock);
319 }
320
321 METHOD(attribute_manager_t, destroy, void,
322 private_attribute_manager_t *this)
323 {
324 this->providers->destroy(this->providers);
325 this->handlers->destroy(this->handlers);
326 this->lock->destroy(this->lock);
327 free(this);
328 }
329
330 /*
331 * see header file
332 */
333 attribute_manager_t *attribute_manager_create()
334 {
335 private_attribute_manager_t *this;
336
337 INIT(this,
338 .public = {
339 .acquire_address = _acquire_address,
340 .release_address = _release_address,
341 .create_responder_enumerator = _create_responder_enumerator,
342 .add_provider = _add_provider,
343 .remove_provider = _remove_provider,
344 .handle = _handle,
345 .release = _release,
346 .create_initiator_enumerator = _create_initiator_enumerator,
347 .add_handler = _add_handler,
348 .remove_handler = _remove_handler,
349 .destroy = _destroy,
350 },
351 .providers = linked_list_create(),
352 .handlers = linked_list_create(),
353 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
354 );
355
356 return &this->public;
357 }