329f317dd3e083bdae046902b426d180290c3c1d
[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, hydra->daemon,
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", hydra->daemon);
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 type = atoi(key);
194 if (!type)
195 {
196 for (i = 0; i < countof(keys); i++)
197 {
198 if (streq(key, keys[i].name))
199 {
200 mapped = &keys[i];
201 break;
202 }
203 }
204 if (!mapped)
205 {
206 DBG1(DBG_CFG, "mapping attribute type %s failed", key);
207 continue;
208 }
209 }
210 tokens = enumerator_create_token(value, ",", " ");
211 while (tokens->enumerate(tokens, &token))
212 {
213 pos = strchr(token, '/');
214 if (pos)
215 {
216 *(pos++) = '\0';
217 mask = atoi(pos);
218 }
219 host = host_create_from_string(token, 0);
220 if (!host)
221 {
222 if (!type)
223 {
224 DBG1(DBG_CFG, "invalid host in key %s: %s", key, token);
225 continue;
226 }
227 /* store numeric attributes that are no IP addresses as strings */
228 data = chunk_clone(chunk_from_str(token));
229 }
230 else
231 {
232 family = host->get_family(host);
233 if (mask == -1)
234 {
235 data = chunk_clone(host->get_address(host));
236 }
237 else
238 {
239 if (family == AF_INET)
240 { /* IPv4 attributes contain a subnet mask */
241 u_int32_t netmask;
242
243 mask = 32 - mask;
244 netmask = htonl((0xFFFFFFFF >> mask) << mask);
245 data = chunk_cat("cc", host->get_address(host),
246 chunk_from_thing(netmask));
247 }
248 else
249 { /* IPv6 addresses the prefix only */
250 data = chunk_cat("cc", host->get_address(host),
251 chunk_from_chars(mask));
252 }
253 }
254 host->destroy(host);
255 }
256 INIT(entry,
257 .type = type ?: (family == AF_INET ? mapped->v4 : mapped->v6),
258 .value = data,
259 );
260 DBG2(DBG_CFG, "loaded attribute %N: %#B",
261 configuration_attribute_type_names, entry->type, &entry->value);
262 this->attributes->insert_last(this->attributes, entry);
263 }
264 tokens->destroy(tokens);
265 }
266 enumerator->destroy(enumerator);
267 }
268
269 METHOD(attr_provider_t, reload, void,
270 private_attr_provider_t *this)
271 {
272 this->lock->write_lock(this->lock);
273
274 this->attributes->destroy_function(this->attributes, (void*)attribute_destroy);
275 this->attributes = linked_list_create();
276
277 load_entries(this);
278
279 DBG1(DBG_CFG, "loaded %d entr%s for attr plugin configuration",
280 this->attributes->get_count(this->attributes),
281 this->attributes->get_count(this->attributes) == 1 ? "y" : "ies");
282
283 this->lock->unlock(this->lock);
284 }
285
286 /*
287 * see header file
288 */
289 attr_provider_t *attr_provider_create(database_t *db)
290 {
291 private_attr_provider_t *this;
292
293 INIT(this,
294 .public = {
295 .provider = {
296 .acquire_address = (void*)return_null,
297 .release_address = (void*)return_false,
298 .create_attribute_enumerator = _create_attribute_enumerator,
299 },
300 .reload = _reload,
301 .destroy = _destroy,
302 },
303 .attributes = linked_list_create(),
304 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
305 );
306
307 load_entries(this);
308
309 return &this->public;
310 }
311