Return to eap_radius_plugin.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / eap_radius |
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, §ion)) 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: }