Annotation of embedaddon/strongswan/src/libcharon/config/backend_manager.c, revision 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>