Annotation of embedaddon/strongswan/src/libcharon/config/backend_manager.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2018 Tobias Brunner
                      3:  * Copyright (C) 2007-2009 Martin Willi
                      4:  * HSR 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: #include "backend_manager.h"
                     18: 
                     19: #include <sys/types.h>
                     20: 
                     21: #include <daemon.h>
                     22: #include <collections/linked_list.h>
                     23: #include <threading/rwlock.h>
                     24: 
                     25: 
                     26: typedef struct private_backend_manager_t private_backend_manager_t;
                     27: 
                     28: /**
                     29:  * Private data of an backend_manager_t object.
                     30:  */
                     31: struct private_backend_manager_t {
                     32: 
                     33:        /**
                     34:         * Public part of backend_manager_t object.
                     35:         */
                     36:        backend_manager_t public;
                     37: 
                     38:        /**
                     39:         * list of registered backends
                     40:         */
                     41:        linked_list_t *backends;
                     42: 
                     43:        /**
                     44:         * rwlock for backends
                     45:         */
                     46:        rwlock_t *lock;
                     47: };
                     48: 
                     49: /**
                     50:  * match of an ike_cfg
                     51:  */
                     52: typedef enum ike_cfg_match_t {
                     53:        /* doesn't match at all */
                     54:        MATCH_NONE              = 0x00,
                     55:        /* match for a %any host. For both hosts, hence skip 0x02 */
                     56:        MATCH_ANY               = 0x01,
                     57:        /* IKE version matches exactly (config is not for any version) */
                     58:        MATCH_VERSION   = 0x04,
                     59:        /* local identity matches */
                     60:        MATCH_ME                = 0x08,
                     61:        /* remote identity matches */
                     62:        MATCH_OTHER             = 0x10,
                     63: } ike_cfg_match_t;
                     64: 
                     65: /**
                     66:  * data to pass nested IKE enumerator
                     67:  */
                     68: typedef struct {
                     69:        private_backend_manager_t *this;
                     70:        host_t *me;
                     71:        host_t *other;
                     72: } ike_data_t;
                     73: 
                     74: /**
                     75:  * inner enumerator constructor for IKE cfgs
                     76:  */
                     77: static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
                     78: {
                     79:        return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
                     80: }
                     81: 
                     82: /**
                     83:  * get a match of a candidate ike_cfg for two hosts
                     84:  */
                     85: static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
                     86:                                                                         ike_version_t version)
                     87: {
                     88:        ike_cfg_match_t match = MATCH_NONE;
                     89:        int quality;
                     90: 
                     91:        if (cand->get_version(cand) != IKE_ANY &&
                     92:                version != cand->get_version(cand))
                     93:        {
                     94:                return MATCH_NONE;
                     95:        }
                     96: 
                     97:        if (me)
                     98:        {
                     99:                quality = cand->match_me(cand, me);
                    100:                if (!quality)
                    101:                {
                    102:                        return MATCH_NONE;
                    103:                }
                    104:                match += quality * MATCH_ME;
                    105:        }
                    106:        else
                    107:        {
                    108:                match += MATCH_ANY;
                    109:        }
                    110: 
                    111:        if (other)
                    112:        {
                    113:                quality = cand->match_other(cand, other);
                    114:                if (!quality)
                    115:                {
                    116:                        return MATCH_NONE;
                    117:                }
                    118:                match += quality * MATCH_OTHER;
                    119:        }
                    120:        else
                    121:        {
                    122:                match += MATCH_ANY;
                    123:        }
                    124: 
                    125:        if (match != MATCH_NONE &&
                    126:                cand->get_version(cand) != IKE_ANY)
                    127:        {       /* if we have a match, improve it if candidate version specified */
                    128:                match += MATCH_VERSION;
                    129:        }
                    130:        return match;
                    131: }
                    132: 
                    133: /**
                    134:  * list element to help sorting
                    135:  */
                    136: typedef struct {
                    137:        ike_cfg_match_t match;
                    138:        ike_cfg_t *cfg;
                    139: } ike_match_entry_t;
                    140: 
                    141: CALLBACK(ike_enum_filter, bool,
                    142:        linked_list_t *configs, enumerator_t *orig, va_list args)
                    143: {
                    144:        ike_match_entry_t *entry;
                    145:        ike_cfg_t **out;
                    146: 
                    147:        VA_ARGS_VGET(args, out);
                    148: 
                    149:        if (orig->enumerate(orig, &entry))
                    150:        {
                    151:                *out = entry->cfg;
                    152:                return TRUE;
                    153:        }
                    154:        return FALSE;
                    155: }
                    156: 
                    157: CALLBACK(ike_match_entry_list_destroy, void,
                    158:        linked_list_t *configs)
                    159: {
                    160:        ike_match_entry_t *entry;
                    161: 
                    162:        while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
                    163:        {
                    164:                entry->cfg->destroy(entry->cfg);
                    165:                free(entry);
                    166:        }
                    167:        configs->destroy(configs);
                    168: }
                    169: 
                    170: /**
                    171:  * Insert entry into match-sorted list
                    172:  */
                    173: static void insert_sorted_ike(ike_match_entry_t *entry, linked_list_t *list)
                    174: {
                    175:        enumerator_t *enumerator;
                    176:        ike_match_entry_t *current;
                    177: 
                    178:        enumerator = list->create_enumerator(list);
                    179:        while (enumerator->enumerate(enumerator, &current))
                    180:        {
                    181:                if (entry->match > current->match)
                    182:                {
                    183:                        break;
                    184:                }
                    185:        }
                    186:        list->insert_before(list, enumerator, entry);
                    187:        enumerator->destroy(enumerator);
                    188: }
                    189: 
                    190: /**
                    191:  * Create a sorted list of all matching IKE configs
                    192:  */
                    193: static linked_list_t *get_matching_ike_cfgs(private_backend_manager_t *this,
                    194:                                                                                        host_t *me, host_t *other,
                    195:                                                                                        ike_version_t version)
                    196: {
                    197:        ike_cfg_t *current;
                    198:        char *my_addr, *other_addr;
                    199:        enumerator_t *enumerator;
                    200:        ike_data_t *data;
                    201:        linked_list_t *configs;
                    202:        ike_cfg_match_t match;
                    203:        ike_match_entry_t *entry;
                    204: 
                    205:        INIT(data,
                    206:                .this = this,
                    207:                .me = me,
                    208:                .other = other,
                    209:        );
                    210: 
                    211:        configs = linked_list_create();
                    212: 
                    213:        this->lock->read_lock(this->lock);
                    214:        enumerator = enumerator_create_nested(
                    215:                                                this->backends->create_enumerator(this->backends),
                    216:                                                (void*)ike_enum_create, data, (void*)free);
                    217: 
                    218:        while (enumerator->enumerate(enumerator, &current))
                    219:        {
                    220:                my_addr = current->get_my_addr(current);
                    221:                other_addr = current->get_other_addr(current);
                    222:                match = get_ike_match(current, me, other, version);
                    223:                DBG3(DBG_CFG, "ike config match: %d (%s...%s %N)", match, my_addr,
                    224:                         other_addr, ike_version_names, current->get_version(current));
                    225: 
                    226:                if (match)
                    227:                {
                    228:                        DBG2(DBG_CFG, "  candidate: %s...%s, prio %d",
                    229:                                 my_addr, other_addr, match);
                    230: 
                    231:                        INIT(entry,
                    232:                                .match = match,
                    233:                                .cfg = current->get_ref(current),
                    234:                        );
                    235:                        insert_sorted_ike(entry, configs);
                    236:                }
                    237:        }
                    238:        enumerator->destroy(enumerator);
                    239:        this->lock->unlock(this->lock);
                    240: 
                    241:        return configs;
                    242: }
                    243: 
                    244: METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
                    245:        private_backend_manager_t *this, host_t *me, host_t *other,
                    246:        ike_version_t version)
                    247: {
                    248:        linked_list_t *configs;
                    249:        ike_match_entry_t *entry;
                    250:        ike_cfg_t *found = NULL;
                    251:        char *my_addr, *other_addr;
                    252: 
                    253:        DBG2(DBG_CFG, "looking for an %N config for %H...%H", ike_version_names,
                    254:                 version, me, other);
                    255: 
                    256:        configs = get_matching_ike_cfgs(this, me, other, version);
                    257:        if (configs->get_first(configs, (void**)&entry) == SUCCESS)
                    258:        {
                    259:                found = entry->cfg->get_ref(entry->cfg);
                    260: 
                    261:                my_addr = found->get_my_addr(found);
                    262:                other_addr = found->get_other_addr(found);
                    263:                DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
                    264:                         my_addr, other_addr, entry->match);
                    265:        }
                    266:        ike_match_entry_list_destroy(configs);
                    267: 
                    268:        return found;
                    269: }
                    270: 
                    271: METHOD(backend_manager_t, create_ike_cfg_enumerator, enumerator_t*,
                    272:        private_backend_manager_t *this, host_t *me, host_t *other,
                    273:        ike_version_t version)
                    274: {
                    275:        linked_list_t *configs;
                    276: 
                    277:        DBG2(DBG_CFG, "looking for %N configs for %H...%H", ike_version_names,
                    278:                 version, me, other);
                    279: 
                    280:        configs = get_matching_ike_cfgs(this, me, other, version);
                    281: 
                    282:        return enumerator_create_filter(configs->create_enumerator(configs),
                    283:                                                                        ike_enum_filter, configs,
                    284:                                                                        ike_match_entry_list_destroy);
                    285: }
                    286: 
                    287: /**
                    288:  * Get the best ID match in one of the configs auth_cfg
                    289:  */
                    290: static id_match_t get_peer_match(identification_t *id,
                    291:                                                                 peer_cfg_t *cfg, bool local)
                    292: {
                    293:        enumerator_t *enumerator;
                    294:        auth_cfg_t *auth;
                    295:        identification_t *candidate;
                    296:        id_match_t match = ID_MATCH_NONE;
                    297:        char *where = local ? "local" : "remote";
                    298:        chunk_t data;
                    299: 
                    300:        if (!id)
                    301:        {
                    302:                DBG3(DBG_CFG, "  %s id match: %d (%N)",
                    303:                         where, ID_MATCH_ANY, id_type_names, ID_ANY);
                    304:                return ID_MATCH_ANY;
                    305:        }
                    306: 
                    307:        /* compare first auth config only */
                    308:        enumerator = cfg->create_auth_cfg_enumerator(cfg, local);
                    309:        if (enumerator->enumerate(enumerator, &auth))
                    310:        {
                    311:                candidate = auth->get(auth, AUTH_RULE_IDENTITY);
                    312:                if (candidate)
                    313:                {
                    314:                        match = id->matches(id, candidate);
                    315:                        /* match vice-versa, as the proposed IDr might be ANY */
                    316:                        if (!match)
                    317:                        {
                    318:                                match = candidate->matches(candidate, id);
                    319:                        }
                    320:                }
                    321:                else
                    322:                {
                    323:                        match = ID_MATCH_ANY;
                    324:                }
                    325:        }
                    326:        enumerator->destroy(enumerator);
                    327: 
                    328:        data = id->get_encoding(id);
                    329:        DBG3(DBG_CFG, "  %s id match: %d (%N: %#B)",
                    330:                 where, match, id_type_names, id->get_type(id), &data);
                    331:        return match;
                    332: }
                    333: 
                    334: /**
                    335:  * data to pass nested peer enumerator
                    336:  */
                    337: typedef struct {
                    338:        rwlock_t *lock;
                    339:        identification_t *me;
                    340:        identification_t *other;
                    341: } peer_data_t;
                    342: 
                    343: /**
                    344:  * list element to help sorting
                    345:  */
                    346: typedef struct {
                    347:        id_match_t match_peer;
                    348:        ike_cfg_match_t match_ike;
                    349:        peer_cfg_t *cfg;
                    350: } match_entry_t;
                    351: 
                    352: /**
                    353:  * inner enumerator constructor for peer cfgs
                    354:  */
                    355: static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
                    356: {
                    357:        return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
                    358: }
                    359: 
                    360: /**
                    361:  * unlock/cleanup peer enumerator
                    362:  */
                    363: static void peer_enum_destroy(peer_data_t *data)
                    364: {
                    365:        data->lock->unlock(data->lock);
                    366:        free(data);
                    367: }
                    368: 
                    369: CALLBACK(peer_enum_filter, bool,
                    370:        linked_list_t *configs, enumerator_t *orig, va_list args)
                    371: {
                    372:        match_entry_t *entry;
                    373:        peer_cfg_t **out;
                    374: 
                    375:        VA_ARGS_VGET(args, out);
                    376: 
                    377:        if (orig->enumerate(orig, &entry))
                    378:        {
                    379:                *out = entry->cfg;
                    380:                return TRUE;
                    381:        }
                    382:        return FALSE;
                    383: }
                    384: 
                    385: CALLBACK(peer_enum_filter_destroy, void,
                    386:        linked_list_t *configs)
                    387: {
                    388:        match_entry_t *entry;
                    389: 
                    390:        while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
                    391:        {
                    392:                entry->cfg->destroy(entry->cfg);
                    393:                free(entry);
                    394:        }
                    395:        configs->destroy(configs);
                    396: }
                    397: 
                    398: /**
                    399:  * Insert entry into match-sorted list
                    400:  */
                    401: static void insert_sorted(match_entry_t *entry, linked_list_t *list)
                    402: {
                    403:        enumerator_t *enumerator;
                    404:        match_entry_t *current;
                    405: 
                    406:        enumerator = list->create_enumerator(list);
                    407:        while (enumerator->enumerate(enumerator, &current))
                    408:        {
                    409:                if ((entry->match_ike > current->match_ike &&
                    410:                         entry->match_peer >= current->match_peer) ||
                    411:                        (entry->match_ike >= current->match_ike &&
                    412:                          entry->match_peer > current->match_peer))
                    413:                {
                    414:                        break;
                    415:                }
                    416:        }
                    417:        list->insert_before(list, enumerator, entry);
                    418:        enumerator->destroy(enumerator);
                    419: }
                    420: 
                    421: METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
                    422:        private_backend_manager_t *this, host_t *me, host_t *other,
                    423:        identification_t *my_id, identification_t *other_id, ike_version_t version)
                    424: {
                    425:        enumerator_t *enumerator;
                    426:        peer_data_t *data;
                    427:        peer_cfg_t *cfg;
                    428:        linked_list_t *configs;
                    429: 
                    430:        INIT(data,
                    431:                .lock = this->lock,
                    432:                .me = my_id,
                    433:                .other = other_id,
                    434:        );
                    435: 
                    436:        /* create a sorted list with all matches */
                    437:        this->lock->read_lock(this->lock);
                    438:        enumerator = enumerator_create_nested(
                    439:                                        this->backends->create_enumerator(this->backends),
                    440:                                        (void*)peer_enum_create, data, (void*)peer_enum_destroy);
                    441: 
                    442:        if (!me && !other && !my_id && !other_id)
                    443:        {       /* shortcut if we are doing a "listall" */
                    444:                return enumerator;
                    445:        }
                    446: 
                    447:        configs = linked_list_create();
                    448:        while (enumerator->enumerate(enumerator, &cfg))
                    449:        {
                    450:                ike_cfg_t *ike_cfg = cfg->get_ike_cfg(cfg);
                    451:                ike_cfg_match_t match_ike;
                    452:                id_match_t match_peer_me, match_peer_other;
                    453:                match_entry_t *entry;
                    454:                char *my_addr, *other_addr;
                    455: 
                    456:                match_ike = get_ike_match(ike_cfg, me, other, version);
                    457:                my_addr = ike_cfg->get_my_addr(ike_cfg);
                    458:                other_addr = ike_cfg->get_other_addr(ike_cfg);
                    459:                DBG3(DBG_CFG, "peer config \"%s\", ike match: %d (%s...%s %N)",
                    460:                         cfg->get_name(cfg), match_ike, my_addr, other_addr,
                    461:                         ike_version_names, ike_cfg->get_version(ike_cfg));
                    462: 
                    463:                if (!match_ike)
                    464:                {
                    465:                        continue;
                    466:                }
                    467: 
                    468:                match_peer_me = get_peer_match(my_id, cfg, TRUE);
                    469:                if (!match_peer_me)
                    470:                {
                    471:                        continue;
                    472:                }
                    473:                match_peer_other = get_peer_match(other_id, cfg, FALSE);
                    474: 
                    475:                if (match_peer_other)
                    476:                {
                    477:                        DBG2(DBG_CFG, "  candidate \"%s\", match: %d/%d/%d (me/other/ike)",
                    478:                                 cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
                    479:                        INIT(entry,
                    480:                                .match_peer = match_peer_me + match_peer_other,
                    481:                                .match_ike = match_ike,
                    482:                                .cfg = cfg->get_ref(cfg),
                    483:                        );
                    484:                        insert_sorted(entry, configs);
                    485:                }
                    486:        }
                    487:        enumerator->destroy(enumerator);
                    488: 
                    489:        return enumerator_create_filter(configs->create_enumerator(configs),
                    490:                                                                        peer_enum_filter, configs,
                    491:                                                                        peer_enum_filter_destroy);
                    492: }
                    493: 
                    494: METHOD(backend_manager_t, get_peer_cfg_by_name, peer_cfg_t*,
                    495:        private_backend_manager_t *this, char *name)
                    496: {
                    497:        backend_t *backend;
                    498:        peer_cfg_t *config = NULL;
                    499:        enumerator_t *enumerator;
                    500: 
                    501:        this->lock->read_lock(this->lock);
                    502:        enumerator = this->backends->create_enumerator(this->backends);
                    503:        while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
                    504:        {
                    505:                config = backend->get_peer_cfg_by_name(backend, name);
                    506:        }
                    507:        enumerator->destroy(enumerator);
                    508:        this->lock->unlock(this->lock);
                    509:        return config;
                    510: }
                    511: 
                    512: METHOD(backend_manager_t, remove_backend, void,
                    513:        private_backend_manager_t *this, backend_t *backend)
                    514: {
                    515:        this->lock->write_lock(this->lock);
                    516:        this->backends->remove(this->backends, backend, NULL);
                    517:        this->lock->unlock(this->lock);
                    518: }
                    519: 
                    520: METHOD(backend_manager_t, add_backend, void,
                    521:        private_backend_manager_t *this, backend_t *backend)
                    522: {
                    523:        this->lock->write_lock(this->lock);
                    524:        this->backends->insert_last(this->backends, backend);
                    525:        this->lock->unlock(this->lock);
                    526: }
                    527: 
                    528: METHOD(backend_manager_t, destroy, void,
                    529:        private_backend_manager_t *this)
                    530: {
                    531:        this->backends->destroy(this->backends);
                    532:        this->lock->destroy(this->lock);
                    533:        free(this);
                    534: }
                    535: 
                    536: /*
                    537:  * Described in header
                    538:  */
                    539: backend_manager_t *backend_manager_create()
                    540: {
                    541:        private_backend_manager_t *this;
                    542: 
                    543:        INIT(this,
                    544:                .public = {
                    545:                        .get_ike_cfg = _get_ike_cfg,
                    546:                        .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
                    547:                        .get_peer_cfg_by_name = _get_peer_cfg_by_name,
                    548:                        .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
                    549:                        .add_backend = _add_backend,
                    550:                        .remove_backend = _remove_backend,
                    551:                        .destroy = _destroy,
                    552:                },
                    553:                .backends = linked_list_create(),
                    554:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    555:        );
                    556: 
                    557:        return &this->public;
                    558: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>