attribute-manager: Pass the full IKE_SA to provider methods
[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, identification_t *server,
166 attribute_handler_t *handler, configuration_attribute_type_t type,
167 chunk_t data)
168 {
169 enumerator_t *enumerator;
170 attribute_handler_t *current, *handled = NULL;
171
172 this->lock->read_lock(this->lock);
173
174 /* try to find the passed handler */
175 enumerator = this->handlers->create_enumerator(this->handlers);
176 while (enumerator->enumerate(enumerator, &current))
177 {
178 if (current == handler && current->handle(current, server, type, data))
179 {
180 handled = current;
181 break;
182 }
183 }
184 enumerator->destroy(enumerator);
185 if (!handled)
186 { /* handler requesting this attribute not found, try any other */
187 enumerator = this->handlers->create_enumerator(this->handlers);
188 while (enumerator->enumerate(enumerator, &current))
189 {
190 if (current->handle(current, server, type, data))
191 {
192 handled = current;
193 break;
194 }
195 }
196 enumerator->destroy(enumerator);
197 }
198 this->lock->unlock(this->lock);
199
200 if (!handled)
201 {
202 DBG1(DBG_CFG, "handling %N attribute failed",
203 configuration_attribute_type_names, type);
204 }
205 return handled;
206 }
207
208 METHOD(attribute_manager_t, release, void,
209 private_attribute_manager_t *this, attribute_handler_t *handler,
210 identification_t *server, configuration_attribute_type_t type, chunk_t data)
211 {
212 enumerator_t *enumerator;
213 attribute_handler_t *current;
214
215 this->lock->read_lock(this->lock);
216 enumerator = this->handlers->create_enumerator(this->handlers);
217 while (enumerator->enumerate(enumerator, &current))
218 {
219 if (current == handler)
220 {
221 current->release(current, server, type, data);
222 break;
223 }
224 }
225 enumerator->destroy(enumerator);
226 this->lock->unlock(this->lock);
227 }
228
229 /**
230 * Enumerator implementation to enumerate nested initiator attributes
231 */
232 typedef struct {
233 /** implements enumerator_t */
234 enumerator_t public;
235 /** back ref */
236 private_attribute_manager_t *this;
237 /** currently processing handler */
238 attribute_handler_t *handler;
239 /** outer enumerator over handlers */
240 enumerator_t *outer;
241 /** inner enumerator over current handlers attributes */
242 enumerator_t *inner;
243 /** server ID we want attributes for */
244 identification_t *id;
245 /** virtual IPs we are requesting along with attriubutes */
246 linked_list_t *vips;
247 } initiator_enumerator_t;
248
249 /**
250 * Enumerator implementation for initiator attributes
251 */
252 static bool initiator_enumerate(initiator_enumerator_t *this,
253 attribute_handler_t **handler,
254 configuration_attribute_type_t *type,
255 chunk_t *value)
256 {
257 /* enumerate inner attributes using outer handler enumerator */
258 while (!this->inner || !this->inner->enumerate(this->inner, type, value))
259 {
260 if (!this->outer->enumerate(this->outer, &this->handler))
261 {
262 return FALSE;
263 }
264 DESTROY_IF(this->inner);
265 this->inner = this->handler->create_attribute_enumerator(this->handler,
266 this->id, this->vips);
267 }
268 /* inject the handler as additional attribute */
269 *handler = this->handler;
270 return TRUE;
271 }
272
273 /**
274 * Cleanup function of initiator attribute enumerator
275 */
276 static void initiator_destroy(initiator_enumerator_t *this)
277 {
278 this->this->lock->unlock(this->this->lock);
279 this->outer->destroy(this->outer);
280 DESTROY_IF(this->inner);
281 free(this);
282 }
283
284 METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
285 private_attribute_manager_t *this, identification_t *id, linked_list_t *vips)
286 {
287 initiator_enumerator_t *enumerator;
288
289 this->lock->read_lock(this->lock);
290
291 INIT(enumerator,
292 .public = {
293 .enumerate = (void*)initiator_enumerate,
294 .destroy = (void*)initiator_destroy,
295 },
296 .this = this,
297 .id = id,
298 .vips = vips,
299 .outer = this->handlers->create_enumerator(this->handlers),
300 );
301 return &enumerator->public;
302 }
303
304 METHOD(attribute_manager_t, add_handler, void,
305 private_attribute_manager_t *this, attribute_handler_t *handler)
306 {
307 this->lock->write_lock(this->lock);
308 this->handlers->insert_last(this->handlers, handler);
309 this->lock->unlock(this->lock);
310 }
311
312 METHOD(attribute_manager_t, remove_handler, void,
313 private_attribute_manager_t *this, attribute_handler_t *handler)
314 {
315 this->lock->write_lock(this->lock);
316 this->handlers->remove(this->handlers, handler, NULL);
317 this->lock->unlock(this->lock);
318 }
319
320 METHOD(attribute_manager_t, destroy, void,
321 private_attribute_manager_t *this)
322 {
323 this->providers->destroy(this->providers);
324 this->handlers->destroy(this->handlers);
325 this->lock->destroy(this->lock);
326 free(this);
327 }
328
329 /*
330 * see header file
331 */
332 attribute_manager_t *attribute_manager_create()
333 {
334 private_attribute_manager_t *this;
335
336 INIT(this,
337 .public = {
338 .acquire_address = _acquire_address,
339 .release_address = _release_address,
340 .create_responder_enumerator = _create_responder_enumerator,
341 .add_provider = _add_provider,
342 .remove_provider = _remove_provider,
343 .handle = _handle,
344 .release = _release,
345 .create_initiator_enumerator = _create_initiator_enumerator,
346 .add_handler = _add_handler,
347 .remove_handler = _remove_handler,
348 .destroy = _destroy,
349 },
350 .providers = linked_list_create(),
351 .handlers = linked_list_create(),
352 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
353 );
354
355 return &this->public;
356 }