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