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