Made settings_t thread-safe.
[strongswan.git] / src / libstrongswan / settings.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2008 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 #define _GNU_SOURCE
18 #include <string.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <glob.h>
24 #include <libgen.h>
25
26 #include "settings.h"
27
28 #include "debug.h"
29 #include "utils/linked_list.h"
30 #include "threading/rwlock.h"
31
32 #define MAX_INCLUSION_LEVEL 10
33
34 typedef struct private_settings_t private_settings_t;
35 typedef struct section_t section_t;
36 typedef struct kv_t kv_t;
37
38 /**
39 * private data of settings
40 */
41 struct private_settings_t {
42
43 /**
44 * public functions
45 */
46 settings_t public;
47
48 /**
49 * top level section
50 */
51 section_t *top;
52
53 /**
54 * contents of loaded files
55 */
56 linked_list_t *files;
57
58 /**
59 * lock to safely access the settings
60 */
61 rwlock_t *lock;
62 };
63
64 /**
65 * section containing subsections and key value pairs
66 */
67 struct section_t {
68
69 /**
70 * name of the section
71 */
72 char *name;
73
74 /**
75 * subsections, as section_t
76 */
77 linked_list_t *sections;
78
79 /**
80 * key value pairs, as kv_t
81 */
82 linked_list_t *kv;
83 };
84
85 /**
86 * Key value pair
87 */
88 struct kv_t {
89
90 /**
91 * key string, relative
92 */
93 char *key;
94
95 /**
96 * value as string
97 */
98 char *value;
99 };
100
101 /**
102 * Print a format key, but consume already processed arguments
103 */
104 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
105 {
106 va_list copy;
107 bool res;
108 char *pos;
109
110 va_copy(copy, args);
111 while (start < key)
112 {
113 pos = strchr(start, '%');
114 if (!pos)
115 {
116 start += strlen(start) + 1;
117 continue;
118 }
119 pos++;
120 switch (*pos)
121 {
122 case 'd':
123 va_arg(copy, int);
124 break;
125 case 's':
126 va_arg(copy, char*);
127 break;
128 case 'N':
129 va_arg(copy, enum_name_t*);
130 va_arg(copy, int);
131 break;
132 case '%':
133 break;
134 default:
135 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
136 break;
137 }
138 start = pos;
139 if (*start)
140 {
141 start++;
142 }
143 }
144 res = vsnprintf(buf, len, key, copy) < len;
145 va_end(copy);
146 return res;
147 }
148
149 /**
150 * find a section by a given key, using buffered key, reusable buffer
151 */
152 static section_t *find_section_buffered(section_t *section,
153 char *start, char *key, va_list args, char *buf, int len)
154 {
155 char *pos;
156 enumerator_t *enumerator;
157 section_t *current, *found = NULL;
158
159 if (section == NULL)
160 {
161 return NULL;
162 }
163 pos = strchr(key, '.');
164 if (pos)
165 {
166 *pos = '\0';
167 pos++;
168 }
169 if (!print_key(buf, len, start, key, args))
170 {
171 return NULL;
172 }
173 enumerator = section->sections->create_enumerator(section->sections);
174 while (enumerator->enumerate(enumerator, &current))
175 {
176 if (streq(current->name, buf))
177 {
178 found = current;
179 break;
180 }
181 }
182 enumerator->destroy(enumerator);
183 if (found && pos)
184 {
185 return find_section_buffered(found, start, pos, args, buf, len);
186 }
187 return found;
188 }
189
190 /**
191 * Find a section by a given key (thread-safe).
192 */
193 static section_t *find_section(private_settings_t *this, section_t *section,
194 char *key, va_list args)
195 {
196 char buf[128], keybuf[512];
197 section_t *found;
198
199 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
200 {
201 return NULL;
202 }
203 this->lock->read_lock(this->lock);
204 found = find_section_buffered(section, keybuf, keybuf, args, buf,
205 sizeof(buf));
206 this->lock->unlock(this->lock);
207 return found;
208 }
209
210 /**
211 * Find the string value for a key, using buffered key, reusable buffer
212 */
213 static char *find_value_buffered(section_t *section,
214 char *start, char *key, va_list args, char *buf, int len)
215 {
216 char *pos, *value = NULL;
217 enumerator_t *enumerator;
218 kv_t *kv;
219 section_t *current, *found = NULL;
220
221 if (section == NULL)
222 {
223 return NULL;
224 }
225
226 pos = strchr(key, '.');
227 if (pos)
228 {
229 *pos = '\0';
230 pos++;
231
232 if (!print_key(buf, len, start, key, args))
233 {
234 return NULL;
235 }
236 enumerator = section->sections->create_enumerator(section->sections);
237 while (enumerator->enumerate(enumerator, &current))
238 {
239 if (streq(current->name, buf))
240 {
241 found = current;
242 break;
243 }
244 }
245 enumerator->destroy(enumerator);
246 if (found)
247 {
248 return find_value_buffered(found, start, pos, args, buf, len);
249 }
250 }
251 else
252 {
253 if (!print_key(buf, len, start, key, args))
254 {
255 return NULL;
256 }
257 enumerator = section->kv->create_enumerator(section->kv);
258 while (enumerator->enumerate(enumerator, &kv))
259 {
260 if (streq(kv->key, buf))
261 {
262 value = kv->value;
263 break;
264 }
265 }
266 enumerator->destroy(enumerator);
267 }
268 return value;
269 }
270
271 /**
272 * Find the string value for a key (thread-safe).
273 */
274 static char *find_value(private_settings_t *this, section_t *section,
275 char *key, va_list args)
276 {
277 char buf[128], keybuf[512], *value;
278
279 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
280 {
281 return NULL;
282 }
283 this->lock->read_lock(this->lock);
284 value = find_value_buffered(section, keybuf, keybuf, args, buf,
285 sizeof(buf));
286 this->lock->unlock(this->lock);
287 return value;
288 }
289
290 METHOD(settings_t, get_str, char*,
291 private_settings_t *this, char *key, char *def, ...)
292 {
293 char *value;
294 va_list args;
295
296 va_start(args, def);
297 value = find_value(this, this->top, key, args);
298 va_end(args);
299 if (value)
300 {
301 return value;
302 }
303 return def;
304 }
305
306 METHOD(settings_t, get_bool, bool,
307 private_settings_t *this, char *key, bool def, ...)
308 {
309 char *value;
310 va_list args;
311
312 va_start(args, def);
313 value = find_value(this, this->top, key, args);
314 va_end(args);
315 if (value)
316 {
317 if (strcaseeq(value, "true") ||
318 strcaseeq(value, "enabled") ||
319 strcaseeq(value, "yes") ||
320 strcaseeq(value, "1"))
321 {
322 return TRUE;
323 }
324 else if (strcaseeq(value, "false") ||
325 strcaseeq(value, "disabled") ||
326 strcaseeq(value, "no") ||
327 strcaseeq(value, "0"))
328 {
329 return FALSE;
330 }
331 }
332 return def;
333 }
334
335 METHOD(settings_t, get_int, int,
336 private_settings_t *this, char *key, int def, ...)
337 {
338 char *value;
339 int intval;
340 va_list args;
341
342 va_start(args, def);
343 value = find_value(this, this->top, key, args);
344 va_end(args);
345 if (value)
346 {
347 errno = 0;
348 intval = strtol(value, NULL, 10);
349 if (errno == 0)
350 {
351 return intval;
352 }
353 }
354 return def;
355 }
356
357 METHOD(settings_t, get_double, double,
358 private_settings_t *this, char *key, double def, ...)
359 {
360 char *value;
361 double dval;
362 va_list args;
363
364 va_start(args, def);
365 value = find_value(this, this->top, key, args);
366 va_end(args);
367 if (value)
368 {
369 errno = 0;
370 dval = strtod(value, NULL);
371 if (errno == 0)
372 {
373 return dval;
374 }
375 }
376 return def;
377 }
378
379 METHOD(settings_t, get_time, u_int32_t,
380 private_settings_t *this, char *key, u_int32_t def, ...)
381 {
382 char *value, *endptr;
383 u_int32_t timeval;
384 va_list args;
385
386 va_start(args, def);
387 value = find_value(this, this->top, key, args);
388 va_end(args);
389 if (value)
390 {
391 errno = 0;
392 timeval = strtoul(value, &endptr, 10);
393 if (errno == 0)
394 {
395 switch (*endptr)
396 {
397 case 'd': /* time in days */
398 timeval *= 24 * 3600;
399 break;
400 case 'h': /* time in hours */
401 timeval *= 3600;
402 break;
403 case 'm': /* time in minutes */
404 timeval *= 60;
405 break;
406 case 's': /* time in seconds */
407 default:
408 break;
409 }
410 return timeval;
411 }
412 }
413 return def;
414 }
415
416 /**
417 * Enumerate section names, not sections
418 */
419 static bool section_filter(void *null, section_t **in, char **out)
420 {
421 *out = (*in)->name;
422 return TRUE;
423 }
424
425 METHOD(settings_t, create_section_enumerator, enumerator_t*,
426 private_settings_t *this, char *key, ...)
427 {
428 section_t *section;
429 va_list args;
430
431 va_start(args, key);
432 section = find_section(this, this->top, key, args);
433 va_end(args);
434
435 if (!section)
436 {
437 return enumerator_create_empty();
438 }
439 this->lock->read_lock(this->lock);
440 return enumerator_create_filter(
441 section->sections->create_enumerator(section->sections),
442 (void*)section_filter, this->lock, (void*)this->lock->unlock);
443 }
444
445 /**
446 * Enumerate key and values, not kv_t entries
447 */
448 static bool kv_filter(void *null, kv_t **in, char **key,
449 void *none, char **value)
450 {
451 *key = (*in)->key;
452 *value = (*in)->value;
453 return TRUE;
454 }
455
456 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
457 private_settings_t *this, char *key, ...)
458 {
459 section_t *section;
460 va_list args;
461
462 va_start(args, key);
463 section = find_section(this, this->top, key, args);
464 va_end(args);
465
466 if (!section)
467 {
468 return enumerator_create_empty();
469 }
470 this->lock->read_lock(this->lock);
471 return enumerator_create_filter(
472 section->kv->create_enumerator(section->kv),
473 (void*)kv_filter, this->lock, (void*)this->lock->unlock);
474 }
475
476 /**
477 * create a section with the given name
478 */
479 static section_t *section_create(char *name)
480 {
481 section_t *this;
482 INIT(this,
483 .name = name,
484 .sections = linked_list_create(),
485 .kv = linked_list_create(),
486 );
487 return this;
488 }
489
490 /**
491 * destroy a section
492 */
493 static void section_destroy(section_t *this)
494 {
495 this->kv->destroy_function(this->kv, free);
496 this->sections->destroy_function(this->sections, (void*)section_destroy);
497 free(this);
498 }
499
500 /**
501 * callback to find a section by name
502 */
503 static bool section_find(section_t *this, char *name)
504 {
505 return streq(this->name, name);
506 }
507
508 /**
509 * callback to find a kv pair by key
510 */
511 static bool kv_find(kv_t *this, char *key)
512 {
513 return streq(this->key, key);
514 }
515
516 /**
517 * parse text, truncate "skip" chars, delimited by term respecting brackets.
518 *
519 * Chars in "skip" are truncated at the beginning and the end of the resulting
520 * token. "term" contains a list of characters to read up to (first match),
521 * while "br" contains bracket counterparts found in "term" to skip.
522 */
523 static char parse(char **text, char *skip, char *term, char *br, char **token)
524 {
525 char *best = NULL;
526 char best_term = '\0';
527
528 /* skip leading chars */
529 while (strchr(skip, **text))
530 {
531 (*text)++;
532 if (!**text)
533 {
534 return 0;
535 }
536 }
537 /* mark begin of subtext */
538 *token = *text;
539 while (*term)
540 {
541 char *pos = *text;
542 int level = 1;
543
544 /* find terminator */
545 while (*pos)
546 {
547 if (*pos == *term)
548 {
549 level--;
550 }
551 else if (br && *pos == *br)
552 {
553 level++;
554 }
555 if (level == 0)
556 {
557 if (best == NULL || best > pos)
558 {
559 best = pos;
560 best_term = *term;
561 }
562 break;
563 }
564 pos++;
565 }
566 /* try next terminator */
567 term++;
568 if (br)
569 {
570 br++;
571 }
572 }
573 if (best)
574 {
575 /* update input */
576 *text = best;
577 /* null trailing bytes */
578 do
579 {
580 *best = '\0';
581 best--;
582 }
583 while (best >= *token && strchr(skip, *best));
584 /* return found terminator */
585 return best_term;
586 }
587 return 0;
588 }
589
590 /**
591 * Check if "text" starts with "pattern".
592 * Characters in "skip" are skipped first. If found, TRUE is returned and "text"
593 * is modified to point to the character right after "pattern".
594 */
595 static bool starts_with(char **text, char *skip, char *pattern)
596 {
597 char *pos = *text;
598 int len = strlen(pattern);
599 while (strchr(skip, *pos))
600 {
601 pos++;
602 if (!*pos)
603 {
604 return FALSE;
605 }
606 }
607 if (strlen(pos) < len || !strneq(pos, pattern, len))
608 {
609 return FALSE;
610 }
611 *text = pos + len;
612 return TRUE;
613 }
614
615 /**
616 * Check if what follows in "text" is an include statement.
617 * If this function returns TRUE, "text" will point to the character right after
618 * the include pattern, which is returned in "pattern".
619 */
620 static bool parse_include(char **text, char **pattern)
621 {
622 char *pos = *text;
623 if (!starts_with(&pos, "\n\t ", "include"))
624 {
625 return FALSE;
626 }
627 if (starts_with(&pos, "\t ", "="))
628 { /* ignore "include = value" */
629 return FALSE;
630 }
631 *text = pos;
632 return parse(text, "\t ", "\n", NULL, pattern) != 0;
633 }
634
635 /**
636 * Forward declaration.
637 */
638 static bool parse_files(linked_list_t *files, char *file, int level,
639 char *pattern, section_t *section);
640
641 /**
642 * Parse a section
643 */
644 static bool parse_section(linked_list_t *files, char *file, int level,
645 char **text, section_t *section)
646 {
647 bool finished = FALSE;
648 char *key, *value, *inner;
649
650 while (!finished)
651 {
652 if (parse_include(text, &value))
653 {
654 if (!parse_files(files, file, level, value, section))
655 {
656 DBG1(DBG_LIB, "failed to include '%s'", value);
657 return FALSE;
658 }
659 continue;
660 }
661 switch (parse(text, "\t\n ", "{=#", NULL, &key))
662 {
663 case '{':
664 if (parse(text, "\t ", "}", "{", &inner))
665 {
666 section_t *sub;
667 if (section->sections->find_first(section->sections,
668 (linked_list_match_t)section_find,
669 (void**)&sub, key) != SUCCESS)
670 {
671 sub = section_create(key);
672 if (parse_section(files, file, level, &inner, sub))
673 {
674 section->sections->insert_last(section->sections,
675 sub);
676 continue;
677 }
678 section_destroy(sub);
679 }
680 else
681 { /* extend the existing section */
682 if (parse_section(files, file, level, &inner, sub))
683 {
684 continue;
685 }
686 }
687 DBG1(DBG_LIB, "parsing subsection '%s' failed", key);
688 break;
689 }
690 DBG1(DBG_LIB, "matching '}' not found near %s", *text);
691 break;
692 case '=':
693 if (parse(text, "\t ", "\n", NULL, &value))
694 {
695 kv_t *kv;
696 if (section->kv->find_first(section->kv,
697 (linked_list_match_t)kv_find,
698 (void**)&kv, key) != SUCCESS)
699 {
700 INIT(kv,
701 .key = key,
702 .value = value,
703 );
704 section->kv->insert_last(section->kv, kv);
705 }
706 else
707 { /* replace with the most recently read value */
708 kv->value = value;
709 }
710 continue;
711 }
712 DBG1(DBG_LIB, "parsing value failed near %s", *text);
713 break;
714 case '#':
715 parse(text, "", "\n", NULL, &value);
716 continue;
717 default:
718 finished = TRUE;
719 continue;
720 }
721 return FALSE;
722 }
723 return TRUE;
724 }
725
726 /**
727 * Parse a file and add the settings to the given section.
728 */
729 static bool parse_file(linked_list_t *files, char *file, int level,
730 section_t *section)
731 {
732 bool success;
733 char *text, *pos;
734 FILE *fd;
735 int len;
736
737 DBG2(DBG_LIB, "loading config file '%s'", file);
738 fd = fopen(file, "r");
739 if (fd == NULL)
740 {
741 DBG1(DBG_LIB, "'%s' does not exist or is not readable", file);
742 return FALSE;
743 }
744 fseek(fd, 0, SEEK_END);
745 len = ftell(fd);
746 rewind(fd);
747 text = malloc(len + 1);
748 text[len] = '\0';
749 if (fread(text, 1, len, fd) != len)
750 {
751 free(text);
752 return FALSE;
753 }
754 fclose(fd);
755
756 pos = text;
757 success = parse_section(files, file, level, &pos, section);
758 if (!success)
759 {
760 free(text);
761 }
762 else
763 {
764 files->insert_last(files, text);
765 }
766 return success;
767 }
768
769 /**
770 * Load the files matching "pattern", which is resolved with glob(3).
771 * If the pattern is relative, the directory of "file" is used as base.
772 */
773 static bool parse_files(linked_list_t *files, char *file, int level,
774 char *pattern, section_t *section)
775 {
776 bool success = TRUE;
777 int status;
778 glob_t buf;
779 char **expanded, pat[PATH_MAX];
780
781 if (level > MAX_INCLUSION_LEVEL)
782 {
783 DBG1(DBG_LIB, "maximum level of %d includes reached, ignored",
784 MAX_INCLUSION_LEVEL);
785 return TRUE;
786 }
787
788 if (!strlen(pattern))
789 {
790 DBG2(DBG_LIB, "empty include pattern, ignored");
791 return TRUE;
792 }
793
794 if (!file || pattern[0] == '/')
795 { /* absolute path */
796 if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat))
797 {
798 DBG1(DBG_LIB, "include pattern too long, ignored");
799 return TRUE;
800 }
801 }
802 else
803 { /* base relative paths to the directory of the current file */
804 char *dir = strdup(file);
805 dir = dirname(dir);
806 if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat))
807 {
808 DBG1(DBG_LIB, "include pattern too long, ignored");
809 free(dir);
810 return TRUE;
811 }
812 free(dir);
813 }
814 status = glob(pat, GLOB_ERR, NULL, &buf);
815 if (status == GLOB_NOMATCH)
816 {
817 DBG2(DBG_LIB, "no files found matching '%s', ignored", pat);
818 }
819 else if (status != 0)
820 {
821 DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat);
822 success = FALSE;
823 }
824 else
825 {
826 for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
827 {
828 success &= parse_file(files, *expanded, level + 1, section);
829 if (!success)
830 {
831 break;
832 }
833 }
834 }
835 globfree(&buf);
836 return success;
837 }
838
839 /**
840 * Recursivly extends "base" with "extension".
841 */
842 static void section_extend(section_t *base, section_t *extension)
843 {
844 enumerator_t *sections, *values;
845 section_t *sec;
846 kv_t *kv;
847
848 sections = extension->sections->create_enumerator(extension->sections);
849 while (sections->enumerate(sections, (void**)&sec))
850 {
851 section_t *found;
852 if (base->sections->find_first(base->sections,
853 (linked_list_match_t)section_find, (void**)&found,
854 sec->name) == SUCCESS)
855 {
856 section_extend(found, sec);
857 }
858 else
859 {
860 extension->sections->remove_at(extension->sections, sections);
861 base->sections->insert_last(base->sections, sec);
862 }
863 }
864 sections->destroy(sections);
865
866 values = extension->kv->create_enumerator(extension->kv);
867 while (values->enumerate(values, (void**)&kv))
868 {
869 kv_t *found;
870 if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find,
871 (void**)&found, kv->key) == SUCCESS)
872 {
873 found->value = kv->value;
874 }
875 else
876 {
877 extension->kv->remove_at(extension->kv, values);
878 base->kv->insert_last(base->kv, kv);
879 }
880 }
881 values->destroy(values);
882 }
883
884 /**
885 * Load settings from files matching the given file pattern.
886 * All sections and values are added relative to "parent".
887 * All files (even included ones) have to be loaded successfully.
888 */
889 static bool load_files_internal(private_settings_t *this, section_t *parent,
890 char *pattern)
891 {
892 char *text;
893 linked_list_t *files = linked_list_create();
894 section_t *section = section_create(NULL);
895
896 if (!parse_files(files, NULL, 0, pattern, section))
897 {
898 files->destroy_function(files, (void*)free);
899 section_destroy(section);
900 return FALSE;
901 }
902
903 this->lock->write_lock(this->lock);
904 /* extend parent section */
905 section_extend(parent, section);
906 /* move contents of loaded files to main store */
907 while (files->remove_first(files, (void**)&text) == SUCCESS)
908 {
909 this->files->insert_last(this->files, text);
910 }
911 this->lock->unlock(this->lock);
912
913 section_destroy(section);
914 files->destroy(files);
915 return TRUE;
916 }
917
918 METHOD(settings_t, load_files, bool,
919 private_settings_t *this, char *pattern)
920 {
921 return load_files_internal(this, this->top, pattern);
922 }
923
924 METHOD(settings_t, load_files_section, bool,
925 private_settings_t *this, char *pattern, char *key, ...)
926 {
927 section_t *section;
928 va_list args;
929
930 va_start(args, key);
931 section = find_section(this, this->top, key, args);
932 va_end(args);
933
934 if (!section)
935 {
936 return FALSE;
937 }
938 return load_files_internal(this, section, pattern);
939 }
940
941 METHOD(settings_t, destroy, void,
942 private_settings_t *this)
943 {
944 section_destroy(this->top);
945 this->files->destroy_function(this->files, (void*)free);
946 this->lock->destroy(this->lock);
947 free(this);
948 }
949
950 /*
951 * see header file
952 */
953 settings_t *settings_create(char *file)
954 {
955 private_settings_t *this;
956
957 INIT(this,
958 .public = {
959 .get_str = _get_str,
960 .get_int = _get_int,
961 .get_double = _get_double,
962 .get_time = _get_time,
963 .get_bool = _get_bool,
964 .create_section_enumerator = _create_section_enumerator,
965 .create_key_value_enumerator = _create_key_value_enumerator,
966 .load_files = _load_files,
967 .load_files_section = _load_files_section,
968 .destroy = _destroy,
969 },
970 .top = section_create(NULL),
971 .files = linked_list_create(),
972 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
973 );
974
975 if (file == NULL)
976 {
977 file = STRONGSWAN_CONF;
978 }
979
980 load_files(this, file);
981
982 return &this->public;
983 }
984