Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_radius/eap_radius_plugin.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Tobias Brunner
                      3:  * Copyright (C) 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: /*
                     18:  * Copyright (C) 2015 Thom Troy
                     19:  *
                     20:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     21:  * of this software and associated documentation files (the "Software"), to deal
                     22:  * in the Software without restriction, including without limitation the rights
                     23:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     24:  * copies of the Software, and to permit persons to whom the Software is
                     25:  * furnished to do so, subject to the following conditions:
                     26:  *
                     27:  * The above copyright notice and this permission notice shall be included in
                     28:  * all copies or substantial portions of the Software.
                     29:  *
                     30:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     31:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     32:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     33:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     34:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     35:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     36:  * THE SOFTWARE.
                     37:  */
                     38: 
                     39: #include "eap_radius_plugin.h"
                     40: 
                     41: #include "eap_radius.h"
                     42: #include "eap_radius_xauth.h"
                     43: #include "eap_radius_accounting.h"
                     44: #include "eap_radius_dae.h"
                     45: #include "eap_radius_forward.h"
                     46: #include "eap_radius_provider.h"
                     47: 
                     48: #include <radius_client.h>
                     49: #include <radius_config.h>
                     50: 
                     51: #include <daemon.h>
                     52: #include <threading/rwlock.h>
                     53: #include <processing/jobs/callback_job.h>
                     54: #include <processing/jobs/delete_ike_sa_job.h>
                     55: 
                     56: /**
                     57:  * Default RADIUS server port for authentication
                     58:  */
                     59: #define AUTH_PORT 1812
                     60: 
                     61: /**
                     62:  * Default RADIUS server port for accounting
                     63:  */
                     64: #define ACCT_PORT 1813
                     65: 
                     66: typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
                     67: 
                     68: /**
                     69:  * Private data of an eap_radius_plugin_t object.
                     70:  */
                     71: struct private_eap_radius_plugin_t {
                     72: 
                     73:        /**
                     74:         * Public radius_plugin_t interface.
                     75:         */
                     76:        eap_radius_plugin_t public;
                     77: 
                     78:        /**
                     79:         * List of RADIUS server configurations
                     80:         */
                     81:        linked_list_t *configs;
                     82: 
                     83:        /**
                     84:         * Lock for configs list
                     85:         */
                     86:        rwlock_t *lock;
                     87: 
                     88:        /**
                     89:         * RADIUS sessions for accounting
                     90:         */
                     91:        eap_radius_accounting_t *accounting;
                     92: 
                     93:        /**
                     94:         * IKE attribute provider
                     95:         */
                     96:        eap_radius_provider_t *provider;
                     97: 
                     98:        /**
                     99:         * Dynamic authorization extensions
                    100:         */
                    101:        eap_radius_dae_t *dae;
                    102: 
                    103:        /**
                    104:         * RADIUS <-> IKE attribute forwarding
                    105:         */
                    106:        eap_radius_forward_t *forward;
                    107: };
                    108: 
                    109: /**
                    110:  * Instance of the EAP plugin
                    111:  */
                    112: static private_eap_radius_plugin_t *instance = NULL;
                    113: 
                    114: /**
                    115:  * Load RADIUS servers from configuration
                    116:  */
                    117: static void load_configs(private_eap_radius_plugin_t *this)
                    118: {
                    119:        enumerator_t *enumerator;
                    120:        radius_config_t *config;
                    121:        char *nas_identifier, *secret, *address, *section;
                    122:        int auth_port, acct_port, sockets, preference;
                    123:        u_int retransmit_tries;
                    124:        double retransmit_timeout, retransmit_base;
                    125: 
                    126:        address = lib->settings->get_str(lib->settings,
                    127:                                                                "%s.plugins.eap-radius.server", NULL, lib->ns);
                    128:        if (address)
                    129:        {       /* legacy configuration */
                    130:                secret = lib->settings->get_str(lib->settings,
                    131:                                                                "%s.plugins.eap-radius.secret", NULL, lib->ns);
                    132:                if (!secret)
                    133:                {
                    134:                        DBG1(DBG_CFG, "no RADIUS secret defined");
                    135:                        return;
                    136:                }
                    137:                nas_identifier = lib->settings->get_str(lib->settings,
                    138:                                                "%s.plugins.eap-radius.nas_identifier", "strongSwan",
                    139:                                                lib->ns);
                    140:                auth_port = lib->settings->get_int(lib->settings,
                    141:                                                "%s.plugins.eap-radius.port", AUTH_PORT, lib->ns);
                    142:                sockets = lib->settings->get_int(lib->settings,
                    143:                                                "%s.plugins.eap-radius.sockets", 1, lib->ns);
                    144: 
                    145:                retransmit_tries = lib->settings->get_int(lib->settings,
                    146:                                                "%s.plugins.eap-radius.retransmit_tries", 4, lib->ns);
                    147:                retransmit_timeout = lib->settings->get_double(lib->settings,
                    148:                                                "%s.plugins.eap-radius.retransmit_timeout", 2, lib->ns);
                    149:                retransmit_base = lib->settings->get_double(lib->settings,
                    150:                                                "%s.plugins.eap-radius.retransmit_base", 1.4, lib->ns);
                    151: 
                    152:                config = radius_config_create(address, address, auth_port, ACCT_PORT,
                    153:                                                                          nas_identifier, secret, sockets, 0,
                    154:                                                                          retransmit_tries, retransmit_timeout,
                    155:                                                                          retransmit_base);
                    156:                if (!config)
                    157:                {
                    158:                        DBG1(DBG_CFG, "no RADUIS server defined");
                    159:                        return;
                    160:                }
                    161:                this->configs->insert_last(this->configs, config);
                    162:                return;
                    163:        }
                    164: 
                    165:        enumerator = lib->settings->create_section_enumerator(lib->settings,
                    166:                                                                        "%s.plugins.eap-radius.servers", lib->ns);
                    167:        while (enumerator->enumerate(enumerator, &section))
                    168:        {
                    169:                address = lib->settings->get_str(lib->settings,
                    170:                                                        "%s.plugins.eap-radius.servers.%s.address", NULL,
                    171:                                                        lib->ns, section);
                    172:                if (!address)
                    173:                {
                    174:                        DBG1(DBG_CFG, "RADIUS server '%s' misses address, skipped", section);
                    175:                        continue;
                    176:                }
                    177:                secret = lib->settings->get_str(lib->settings,
                    178:                                                        "%s.plugins.eap-radius.servers.%s.secret", NULL,
                    179:                                                        lib->ns, section);
                    180:                if (!secret)
                    181:                {
                    182:                        DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
                    183:                        continue;
                    184:                }
                    185:                nas_identifier = lib->settings->get_str(lib->settings,
                    186:                                "%s.plugins.eap-radius.servers.%s.nas_identifier",
                    187:                                        lib->settings->get_str(lib->settings,
                    188:                                                "%s.plugins.eap-radius.nas_identifier", "strongSwan",
                    189:                                                lib->ns),
                    190:                                lib->ns, section);
                    191:                auth_port = lib->settings->get_int(lib->settings,
                    192:                        "%s.plugins.eap-radius.servers.%s.auth_port",
                    193:                                lib->settings->get_int(lib->settings,
                    194:                                        "%s.plugins.eap-radius.servers.%s.port",
                    195:                                                lib->settings->get_int(lib->settings,
                    196:                                                        "%s.plugins.eap-radius.port", AUTH_PORT, lib->ns),
                    197:                                        lib->ns, section),
                    198:                        lib->ns, section);
                    199:                acct_port = lib->settings->get_int(lib->settings,
                    200:                                "%s.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT,
                    201:                                lib->ns, section);
                    202:                sockets = lib->settings->get_int(lib->settings,
                    203:                                "%s.plugins.eap-radius.servers.%s.sockets",
                    204:                                        lib->settings->get_int(lib->settings,
                    205:                                                "%s.plugins.eap-radius.sockets", 1, lib->ns),
                    206:                                lib->ns, section);
                    207: 
                    208:                retransmit_tries = lib->settings->get_int(lib->settings,
                    209:                                "%s.plugins.eap-radius.servers.%s.retransmit_tries",
                    210:                                        lib->settings->get_int(lib->settings,
                    211:                                                "%s.plugins.eap-radius.retransmit_tries", 4, lib->ns),
                    212:                                lib->ns, section);
                    213: 
                    214:                retransmit_timeout = lib->settings->get_double(lib->settings,
                    215:                                "%s.plugins.eap-radius.servers.%s.retransmit_timeout",
                    216:                                        lib->settings->get_double(lib->settings,
                    217:                                                "%s.plugins.eap-radius.retransmit_timeout", 2, lib->ns),
                    218:                                lib->ns, section);
                    219: 
                    220:                retransmit_base = lib->settings->get_double(lib->settings,
                    221:                                "%s.plugins.eap-radius.servers.%s.retransmit_base",
                    222:                                        lib->settings->get_double(lib->settings,
                    223:                                                "%s.plugins.eap-radius.retransmit_base", 1.4, lib->ns),
                    224:                                lib->ns, section);
                    225: 
                    226:                preference = lib->settings->get_int(lib->settings,
                    227:                                "%s.plugins.eap-radius.servers.%s.preference", 0,
                    228:                                lib->ns, section);
                    229: 
                    230:                config = radius_config_create(section, address, auth_port, acct_port,
                    231:                                                                nas_identifier, secret, sockets, preference,
                    232:                                                                retransmit_tries, retransmit_timeout,
                    233:                                                                retransmit_base);
                    234:                if (!config)
                    235:                {
                    236:                        DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
                    237:                        continue;
                    238:                }
                    239:                this->configs->insert_last(this->configs, config);
                    240:        }
                    241:        enumerator->destroy(enumerator);
                    242: 
                    243:        DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
                    244:                 this->configs->get_count(this->configs),
                    245:                 this->configs->get_count(this->configs) == 1 ? "" : "s");
                    246: }
                    247: 
                    248: METHOD(plugin_t, get_name, char*,
                    249:        private_eap_radius_plugin_t *this)
                    250: {
                    251:        return "eap-radius";
                    252: }
                    253: 
                    254: /**
                    255:  * Register listener
                    256:  */
                    257: static bool plugin_cb(private_eap_radius_plugin_t *this,
                    258:                                          plugin_feature_t *feature, bool reg, void *cb_data)
                    259: {
                    260:        if (reg)
                    261:        {
                    262:                this->accounting = eap_radius_accounting_create();
                    263:                this->forward = eap_radius_forward_create();
                    264:                this->provider = eap_radius_provider_create();
                    265: 
                    266:                load_configs(this);
                    267: 
                    268:                if (lib->settings->get_bool(lib->settings,
                    269:                                                "%s.plugins.eap-radius.dae.enable", FALSE, lib->ns))
                    270:                {
                    271:                        this->dae = eap_radius_dae_create(this->accounting);
                    272:                }
                    273:                if (this->forward)
                    274:                {
                    275:                        charon->bus->add_listener(charon->bus, &this->forward->listener);
                    276:                }
                    277:                charon->attributes->add_provider(charon->attributes,
                    278:                                                                                 &this->provider->provider);
                    279:        }
                    280:        else
                    281:        {
                    282:                charon->attributes->remove_provider(charon->attributes,
                    283:                                                                                        &this->provider->provider);
                    284:                if (this->forward)
                    285:                {
                    286:                        charon->bus->remove_listener(charon->bus, &this->forward->listener);
                    287:                        this->forward->destroy(this->forward);
                    288:                }
                    289:                DESTROY_IF(this->dae);
                    290:                this->provider->destroy(this->provider);
                    291:                this->accounting->destroy(this->accounting);
                    292:        }
                    293:        return TRUE;
                    294: }
                    295: 
                    296: METHOD(plugin_t, get_features, int,
                    297:        private_eap_radius_plugin_t *this, plugin_feature_t *features[])
                    298: {
                    299:        static plugin_feature_t f[] = {
                    300:                PLUGIN_CALLBACK(eap_method_register, eap_radius_create),
                    301:                        PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS),
                    302:                                PLUGIN_DEPENDS(CUSTOM, "eap-radius"),
                    303:                PLUGIN_CALLBACK(xauth_method_register, eap_radius_xauth_create_server),
                    304:                        PLUGIN_PROVIDE(XAUTH_SERVER, "radius"),
                    305:                                PLUGIN_DEPENDS(CUSTOM, "eap-radius"),
                    306:                PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
                    307:                        PLUGIN_PROVIDE(CUSTOM, "eap-radius"),
                    308:                                PLUGIN_DEPENDS(HASHER, HASH_MD5),
                    309:                                PLUGIN_DEPENDS(SIGNER, AUTH_HMAC_MD5_128),
                    310:                                PLUGIN_DEPENDS(RNG, RNG_WEAK),
                    311:        };
                    312:        *features = f;
                    313:        return countof(f);
                    314: }
                    315: 
                    316: METHOD(plugin_t, reload, bool,
                    317:        private_eap_radius_plugin_t *this)
                    318: {
                    319:        this->lock->write_lock(this->lock);
                    320:        this->configs->destroy_offset(this->configs,
                    321:                                                                  offsetof(radius_config_t, destroy));
                    322:        this->configs = linked_list_create();
                    323:        load_configs(this);
                    324:        this->lock->unlock(this->lock);
                    325:        return TRUE;
                    326: }
                    327: 
                    328: METHOD(plugin_t, destroy, void,
                    329:        private_eap_radius_plugin_t *this)
                    330: {
                    331:        this->configs->destroy_offset(this->configs,
                    332:                                                                  offsetof(radius_config_t, destroy));
                    333:        this->lock->destroy(this->lock);
                    334:        free(this);
                    335:        instance = NULL;
                    336: }
                    337: 
                    338: /*
                    339:  * see header file
                    340:  */
                    341: plugin_t *eap_radius_plugin_create()
                    342: {
                    343:        private_eap_radius_plugin_t *this;
                    344: 
                    345:        INIT(this,
                    346:                .public = {
                    347:                        .plugin = {
                    348:                                .get_name = _get_name,
                    349:                                .get_features = _get_features,
                    350:                                .reload = _reload,
                    351:                                .destroy = _destroy,
                    352:                        },
                    353:                },
                    354:                .configs = linked_list_create(),
                    355:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    356:        );
                    357:        instance = this;
                    358: 
                    359:        return &this->public.plugin;
                    360: }
                    361: 
                    362: /**
                    363:  * See header
                    364:  */
                    365: radius_client_t *eap_radius_create_client()
                    366: {
                    367:        if (instance)
                    368:        {
                    369:                enumerator_t *enumerator;
                    370:                radius_config_t *config, *selected = NULL;
                    371:                int current, best = -1;
                    372: 
                    373:                instance->lock->read_lock(instance->lock);
                    374:                enumerator = instance->configs->create_enumerator(instance->configs);
                    375:                while (enumerator->enumerate(enumerator, &config))
                    376:                {
                    377:                        current = config->get_preference(config);
                    378:                        if (current > best ||
                    379:                                /* for two with equal preference, 50-50 chance */
                    380:                                (current == best && random() % 2 == 0))
                    381:                        {
                    382:                                DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
                    383:                                         config->get_name(config), current);
                    384:                                best = current;
                    385:                                DESTROY_IF(selected);
                    386:                                selected = config->get_ref(config);
                    387:                        }
                    388:                        else
                    389:                        {
                    390:                                DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
                    391:                                         config->get_name(config), current);
                    392:                        }
                    393:                }
                    394:                enumerator->destroy(enumerator);
                    395:                instance->lock->unlock(instance->lock);
                    396: 
                    397:                if (selected)
                    398:                {
                    399:                        return radius_client_create(selected);
                    400:                }
                    401:        }
                    402:        return NULL;
                    403: }
                    404: 
                    405: /**
                    406:  * Job to delete all active IKE_SAs
                    407:  */
                    408: static job_requeue_t delete_all_async(void *data)
                    409: {
                    410:        enumerator_t *enumerator;
                    411:        ike_sa_t *ike_sa;
                    412: 
                    413:        enumerator = charon->ike_sa_manager->create_enumerator(
                    414:                                                                                                charon->ike_sa_manager, TRUE);
                    415:        while (enumerator->enumerate(enumerator, &ike_sa))
                    416:        {
                    417:                lib->processor->queue_job(lib->processor,
                    418:                                (job_t*)delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
                    419:        }
                    420:        enumerator->destroy(enumerator);
                    421: 
                    422:        return JOB_REQUEUE_NONE;
                    423: }
                    424: 
                    425: /**
                    426:  * See header.
                    427:  */
                    428: void eap_radius_handle_timeout(ike_sa_id_t *id)
                    429: {
                    430:        charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
                    431: 
                    432:        if (lib->settings->get_bool(lib->settings,
                    433:                                                                "%s.plugins.eap-radius.close_all_on_timeout",
                    434:                                                                FALSE, lib->ns))
                    435:        {
                    436:                DBG1(DBG_CFG, "deleting all IKE_SAs after RADIUS timeout");
                    437:                lib->processor->queue_job(lib->processor,
                    438:                                (job_t*)callback_job_create_with_prio(
                    439:                                                (callback_job_cb_t)delete_all_async, NULL, NULL,
                    440:                                                (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
                    441:        }
                    442:        else if (id)
                    443:        {
                    444:                DBG1(DBG_CFG, "deleting IKE_SA after RADIUS timeout");
                    445:                lib->processor->queue_job(lib->processor,
                    446:                                (job_t*)delete_ike_sa_job_create(id, TRUE));
                    447:        }
                    448: }

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