Added support for named attribute groups
[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 <debug.h>
23 #include <utils/linked_list.h>
24
25 #define SERVER_MAX 2
26
27 typedef struct private_attr_provider_t private_attr_provider_t;
28 typedef struct attribute_entry_t attribute_entry_t;
29
30 /**
31 * private data of attr_provider
32 */
33 struct private_attr_provider_t {
34
35 /**
36 * public functions
37 */
38 attr_provider_t public;
39
40 /**
41 * List of attributes, attribute_entry_t
42 */
43 linked_list_t *attributes;
44 };
45
46 struct attribute_entry_t {
47 /** type of attribute */
48 configuration_attribute_type_t type;
49 /** attribute value */
50 chunk_t value;
51 };
52
53 /**
54 * convert enumerator value from attribute_entry
55 */
56 static bool attr_enum_filter(void *null, attribute_entry_t **in,
57 configuration_attribute_type_t *type, void* none, chunk_t *value)
58 {
59 *type = (*in)->type;
60 *value = (*in)->value;
61 return TRUE;
62 }
63
64 /**
65 * Implementation of attribute_provider_t.create_attribute_enumerator
66 */
67 static enumerator_t* create_attribute_enumerator(private_attr_provider_t *this,
68 char *pool, identification_t *id, host_t *vip)
69 {
70 if (vip)
71 {
72 return enumerator_create_filter(
73 this->attributes->create_enumerator(this->attributes),
74 (void*)attr_enum_filter, NULL, NULL);
75 }
76 return enumerator_create_empty();
77 }
78
79 /**
80 * Implementation of attr_provider_t.destroy
81 */
82 static void destroy(private_attr_provider_t *this)
83 {
84 attribute_entry_t *entry;
85
86 while (this->attributes->remove_last(this->attributes,
87 (void**)&entry) == SUCCESS)
88 {
89 free(entry->value.ptr);
90 free(entry);
91 }
92 this->attributes->destroy(this->attributes);
93 free(this);
94 }
95
96 /**
97 * Add an attribute entry to the list
98 */
99 static void add_legacy_entry(private_attr_provider_t *this, char *key, int nr,
100 configuration_attribute_type_t type)
101 {
102 attribute_entry_t *entry;
103 host_t *host;
104 char *str;
105
106 str = lib->settings->get_str(lib->settings, "%s.%s%d", NULL, hydra->daemon,
107 key, nr);
108 if (str)
109 {
110 host = host_create_from_string(str, 0);
111 if (host)
112 {
113 entry = malloc_thing(attribute_entry_t);
114
115 if (host->get_family(host) == AF_INET6)
116 {
117 switch (type)
118 {
119 case INTERNAL_IP4_DNS:
120 type = INTERNAL_IP6_DNS;
121 break;
122 case INTERNAL_IP4_NBNS:
123 type = INTERNAL_IP6_NBNS;
124 break;
125 default:
126 break;
127 }
128 }
129 entry->type = type;
130 entry->value = chunk_clone(host->get_address(host));
131 host->destroy(host);
132 this->attributes->insert_last(this->attributes, entry);
133 }
134 }
135 }
136
137 /**
138 * Key to attribute type mappings, for v4 and v6 attributes
139 */
140 static struct {
141 char *name;
142 configuration_attribute_type_t v4;
143 configuration_attribute_type_t v6;
144 } keys[] = {
145 {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS},
146 {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS},
147 {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS},
148 {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP},
149 {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK},
150 {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER},
151 {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET},
152 };
153
154 /**
155 * Load (numerical) entries from the plugins.attr namespace
156 */
157 static void load_entries(private_attr_provider_t *this)
158 {
159 enumerator_t *enumerator, *tokens;
160 char *key, *value, *token;
161
162 enumerator = lib->settings->create_key_value_enumerator(lib->settings,
163 "%s.plugins.attr", hydra->daemon);
164 while (enumerator->enumerate(enumerator, &key, &value))
165 {
166 configuration_attribute_type_t type;
167 attribute_entry_t *entry;
168 host_t *host;
169 char *pos;
170 int i, mask = -1;
171
172 type = atoi(key);
173 tokens = enumerator_create_token(value, ",", " ");
174 while (tokens->enumerate(tokens, &token))
175 {
176 pos = strchr(token, '/');
177 if (pos)
178 {
179 *(pos++) = '\0';
180 mask = atoi(pos);
181 }
182 host = host_create_from_string(token, 0);
183 if (!host)
184 {
185 DBG1(DBG_CFG, "invalid host in key %s: %s", key, token);
186 continue;
187 }
188 if (!type)
189 {
190 for (i = 0; i < countof(keys); i++)
191 {
192 if (streq(key, keys[i].name))
193 {
194 if (host->get_family(host) == AF_INET)
195 {
196 type = keys[i].v4;
197 }
198 else
199 {
200 type = keys[i].v6;
201 }
202 }
203 }
204 if (!type)
205 {
206 DBG1(DBG_CFG, "mapping attribute type %s failed", key);
207 break;
208 }
209 }
210 entry = malloc_thing(attribute_entry_t);
211 entry->type = type;
212 if (mask == -1)
213 {
214 entry->value = chunk_clone(host->get_address(host));
215 }
216 else
217 {
218 if (host->get_family(host) == AF_INET)
219 { /* IPv4 attributes contain a subnet mask */
220 u_int32_t netmask;
221
222 mask = 32 - mask;
223 netmask = htonl((0xFFFFFFFF >> mask) << mask);
224 entry->value = chunk_cat("cc", host->get_address(host),
225 chunk_from_thing(netmask));
226 }
227 else
228 { /* IPv6 addresses the prefix only */
229 entry->value = chunk_cat("cc", host->get_address(host),
230 chunk_from_chars(mask));
231 }
232 }
233 host->destroy(host);
234 this->attributes->insert_last(this->attributes, entry);
235 }
236 tokens->destroy(tokens);
237 }
238 enumerator->destroy(enumerator);
239 }
240
241 /*
242 * see header file
243 */
244 attr_provider_t *attr_provider_create(database_t *db)
245 {
246 private_attr_provider_t *this;
247 int i;
248
249 this = malloc_thing(private_attr_provider_t);
250
251 this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))return_null;
252 this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))return_false;
253 this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, char *names, identification_t *id, host_t *vip))create_attribute_enumerator;
254 this->public.destroy = (void(*)(attr_provider_t*))destroy;
255
256 this->attributes = linked_list_create();
257
258 for (i = 1; i <= SERVER_MAX; i++)
259 {
260 add_legacy_entry(this, "dns", i, INTERNAL_IP4_DNS);
261 add_legacy_entry(this, "nbns", i, INTERNAL_IP4_NBNS);
262 }
263
264 load_entries(this);
265
266 return &this->public;
267 }
268