The introduced SHA1_NOFINAL hasher was not sufficient for EAP-AKA,
[strongswan.git] / src / libstrongswan / settings.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * 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 * $Id$
16 */
17
18 #define _GNU_SOURCE
19 #include <string.h>
20 #include <stdio.h>
21 #include <errno.h>
22
23 #include "settings.h"
24
25 #include <debug.h>
26 #include <utils/linked_list.h>
27
28
29 typedef struct private_settings_t private_settings_t;
30 typedef struct section_t section_t;
31 typedef struct kv_t kv_t;
32
33 /**
34 * private data of settings
35 */
36 struct private_settings_t {
37
38 /**
39 * public functions
40 */
41 settings_t public;
42
43 /**
44 * top level section
45 */
46 section_t *top;
47
48 /**
49 * allocated file text
50 */
51 char *text;
52 };
53
54 /**
55 * section containing subsections and key value pairs
56 */
57 struct section_t {
58
59 /**
60 * name of the section
61 */
62 char *name;
63
64 /**
65 * subsections, as section_t
66 */
67 linked_list_t *sections;
68
69 /**
70 * key value pairs, as kv_t
71 */
72 linked_list_t *kv;
73 };
74
75 /**
76 * Key value pair
77 */
78 struct kv_t {
79
80 /**
81 * key string, relative
82 */
83 char *key;
84
85 /**
86 * value as string
87 */
88 char *value;
89 };
90
91 static char *find(section_t *section, char *key)
92 {
93 char *name, *pos, *value = NULL;
94 enumerator_t *enumerator;
95 kv_t *kv;
96 section_t *current, *found = NULL;
97
98 if (section == NULL)
99 {
100 return NULL;
101 }
102
103 name = strdupa(key);
104
105 pos = strchr(name, '.');
106 if (pos)
107 {
108 *pos = '\0';
109 pos++;
110 enumerator = section->sections->create_enumerator(section->sections);
111 while (enumerator->enumerate(enumerator, &current))
112 {
113 if (streq(current->name, name))
114 {
115 found = current;
116 break;
117 }
118 }
119 enumerator->destroy(enumerator);
120 if (found)
121 {
122 return find(found, pos);
123 }
124 }
125 else
126 {
127 enumerator = section->kv->create_enumerator(section->kv);
128 while (enumerator->enumerate(enumerator, &kv))
129 {
130 if (streq(kv->key, name))
131 {
132 value = kv->value;
133 break;
134 }
135 }
136 enumerator->destroy(enumerator);
137 }
138 return value;
139 }
140
141 /**
142 * Implementation of settings_t.get.
143 */
144 static char* get_str(private_settings_t *this, char *key, char *def)
145 {
146 char *value;
147
148 value = find(this->top, key);
149 if (value)
150 {
151 return value;
152 }
153 return def;
154 }
155
156 /**
157 * Implementation of settings_t.get_bool.
158 */
159 static bool get_bool(private_settings_t *this, char *key, bool def)
160 {
161 char *value;
162
163 value = find(this->top, key);
164 if (value)
165 {
166 if (strcasecmp(value, "true") == 0 ||
167 strcasecmp(value, "enables") == 0 ||
168 strcasecmp(value, "yes") == 0 ||
169 strcasecmp(value, "1") == 0)
170 {
171 return TRUE;
172 }
173 else if (strcasecmp(value, "false") == 0 ||
174 strcasecmp(value, "disabled") == 0 ||
175 strcasecmp(value, "no") == 0 ||
176 strcasecmp(value, "0") == 0)
177 {
178 return FALSE;
179 }
180 }
181 return def;
182 }
183
184 /**
185 * Implementation of settings_t.get_int.
186 */
187 static int get_int(private_settings_t *this, char *key, int def)
188 {
189 char *value;
190 int intval;
191
192 value = find(this->top, key);
193 if (value)
194 {
195 errno = 0;
196 intval = strtol(value, NULL, 10);
197 if (errno == 0)
198 {
199 return intval;
200 }
201 }
202 return def;
203 }
204
205 /**
206 * destry a section
207 */
208 static void section_destroy(section_t *this)
209 {
210 this->kv->destroy_function(this->kv, free);
211 this->sections->destroy_function(this->sections, (void*)section_destroy);
212
213 free(this);
214 }
215
216 /**
217 * parse text, truncate "skip" chars, delimited by term respecting brackets.
218 *
219 * Chars in "skip" are truncated at the beginning and the end of the resulting
220 * token. "term" contains a list of characters to read up to (first match),
221 * while "br" contains bracket counterparts found in "term" to skip.
222 */
223 static char parse(char **text, char *skip, char *term, char *br, char **token)
224 {
225 char *best = NULL;
226 char best_term = '\0';
227
228 /* skip leading chars */
229 while (strchr(skip, **text))
230 {
231 (*text)++;
232 if (!**text)
233 {
234 return 0;
235 }
236 }
237 /* mark begin of subtext */
238 *token = *text;
239 while (*term)
240 {
241 char *pos = *text;
242 int level = 1;
243
244 /* find terminator */
245 while (*pos)
246 {
247 if (*pos == *term)
248 {
249 level--;
250 }
251 else if (br && *pos == *br)
252 {
253 level++;
254 }
255 if (level == 0)
256 {
257 if (best == NULL || best > pos)
258 {
259 best = pos;
260 best_term = *term;
261 }
262 break;
263 }
264 pos++;
265 }
266 /* try next terminator */
267 term++;
268 if (br)
269 {
270 br++;
271 }
272 }
273 if (best)
274 {
275 /* update input */
276 *text = best;
277 /* null trailing bytes */
278 do
279 {
280 *best = '\0';
281 best--;
282 }
283 while (best >= *token && strchr(skip, *best));
284 /* return found terminator */
285 return best_term;
286 }
287 return 0;
288 }
289
290 /**
291 * Parse a section
292 */
293 static section_t* parse_section(char **text, char *name)
294 {
295 section_t *sub, *section;
296 bool finished = FALSE;
297 char *key, *value, *inner;
298
299 static int lev = 0;
300 lev++;
301
302 section = malloc_thing(section_t);
303 section->name = name;
304 section->sections = linked_list_create();
305 section->kv = linked_list_create();
306
307 while (!finished)
308 {
309 switch (parse(text, "\t\n ", "{=#", NULL, &key))
310 {
311 case '{':
312 if (parse(text, "\t ", "}", "{", &inner))
313 {
314 sub = parse_section(&inner, key);
315 if (sub)
316 {
317 section->sections->insert_last(section->sections, sub);
318 continue;
319 }
320 }
321 break;
322 case '=':
323 if (parse(text, "\t ", "\n", NULL, &value))
324 {
325 kv_t *kv = malloc_thing(kv_t);
326 kv->key = key;
327 kv->value = value;
328 section->kv->insert_last(section->kv, kv);
329 continue;
330 }
331 break;
332 case '#':
333 parse(text, "", "\n", NULL, &value);
334 continue;
335 default:
336 finished = TRUE;
337 continue;
338 }
339 section_destroy(section);
340 return NULL;
341 }
342 return section;
343 }
344
345 /**
346 * Implementation of settings_t.destroy
347 */
348 static void destroy(private_settings_t *this)
349 {
350 if (this->top)
351 {
352 section_destroy(this->top);
353 }
354 free(this->text);
355 free(this);
356 }
357
358 /*
359 * see header file
360 */
361 settings_t *settings_create(char *file)
362 {
363 private_settings_t *this = malloc_thing(private_settings_t);
364
365 this->public.get_str = (char*(*)(settings_t*, char *key, char* def))get_str;
366 this->public.get_int = (int(*)(settings_t*, char *key, bool def))get_int;
367 this->public.get_bool = (bool(*)(settings_t*, char *key, bool def))get_bool;
368 this->public.destroy = (void(*)(settings_t*))destroy;
369
370 this->top = NULL;
371 this->text = NULL;
372
373 if (file)
374 {
375 FILE *fd;
376 int len;
377 char *pos;
378
379 fd = fopen(file, "r");
380 if (fd == NULL)
381 {
382 return &this->public;
383 }
384 fseek(fd, 0, SEEK_END);
385 len = ftell(fd);
386 rewind(fd);
387 this->text = malloc(len + 1);
388 this->text[len] = '\0';
389 if (fread(this->text, 1, len, fd) != len)
390 {
391 free(this->text);
392 this->text = NULL;
393 return &this->public;
394 }
395 fclose(fd);
396
397 pos = this->text;
398 this->top = parse_section(&pos, NULL);
399 if (this->top == NULL)
400 {
401 free(this->text);
402 this->text = NULL;
403 return &this->public;
404 }
405 }
406 return &this->public;
407 }
408