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, §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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>