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