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, &section))
                    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, &section))
                    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, &section))
                    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(&section->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(&section->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, &current);
                    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(&section->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, &section))
                    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>