e544aaf3ec19cf818def86051fe015f30a7a2e4c
[strongswan.git] / src / libcharon / plugins / eap_radius / eap_radius_plugin.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "eap_radius_plugin.h"
17
18 #include "eap_radius.h"
19 #include "eap_radius_accounting.h"
20 #include "eap_radius_dae.h"
21 #include "eap_radius_forward.h"
22 #include "radius_client.h"
23 #include "radius_server.h"
24
25 #include <daemon.h>
26 #include <threading/rwlock.h>
27
28 /**
29 * Default RADIUS server port for authentication
30 */
31 #define AUTH_PORT 1812
32
33 /**
34 * Default RADIUS server port for accounting
35 */
36 #define ACCT_PORT 1813
37
38 typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
39
40 /**
41 * Private data of an eap_radius_plugin_t object.
42 */
43 struct private_eap_radius_plugin_t {
44
45 /**
46 * Public radius_plugin_t interface.
47 */
48 eap_radius_plugin_t public;
49
50 /**
51 * List of RADIUS servers
52 */
53 linked_list_t *servers;
54
55 /**
56 * Lock for server list
57 */
58 rwlock_t *lock;
59
60 /**
61 * RADIUS sessions for accounting
62 */
63 eap_radius_accounting_t *accounting;
64
65 /**
66 * Dynamic authorization extensions
67 */
68 eap_radius_dae_t *dae;
69
70 /**
71 * RADIUS <-> IKE attribute forwarding
72 */
73 eap_radius_forward_t *forward;
74 };
75
76 /**
77 * Instance of the EAP plugin
78 */
79 static private_eap_radius_plugin_t *instance = NULL;
80
81 /**
82 * Load RADIUS servers from configuration
83 */
84 static void load_servers(private_eap_radius_plugin_t *this)
85 {
86 enumerator_t *enumerator;
87 radius_server_t *server;
88 char *nas_identifier, *secret, *address, *section;
89 int auth_port, acct_port, sockets, preference;
90
91 address = lib->settings->get_str(lib->settings,
92 "charon.plugins.eap-radius.server", NULL);
93 if (address)
94 { /* legacy configuration */
95 secret = lib->settings->get_str(lib->settings,
96 "charon.plugins.eap-radius.secret", NULL);
97 if (!secret)
98 {
99 DBG1(DBG_CFG, "no RADUIS secret defined");
100 return;
101 }
102 nas_identifier = lib->settings->get_str(lib->settings,
103 "charon.plugins.eap-radius.nas_identifier", "strongSwan");
104 auth_port = lib->settings->get_int(lib->settings,
105 "charon.plugins.eap-radius.port", AUTH_PORT);
106 sockets = lib->settings->get_int(lib->settings,
107 "charon.plugins.eap-radius.sockets", 1);
108 server = radius_server_create(address, address, auth_port, ACCT_PORT,
109 nas_identifier, secret, sockets, 0);
110 if (!server)
111 {
112 DBG1(DBG_CFG, "no RADUIS server defined");
113 return;
114 }
115 this->servers->insert_last(this->servers, server);
116 return;
117 }
118
119 enumerator = lib->settings->create_section_enumerator(lib->settings,
120 "charon.plugins.eap-radius.servers");
121 while (enumerator->enumerate(enumerator, &section))
122 {
123 address = lib->settings->get_str(lib->settings,
124 "charon.plugins.eap-radius.servers.%s.address", NULL, section);
125 if (!address)
126 {
127 DBG1(DBG_CFG, "RADIUS server '%s' misses address, skipped", section);
128 continue;
129 }
130 secret = lib->settings->get_str(lib->settings,
131 "charon.plugins.eap-radius.servers.%s.secret", NULL, section);
132 if (!secret)
133 {
134 DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
135 continue;
136 }
137 nas_identifier = lib->settings->get_str(lib->settings,
138 "charon.plugins.eap-radius.servers.%s.nas_identifier",
139 "strongSwan", section);
140 auth_port = lib->settings->get_int(lib->settings,
141 "charon.plugins.eap-radius.servers.%s.auth_port",
142 lib->settings->get_int(lib->settings,
143 "charon.plugins.eap-radius.servers.%s.port",
144 AUTH_PORT, section),
145 section);
146 acct_port = lib->settings->get_int(lib->settings,
147 "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section);
148 sockets = lib->settings->get_int(lib->settings,
149 "charon.plugins.eap-radius.servers.%s.sockets", 1, section);
150 preference = lib->settings->get_int(lib->settings,
151 "charon.plugins.eap-radius.servers.%s.preference", 0, section);
152 server = radius_server_create(section, address, auth_port, acct_port,
153 nas_identifier, secret, sockets, preference);
154 if (!server)
155 {
156 DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
157 continue;
158 }
159 this->servers->insert_last(this->servers, server);
160 }
161 enumerator->destroy(enumerator);
162
163 DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
164 this->servers->get_count(this->servers),
165 this->servers->get_count(this->servers) == 1 ? "" : "s");
166 }
167
168 METHOD(plugin_t, get_name, char*,
169 private_eap_radius_plugin_t *this)
170 {
171 return "eap-radius";
172 }
173
174 METHOD(plugin_t, get_features, int,
175 eap_radius_plugin_t *this, plugin_feature_t *features[])
176 {
177 static plugin_feature_t f[] = {
178 PLUGIN_CALLBACK(eap_method_register, eap_radius_create),
179 PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS),
180 PLUGIN_DEPENDS(HASHER, HASH_MD5),
181 PLUGIN_DEPENDS(SIGNER, AUTH_HMAC_MD5_128),
182 PLUGIN_DEPENDS(RNG, RNG_WEAK),
183 };
184 *features = f;
185 return countof(f);
186 }
187
188 METHOD(plugin_t, reload, bool,
189 private_eap_radius_plugin_t *this)
190 {
191 this->lock->write_lock(this->lock);
192 this->servers->destroy_offset(this->servers,
193 offsetof(radius_server_t, destroy));
194 this->servers = linked_list_create();
195 load_servers(this);
196 this->lock->unlock(this->lock);
197 return TRUE;
198 }
199
200 METHOD(plugin_t, destroy, void,
201 private_eap_radius_plugin_t *this)
202 {
203 if (this->forward)
204 {
205 charon->bus->remove_listener(charon->bus, &this->forward->listener);
206 this->forward->destroy(this->forward);
207 }
208 DESTROY_IF(this->dae);
209 this->servers->destroy_offset(this->servers,
210 offsetof(radius_server_t, destroy));
211 this->lock->destroy(this->lock);
212 charon->bus->remove_listener(charon->bus, &this->accounting->listener);
213 this->accounting->destroy(this->accounting);
214 free(this);
215 instance = NULL;
216 }
217
218 /*
219 * see header file
220 */
221 plugin_t *eap_radius_plugin_create()
222 {
223 private_eap_radius_plugin_t *this;
224
225 INIT(this,
226 .public = {
227 .plugin = {
228 .get_name = _get_name,
229 .get_features = _get_features,
230 .reload = _reload,
231 .destroy = _destroy,
232 },
233 },
234 .servers = linked_list_create(),
235 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
236 .accounting = eap_radius_accounting_create(),
237 .forward = eap_radius_forward_create(),
238 );
239
240 load_servers(this);
241 instance = this;
242
243 if (lib->settings->get_bool(lib->settings,
244 "charon.plugins.eap-radius.accounting", FALSE))
245 {
246 charon->bus->add_listener(charon->bus, &this->accounting->listener);
247 }
248 if (lib->settings->get_bool(lib->settings,
249 "charon.plugins.eap-radius.dae.enable", FALSE))
250 {
251 this->dae = eap_radius_dae_create(this->accounting);
252 }
253 if (this->forward)
254 {
255 charon->bus->add_listener(charon->bus, &this->forward->listener);
256 }
257
258 return &this->public.plugin;
259 }
260
261 /**
262 * See header
263 */
264 enumerator_t *eap_radius_create_server_enumerator()
265 {
266 if (instance)
267 {
268 instance->lock->read_lock(instance->lock);
269 return enumerator_create_cleaner(
270 instance->servers->create_enumerator(instance->servers),
271 (void*)instance->lock->unlock, instance->lock);
272 }
273 return enumerator_create_empty();
274 }
275