b6afd9a4b1ec5b34540eabfd6ddd580a453f2970
[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 identification_t *id;
69 host_t *host = NULL;
70
71 id = ike_sa->get_other_eap_id(ike_sa);
72
73 this->lock->read_lock(this->lock);
74 enumerator = this->providers->create_enumerator(this->providers);
75 while (enumerator->enumerate(enumerator, &current))
76 {
77 host = current->acquire_address(current, pools, id, requested);
78 if (host)
79 {
80 break;
81 }
82 }
83 enumerator->destroy(enumerator);
84 this->lock->unlock(this->lock);
85
86 return host;
87 }
88
89 METHOD(attribute_manager_t, release_address, bool,
90 private_attribute_manager_t *this, linked_list_t *pools, host_t *address,
91 ike_sa_t *ike_sa)
92 {
93 enumerator_t *enumerator;
94 attribute_provider_t *current;
95 identification_t *id;
96 bool found = FALSE;
97
98 id = ike_sa->get_other_eap_id(ike_sa);
99
100 this->lock->read_lock(this->lock);
101 enumerator = this->providers->create_enumerator(this->providers);
102 while (enumerator->enumerate(enumerator, &current))
103 {
104 if (current->release_address(current, pools, address, id))
105 {
106 found = TRUE;
107 break;
108 }
109 }
110 enumerator->destroy(enumerator);
111 this->lock->unlock(this->lock);
112
113 return found;
114 }
115
116 /**
117 * inner enumerator constructor for responder attributes
118 */
119 static enumerator_t *responder_enum_create(attribute_provider_t *provider,
120 enum_data_t *data)
121 {
122 identification_t *id;
123
124 id = data->ike_sa->get_other_eap_id(data->ike_sa);
125 return provider->create_attribute_enumerator(provider, data->pools,
126 id, data->vips);
127 }
128
129 METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
130 private_attribute_manager_t *this, linked_list_t *pools,
131 ike_sa_t *ike_sa, linked_list_t *vips)
132 {
133 enum_data_t *data;
134
135 INIT(data,
136 .pools = pools,
137 .ike_sa = ike_sa,
138 .vips = vips,
139 );
140 this->lock->read_lock(this->lock);
141 return enumerator_create_cleaner(
142 enumerator_create_nested(
143 this->providers->create_enumerator(this->providers),
144 (void*)responder_enum_create, data, free),
145 (void*)this->lock->unlock, this->lock);
146 }
147
148 METHOD(attribute_manager_t, add_provider, void,
149 private_attribute_manager_t *this, attribute_provider_t *provider)
150 {
151 this->lock->write_lock(this->lock);
152 this->providers->insert_last(this->providers, provider);
153 this->lock->unlock(this->lock);
154 }
155
156 METHOD(attribute_manager_t, remove_provider, void,
157 private_attribute_manager_t *this, attribute_provider_t *provider)
158 {
159 this->lock->write_lock(this->lock);
160 this->providers->remove(this->providers, provider, NULL);
161 this->lock->unlock(this->lock);
162 }
163
164 METHOD(attribute_manager_t, handle, attribute_handler_t*,
165 private_attribute_manager_t *this, ike_sa_t *ike_sa,
166 attribute_handler_t *handler, configuration_attribute_type_t type,
167 chunk_t data)
168 {
169 enumerator_t *enumerator;
170 identification_t *server;
171 attribute_handler_t *current, *handled = NULL;
172
173 server = ike_sa->get_other_id(ike_sa);
174
175 this->lock->read_lock(this->lock);
176
177 /* try to find the passed handler */
178 enumerator = this->handlers->create_enumerator(this->handlers);
179 while (enumerator->enumerate(enumerator, &current))
180 {
181 if (current == handler && current->handle(current, server, type, data))
182 {
183 handled = current;
184 break;
185 }
186 }
187 enumerator->destroy(enumerator);
188 if (!handled)
189 { /* handler requesting this attribute not found, try any other */
190 enumerator = this->handlers->create_enumerator(this->handlers);
191 while (enumerator->enumerate(enumerator, &current))
192 {
193 if (current->handle(current, server, type, data))
194 {
195 handled = current;
196 break;
197 }
198 }
199 enumerator->destroy(enumerator);
200 }
201 this->lock->unlock(this->lock);
202
203 if (!handled)
204 {
205 DBG1(DBG_CFG, "handling %N attribute failed",
206 configuration_attribute_type_names, type);
207 }
208 return handled;
209 }
210
211 METHOD(attribute_manager_t, release, void,
212 private_attribute_manager_t *this, attribute_handler_t *handler,
213 ike_sa_t *ike_sa, configuration_attribute_type_t type, chunk_t data)
214 {
215 enumerator_t *enumerator;
216 attribute_handler_t *current;
217 identification_t *server;
218
219 server = ike_sa->get_other_id(ike_sa);
220
221 this->lock->read_lock(this->lock);
222 enumerator = this->handlers->create_enumerator(this->handlers);
223 while (enumerator->enumerate(enumerator, &current))
224 {
225 if (current == handler)
226 {
227 current->release(current, server, type, data);
228 break;
229 }
230 }
231 enumerator->destroy(enumerator);
232 this->lock->unlock(this->lock);
233 }
234
235 /**
236 * Enumerator implementation to enumerate nested initiator attributes
237 */
238 typedef struct {
239 /** implements enumerator_t */
240 enumerator_t public;
241 /** back ref */
242 private_attribute_manager_t *this;
243 /** currently processing handler */
244 attribute_handler_t *handler;
245 /** outer enumerator over handlers */
246 enumerator_t *outer;
247 /** inner enumerator over current handlers attributes */
248 enumerator_t *inner;
249 /** IKE_SA to request attributes for */
250 ike_sa_t *ike_sa;
251 /** virtual IPs we are requesting along with attriubutes */
252 linked_list_t *vips;
253 } initiator_enumerator_t;
254
255 /**
256 * Enumerator implementation for initiator attributes
257 */
258 static bool initiator_enumerate(initiator_enumerator_t *this,
259 attribute_handler_t **handler,
260 configuration_attribute_type_t *type,
261 chunk_t *value)
262 {
263 identification_t *id;
264
265 id = this->ike_sa->get_other_id(this->ike_sa);
266
267 /* enumerate inner attributes using outer handler enumerator */
268 while (!this->inner || !this->inner->enumerate(this->inner, type, value))
269 {
270 if (!this->outer->enumerate(this->outer, &this->handler))
271 {
272 return FALSE;
273 }
274 DESTROY_IF(this->inner);
275 this->inner = this->handler->create_attribute_enumerator(this->handler,
276 id, this->vips);
277 }
278 /* inject the handler as additional attribute */
279 *handler = this->handler;
280 return TRUE;
281 }
282
283 /**
284 * Cleanup function of initiator attribute enumerator
285 */
286 static void initiator_destroy(initiator_enumerator_t *this)
287 {
288 this->this->lock->unlock(this->this->lock);
289 this->outer->destroy(this->outer);
290 DESTROY_IF(this->inner);
291 free(this);
292 }
293
294 METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
295 private_attribute_manager_t *this, ike_sa_t *ike_sa, linked_list_t *vips)
296 {
297 initiator_enumerator_t *enumerator;
298
299 this->lock->read_lock(this->lock);
300
301 INIT(enumerator,
302 .public = {
303 .enumerate = (void*)initiator_enumerate,
304 .destroy = (void*)initiator_destroy,
305 },
306 .this = this,
307 .ike_sa = ike_sa,
308 .vips = vips,
309 .outer = this->handlers->create_enumerator(this->handlers),
310 );
311 return &enumerator->public;
312 }
313
314 METHOD(attribute_manager_t, add_handler, void,
315 private_attribute_manager_t *this, attribute_handler_t *handler)
316 {
317 this->lock->write_lock(this->lock);
318 this->handlers->insert_last(this->handlers, handler);
319 this->lock->unlock(this->lock);
320 }
321
322 METHOD(attribute_manager_t, remove_handler, void,
323 private_attribute_manager_t *this, attribute_handler_t *handler)
324 {
325 this->lock->write_lock(this->lock);
326 this->handlers->remove(this->handlers, handler, NULL);
327 this->lock->unlock(this->lock);
328 }
329
330 METHOD(attribute_manager_t, destroy, void,
331 private_attribute_manager_t *this)
332 {
333 this->providers->destroy(this->providers);
334 this->handlers->destroy(this->handlers);
335 this->lock->destroy(this->lock);
336 free(this);
337 }
338
339 /*
340 * see header file
341 */
342 attribute_manager_t *attribute_manager_create()
343 {
344 private_attribute_manager_t *this;
345
346 INIT(this,
347 .public = {
348 .acquire_address = _acquire_address,
349 .release_address = _release_address,
350 .create_responder_enumerator = _create_responder_enumerator,
351 .add_provider = _add_provider,
352 .remove_provider = _remove_provider,
353 .handle = _handle,
354 .release = _release,
355 .create_initiator_enumerator = _create_initiator_enumerator,
356 .add_handler = _add_handler,
357 .remove_handler = _remove_handler,
358 .destroy = _destroy,
359 },
360 .providers = linked_list_create(),
361 .handlers = linked_list_create(),
362 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
363 );
364
365 return &this->public;
366 }