Annotation of embedaddon/strongswan/src/starter/parser/conf_parser.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013-2014 Tobias Brunner
3: * HSR 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:
16: #include "conf_parser.h"
17:
18: #include <collections/array.h>
19: #include <collections/hashtable.h>
20:
21: /**
22: * Provided by the generated parser
23: */
24: bool conf_parser_parse_file(conf_parser_t *this, char *file);
25:
26: typedef struct private_conf_parser_t private_conf_parser_t;
27: typedef struct section_t section_t;
28:
29: /**
30: * Private data
31: */
32: struct private_conf_parser_t {
33:
34: /**
35: * Public interface
36: */
37: conf_parser_t public;
38:
39: /**
40: * Path to config file
41: */
42: char *file;
43:
44: /**
45: * TRUE while parsing the config file
46: */
47: bool parsing;
48:
49: /**
50: * Hashtable for ca sections, as section_t
51: */
52: hashtable_t *cas;
53:
54: /**
55: * Hashtable for conn sections, as section_t
56: */
57: hashtable_t *conns;
58:
59: /**
60: * Array to keep track of the order of conn sections, as section_t
61: */
62: array_t *conns_order;
63:
64: /**
65: * config setup section
66: */
67: section_t *config_setup;
68:
69: /**
70: * Pointer to the current section (the one added last) during parsing
71: */
72: section_t *current_section;
73:
74: /**
75: * Refcount for this parser instance (also used by dictionaries)
76: */
77: refcount_t ref;
78: };
79:
80: typedef struct {
81: /** Key of the setting */
82: char *key;
83: /** Value of the setting */
84: char *value;
85: } setting_t;
86:
87: int setting_find(const void *a, const void *b)
88: {
89: const char *key = a;
90: const setting_t *setting = b;
91: return strcmp(key, setting->key);
92: }
93:
94: int setting_sort(const void *a, const void *b, void *user)
95: {
96: const setting_t *sa = a, *sb = b;
97: return strcmp(sa->key, sb->key);
98: }
99:
100: static void setting_destroy(setting_t *this)
101: {
102: free(this->key);
103: free(this->value);
104: free(this);
105: }
106:
107: struct section_t {
108: /** Name of the section */
109: char *name;
110: /** Sorted array of settings, as setting_t */
111: array_t *settings;
112: /** Array of also= settings (in reversed order, i.e. most important to least
113: * important), as setting_t */
114: array_t *also;
115: /** Array of linearized parent objects derived from also= settings, in their
116: * order of importance (most to least, i.e. %default) as section_t
117: * NULL if not yet determined */
118: array_t *parents;
119: };
120:
121: static section_t *section_create(char *name)
122: {
123: section_t *this;
124:
125: INIT(this,
126: .name = name,
127: );
128: return this;
129: }
130:
131: static void section_destroy(section_t *this)
132: {
133: array_destroy_function(this->settings, (void*)setting_destroy, NULL);
134: array_destroy_function(this->also, (void*)setting_destroy, NULL);
135: array_destroy(this->parents);
136: free(this->name);
137: free(this);
138: }
139:
140: typedef struct {
141: /** Public interface */
142: dictionary_t public;
143: /** Parser object */
144: private_conf_parser_t *parser;
145: /** Section object */
146: section_t *section;
147: } section_dictionary_t;
148:
149: typedef struct {
150: /** Public interface */
151: enumerator_t public;
152: /** Current settings enumerator */
153: enumerator_t *settings;
154: /** Enumerator into parent list */
155: enumerator_t *parents;
156: /** Hashtable to keep track of already enumerated settings */
157: hashtable_t *seen;
158: } dictionary_enumerator_t;
159:
160: METHOD(enumerator_t, dictionary_enumerate, bool,
161: dictionary_enumerator_t *this, va_list args)
162: {
163: setting_t *setting;
164: section_t *parent;
165: char **key, **value;
166:
167: VA_ARGS_VGET(args, key, value);
168:
169: while (TRUE)
170: {
171: if (this->settings &&
172: this->settings->enumerate(this->settings, &setting))
173: {
174: if (this->seen->get(this->seen, setting->key))
175: {
176: continue;
177: }
178: this->seen->put(this->seen, setting->key, setting->key);
179: if (!setting->value)
180: {
181: continue;
182: }
183: if (key)
184: {
185: *key = setting->key;
186: }
187: if (value)
188: {
189: *value = setting->value;
190: }
191: return TRUE;
192: }
193: DESTROY_IF(this->settings);
194: this->settings = NULL;
195: if (this->parents &&
196: this->parents->enumerate(this->parents, &parent))
197: {
198: if (parent->settings)
199: {
200: this->settings = array_create_enumerator(parent->settings);
201: }
202: continue;
203: }
204: DESTROY_IF(this->parents);
205: this->parents = NULL;
206: break;
207: }
208: return FALSE;
209: }
210:
211: METHOD(enumerator_t, dictionary_enumerator_destroy, void,
212: dictionary_enumerator_t *this)
213: {
214: DESTROY_IF(this->settings);
215: DESTROY_IF(this->parents);
216: this->seen->destroy(this->seen);
217: free(this);
218: }
219:
220: METHOD(dictionary_t, dictionary_create_enumerator, enumerator_t*,
221: section_dictionary_t *this)
222: {
223: dictionary_enumerator_t *enumerator;
224:
225: INIT(enumerator,
226: .public = {
227: .enumerate = enumerator_enumerate_default,
228: .venumerate = _dictionary_enumerate,
229: .destroy = _dictionary_enumerator_destroy,
230: },
231: .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
232: );
233: if (this->section->settings)
234: {
235: enumerator->settings = array_create_enumerator(this->section->settings);
236: }
237: if (this->section->parents)
238: {
239: enumerator->parents = array_create_enumerator(this->section->parents);
240: }
241: return &enumerator->public;
242: }
243:
244: METHOD(dictionary_t, dictionary_get, void*,
245: section_dictionary_t *this, const void *key)
246: {
247: enumerator_t *parents;
248: section_t *section;
249: setting_t *setting;
250: char *value = NULL;
251:
252: section = this->section;
253: if (array_bsearch(section->settings, key, setting_find, &setting) != -1)
254: {
255: return setting->value;
256: }
257: parents = array_create_enumerator(section->parents);
258: while (parents->enumerate(parents, §ion))
259: {
260: if (array_bsearch(section->settings, key, setting_find, &setting) != -1)
261: {
262: value = setting->value;
263: break;
264: }
265: }
266: parents->destroy(parents);
267: return value;
268: }
269:
270: METHOD(dictionary_t, dictionary_destroy, void,
271: section_dictionary_t *this)
272: {
273: this->parser->public.destroy(&this->parser->public);
274: free(this);
275: }
276:
277: static dictionary_t *section_dictionary_create(private_conf_parser_t *parser,
278: section_t *section)
279: {
280: section_dictionary_t *this;
281:
282: INIT(this,
283: .public = {
284: .create_enumerator = _dictionary_create_enumerator,
285: .get = _dictionary_get,
286: .destroy = _dictionary_destroy,
287: },
288: .parser = parser,
289: .section = section,
290: );
291:
292: ref_get(&parser->ref);
293:
294: return &this->public;
295: }
296:
297: CALLBACK(conn_filter, bool,
298: void *unused, enumerator_t *orig, va_list args)
299: {
300: section_t *section;
301: char **name;
302:
303: VA_ARGS_VGET(args, name);
304:
305: while (orig->enumerate(orig, §ion))
306: {
307: if (!streq(section->name, "%default"))
308: {
309: *name = section->name;
310: return TRUE;
311: }
312: }
313: return FALSE;
314: }
315:
316: CALLBACK(ca_filter, bool,
317: void *unused, enumerator_t *orig, va_list args)
318: {
319: void *key;
320: section_t *section;
321: char **name;
322:
323: VA_ARGS_VGET(args, name);
324:
325: while (orig->enumerate(orig, &key, §ion))
326: {
327: if (!streq(section->name, "%default"))
328: {
329: *name = section->name;
330: return TRUE;
331: }
332: }
333: return FALSE;
334: }
335:
336: METHOD(conf_parser_t, get_sections, enumerator_t*,
337: private_conf_parser_t *this, conf_parser_section_t type)
338: {
339: switch (type)
340: {
341: case CONF_PARSER_CONN:
342: return enumerator_create_filter(
343: array_create_enumerator(this->conns_order),
344: conn_filter, NULL, NULL);
345: case CONF_PARSER_CA:
346: return enumerator_create_filter(
347: this->cas->create_enumerator(this->cas),
348: ca_filter, NULL, NULL);
349: case CONF_PARSER_CONFIG_SETUP:
350: default:
351: return enumerator_create_empty();
352: }
353: }
354:
355: METHOD(conf_parser_t, get_section, dictionary_t*,
356: private_conf_parser_t *this, conf_parser_section_t type, char *name)
357: {
358: section_t *section = NULL;
359:
360: if (name && streq(name, "%default"))
361: {
362: return NULL;
363: }
364: switch (type)
365: {
366: case CONF_PARSER_CONFIG_SETUP:
367: section = this->config_setup;
368: break;
369: case CONF_PARSER_CONN:
370: section = this->conns->get(this->conns, name);
371: break;
372: case CONF_PARSER_CA:
373: section = this->cas->get(this->cas, name);
374: break;
375: default:
376: break;
377: }
378: return section ? section_dictionary_create(this, section) : NULL;
379: }
380:
381: METHOD(conf_parser_t, add_section, bool,
382: private_conf_parser_t *this, conf_parser_section_t type, char *name)
383: {
384: hashtable_t *sections = this->conns;
385: array_t *order = this->conns_order;
386: section_t *section = NULL;
387: bool exists = FALSE;
388:
389: if (!this->parsing)
390: {
391: free(name);
392: return exists;
393: }
394: switch (type)
395: {
396: case CONF_PARSER_CONFIG_SETUP:
397: section = this->config_setup;
398: /* we don't expect a name, but just in case */
399: free(name);
400: break;
401: case CONF_PARSER_CA:
402: sections = this->cas;
403: order = NULL;
404: /* fall-through */
405: case CONF_PARSER_CONN:
406: section = sections->get(sections, name);
407: if (!section)
408: {
409: section = section_create(name);
410: sections->put(sections, name, section);
411: if (order)
412: {
413: array_insert(order, ARRAY_TAIL, section);
414: }
415: }
416: else
417: {
418: exists = TRUE;
419: free(name);
420: }
421: break;
422:
423: }
424: this->current_section = section;
425: return exists;
426: }
427:
428: METHOD(conf_parser_t, add_setting, void,
429: private_conf_parser_t *this, char *key, char *value)
430: {
431: section_t *section = this->current_section;
432: setting_t *setting;
433:
434: if (!this->parsing || !this->current_section)
435: {
436: free(key);
437: free(value);
438: return;
439: }
440: if (streq(key, "also"))
441: {
442: if (!value || !strlen(value) || streq(value, "%default"))
443: { /* we require a name, but all sections inherit from %default */
444: free(key);
445: free(value);
446: return;
447: }
448: INIT(setting,
449: .key = key,
450: .value = value,
451: );
452: array_insert_create(§ion->also, ARRAY_HEAD, setting);
453: return;
454: }
455: if (array_bsearch(section->settings, key, setting_find, &setting) == -1)
456: {
457: INIT(setting,
458: .key = key,
459: .value = value,
460: );
461: array_insert_create(§ion->settings, ARRAY_TAIL, setting);
462: array_sort(section->settings, setting_sort, NULL);
463: }
464: else
465: {
466: free(setting->value);
467: setting->value = value;
468: free(key);
469: }
470: }
471:
472: /**
473: * Check if the given section is contained in the given array. The search
474: * starts at the given index.
475: */
476: static bool is_contained_in(array_t *arr, section_t *section)
477: {
478: section_t *current;
479: int i;
480:
481: for (i = 0; i < array_count(arr); i++)
482: {
483: array_get(arr, i, ¤t);
484: if (streq(section->name, current->name))
485: {
486: return TRUE;
487: }
488: }
489: return FALSE;
490: }
491:
492: /**
493: * This algorithm to linearize sections uses a bottom-first depth-first
494: * semantic, with an additional elimination step that removes all but the
495: * last occurrence of each section.
496: *
497: * Consider this configuration:
498: *
499: * conn A
500: * conn B
501: * also=A
502: * conn C
503: * also=A
504: * conn D
505: * also=C
506: * also=B
507: *
508: * The linearization would yield D B A C A, which gets reduced to D B C A.
509: *
510: * Ambiguous configurations are handled pragmatically.
511: *
512: * Consider the following configuration:
513: *
514: * conn A
515: * conn B
516: * conn C
517: * also=A
518: * also=B
519: * conn D
520: * also=B
521: * also=A
522: * conn E
523: * also=C
524: * also=D
525: *
526: * It is ambiguous because D and C include the same two sections but in
527: * a different order.
528: *
529: * The linearization would yield E D A B C B A which gets reduced to E D C B A.
530: */
531: static bool resolve_also_single(hashtable_t *sections,
532: section_t *section, section_t *def, array_t *stack)
533: {
534: enumerator_t *enumerator;
535: array_t *parents;
536: section_t *parent, *grandparent;
537: setting_t *also;
538: bool success = TRUE;
539: int i;
540:
541: array_insert(stack, ARRAY_HEAD, section);
542: parents = array_create(0, 0);
543: enumerator = array_create_enumerator(section->also);
544: while (enumerator->enumerate(enumerator, &also))
545: {
546: parent = sections->get(sections, also->value);
547: if (!parent || is_contained_in(stack, parent))
548: {
549: if (!parent)
550: {
551: DBG1(DBG_CFG, "section '%s' referenced in section '%s' not "
552: "found", also->value, section->name);
553: }
554: else
555: {
556: DBG1(DBG_CFG, "section '%s' referenced in section '%s' causes "
557: "a loop", parent->name, section->name);
558: }
559: array_remove_at(section->also, enumerator);
560: setting_destroy(also);
561: success = FALSE;
562: continue;
563: }
564: if (!parent->parents)
565: {
566: if (!resolve_also_single(sections, parent, def, stack))
567: {
568: success = FALSE;
569: continue;
570: }
571: }
572: /* add the grandparents and the parent to the list */
573: array_insert(parents, ARRAY_TAIL, parent);
574: for (i = 0; i < array_count(parent->parents); i++)
575: {
576: array_get(parent->parents, i, &grandparent);
577: array_insert(parents, ARRAY_TAIL, grandparent);
578: }
579: }
580: enumerator->destroy(enumerator);
581: array_remove(stack, ARRAY_HEAD, NULL);
582:
583: if (success && def && !array_count(parents))
584: {
585: array_insert(parents, ARRAY_TAIL, def);
586: }
587:
588: while (success && array_remove(parents, ARRAY_HEAD, &parent))
589: {
590: if (!is_contained_in(parents, parent))
591: { /* last occurrence of this section */
592: array_insert_create(§ion->parents, ARRAY_TAIL, parent);
593: }
594: }
595: array_destroy(parents);
596: return success;
597: }
598:
599: /**
600: * Resolve also= statements. The functions returns TRUE if everything is fine,
601: * or FALSE if either a referenced section does not exist, or if the section
602: * inheritance can't be determined properly (e.g. if there are loops or if a
603: * section inherits from multiple sections - perhaps over several levels - in
604: * an ambiguous way).
605: */
606: static bool resolve_also(hashtable_t *sections)
607: {
608: enumerator_t *enumerator;
609: section_t *def, *section;
610: array_t *stack;
611: bool success = TRUE;
612:
613: stack = array_create(0, 0);
614:
615: def = sections->get(sections, "%default");
616: if (def)
617: { /* the default section is the only one with an empty parents list */
618: def->parents = array_create(0, 0);
619: }
620: enumerator = sections->create_enumerator(sections);
621: while (enumerator->enumerate(enumerator, NULL, §ion))
622: {
623: if (section->parents)
624: { /* already determined */
625: continue;
626: }
627: success = resolve_also_single(sections, section, def, stack) && success;
628: }
629: enumerator->destroy(enumerator);
630: array_destroy(stack);
631: return success;
632: }
633:
634: METHOD(conf_parser_t, parse, bool,
635: private_conf_parser_t *this)
636: {
637: bool success;
638:
639: if (!this->file)
640: { /* no file, lets assume this is OK */
641: return TRUE;
642: }
643: this->parsing = TRUE;
644: success = conf_parser_parse_file(&this->public, this->file);
645: this->parsing = FALSE;
646: return success && resolve_also(this->conns) && resolve_also(this->cas);
647: }
648:
649: METHOD(conf_parser_t, destroy, void,
650: private_conf_parser_t *this)
651: {
652: if (ref_put(&this->ref))
653: {
654: this->cas->destroy_function(this->cas, (void*)section_destroy);
655: this->conns->destroy_function(this->conns, (void*)section_destroy);
656: section_destroy(this->config_setup);
657: array_destroy(this->conns_order);
658: free(this->file);
659: free(this);
660: }
661: }
662:
663: /*
664: * Described in header
665: */
666: conf_parser_t *conf_parser_create(const char *file)
667: {
668: private_conf_parser_t *this;
669:
670: INIT(this,
671: .public = {
672: .parse = _parse,
673: .get_sections = _get_sections,
674: .get_section = _get_section,
675: .add_section = _add_section,
676: .add_setting = _add_setting,
677: .destroy = _destroy,
678: },
679: .file = strdupnull(file),
680: .cas = hashtable_create(hashtable_hash_str,
681: hashtable_equals_str, 8),
682: .conns = hashtable_create(hashtable_hash_str,
683: hashtable_equals_str, 8),
684: .conns_order = array_create(0, 0),
685: .config_setup = section_create(NULL),
686: .ref = 1,
687: );
688:
689: return &this->public;
690: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>