attr: Silently skip over load option
[strongswan.git] / src / libhydra / plugins / attr / attr_provider.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "attr_provider.h"
18
19 #include <time.h>
20
21 #include <hydra.h>
22 #include <utils/debug.h>
23 #include <collections/linked_list.h>
24 #include <threading/rwlock.h>
25
26 #define SERVER_MAX 2
27
28 typedef struct private_attr_provider_t private_attr_provider_t;
29 typedef struct attribute_entry_t attribute_entry_t;
30
31 /**
32 * private data of attr_provider
33 */
34 struct private_attr_provider_t {
35
36 /**
37 * public functions
38 */
39 attr_provider_t public;
40
41 /**
42 * List of attributes, attribute_entry_t
43 */
44 linked_list_t *attributes;
45
46 /**
47 * Lock for attribute list
48 */
49 rwlock_t *lock;
50 };
51
52 struct attribute_entry_t {
53 /** type of attribute */
54 configuration_attribute_type_t type;
55 /** attribute value */
56 chunk_t value;
57 };
58
59 /**
60 * Destroy an entry
61 */
62 static void attribute_destroy(attribute_entry_t *this)
63 {
64 free(this->value.ptr);
65 free(this);
66 }
67
68 /**
69 * convert enumerator value from attribute_entry
70 */
71 static bool attr_enum_filter(void *null, attribute_entry_t **in,
72 configuration_attribute_type_t *type, void* none, chunk_t *value)
73 {
74 *type = (*in)->type;
75 *value = (*in)->value;
76 return TRUE;
77 }
78
79 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
80 private_attr_provider_t *this, linked_list_t *pools,
81 identification_t *id, linked_list_t *vips)
82 {
83 if (vips->get_count(vips))
84 {
85 this->lock->read_lock(this->lock);
86 return enumerator_create_filter(
87 this->attributes->create_enumerator(this->attributes),
88 (void*)attr_enum_filter, this->lock, (void*)this->lock->unlock);
89 }
90 return enumerator_create_empty();
91 }
92
93 METHOD(attr_provider_t, destroy, void,
94 private_attr_provider_t *this)
95 {
96 this->attributes->destroy_function(this->attributes,
97 (void*)attribute_destroy);
98 this->lock->destroy(this->lock);
99 free(this);
100 }
101
102 /**
103 * Add an attribute entry to the list
104 */
105 static void add_legacy_entry(private_attr_provider_t *this, char *key, int nr,
106 configuration_attribute_type_t type)
107 {
108 attribute_entry_t *entry;
109 host_t *host;
110 char *str;
111
112 str = lib->settings->get_str(lib->settings, "%s.%s%d", NULL, lib->ns,
113 key, nr);
114 if (str)
115 {
116 host = host_create_from_string(str, 0);
117 if (host)
118 {
119 entry = malloc_thing(attribute_entry_t);
120
121 if (host->get_family(host) == AF_INET6)
122 {
123 switch (type)
124 {
125 case INTERNAL_IP4_DNS:
126 type = INTERNAL_IP6_DNS;
127 break;
128 case INTERNAL_IP4_NBNS:
129 type = INTERNAL_IP6_NBNS;
130 break;
131 default:
132 break;
133 }
134 }
135 entry->type = type;
136 entry->value = chunk_clone(host->get_address(host));
137 host->destroy(host);
138 DBG2(DBG_CFG, "loaded legacy entry attribute %N: %#B",
139 configuration_attribute_type_names, entry->type, &entry->value);
140 this->attributes->insert_last(this->attributes, entry);
141 }
142 }
143 }
144
145 /**
146 * Key to attribute type mappings, for v4 and v6 attributes
147 */
148 typedef struct {
149 char *name;
150 configuration_attribute_type_t v4;
151 configuration_attribute_type_t v6;
152 } attribute_type_key_t;
153
154 static attribute_type_key_t keys[] = {
155 {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS},
156 {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS},
157 {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS},
158 {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP},
159 {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK},
160 {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER},
161 {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET},
162 {"split-include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE},
163 {"split-exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN},
164 };
165
166 /**
167 * Load (numerical) entries from the plugins.attr namespace
168 */
169 static void load_entries(private_attr_provider_t *this)
170 {
171 enumerator_t *enumerator, *tokens;
172 char *key, *value, *token;
173 int i;
174
175 for (i = 1; i <= SERVER_MAX; i++)
176 {
177 add_legacy_entry(this, "dns", i, INTERNAL_IP4_DNS);
178 add_legacy_entry(this, "nbns", i, INTERNAL_IP4_NBNS);
179 }
180
181 enumerator = lib->settings->create_key_value_enumerator(lib->settings,
182 "%s.plugins.attr", lib->ns);
183 while (enumerator->enumerate(enumerator, &key, &value))
184 {
185 configuration_attribute_type_t type;
186 attribute_type_key_t *mapped = NULL;
187 attribute_entry_t *entry;
188 chunk_t data;
189 host_t *host;
190 char *pos;
191 int i, mask = -1, family;
192
193 if (streq(key, "load"))
194 {
195 continue;
196 }
197 type = atoi(key);
198 if (!type)
199 {
200 for (i = 0; i < countof(keys); i++)
201 {
202 if (streq(key, keys[i].name))
203 {
204 mapped = &keys[i];
205 break;
206 }
207 }
208 if (!mapped)
209 {
210 DBG1(DBG_CFG, "mapping attribute type %s failed", key);
211 continue;
212 }
213 }
214 tokens = enumerator_create_token(value, ",", " ");
215 while (tokens->enumerate(tokens, &token))
216 {
217 pos = strchr(token, '/');
218 if (pos)
219 {
220 *(pos++) = '\0';
221 mask = atoi(pos);
222 }
223 host = host_create_from_string(token, 0);
224 if (!host)
225 {
226 if (mapped)
227 {
228 DBG1(DBG_CFG, "invalid host in key %s: %s", key, token);
229 continue;
230 }
231 /* store numeric attributes that are no IP addresses as strings */
232 data = chunk_clone(chunk_from_str(token));
233 }
234 else
235 {
236 family = host->get_family(host);
237 if (mask == -1)
238 {
239 data = chunk_clone(host->get_address(host));
240 }
241 else
242 {
243 if (family == AF_INET)
244 { /* IPv4 attributes contain a subnet mask */
245 u_int32_t netmask;
246
247 mask = 32 - mask;
248 netmask = htonl((0xFFFFFFFF >> mask) << mask);
249 data = chunk_cat("cc", host->get_address(host),
250 chunk_from_thing(netmask));
251 }
252 else
253 { /* IPv6 addresses the prefix only */
254 data = chunk_cat("cc", host->get_address(host),
255 chunk_from_chars(mask));
256 }
257 }
258 host->destroy(host);
259 if (mapped)
260 {
261 switch (family)
262 {
263 case AF_INET:
264 type = mapped->v4;
265 break;
266 case AF_INET6:
267 type = mapped->v6;
268 break;
269 }
270 }
271 }
272 INIT(entry,
273 .type = type,
274 .value = data,
275 );
276 DBG2(DBG_CFG, "loaded attribute %N: %#B",
277 configuration_attribute_type_names, entry->type, &entry->value);
278 this->attributes->insert_last(this->attributes, entry);
279 }
280 tokens->destroy(tokens);
281 }
282 enumerator->destroy(enumerator);
283 }
284
285 METHOD(attr_provider_t, reload, void,
286 private_attr_provider_t *this)
287 {
288 this->lock->write_lock(this->lock);
289
290 this->attributes->destroy_function(this->attributes, (void*)attribute_destroy);
291 this->attributes = linked_list_create();
292
293 load_entries(this);
294
295 DBG1(DBG_CFG, "loaded %d entr%s for attr plugin configuration",
296 this->attributes->get_count(this->attributes),
297 this->attributes->get_count(this->attributes) == 1 ? "y" : "ies");
298
299 this->lock->unlock(this->lock);
300 }
301
302 /*
303 * see header file
304 */
305 attr_provider_t *attr_provider_create(database_t *db)
306 {
307 private_attr_provider_t *this;
308
309 INIT(this,
310 .public = {
311 .provider = {
312 .acquire_address = (void*)return_null,
313 .release_address = (void*)return_false,
314 .create_attribute_enumerator = _create_attribute_enumerator,
315 },
316 .reload = _reload,
317 .destroy = _destroy,
318 },
319 .attributes = linked_list_create(),
320 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
321 );
322
323 load_entries(this);
324
325 return &this->public;
326 }