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