62b53e5ac890e78eb581bf5b2bedd4491a7b756e
[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 "radius_client.h"
22 #include "radius_server.h"
23
24 #include <daemon.h>
25 #include <threading/rwlock.h>
26
27 /**
28 * Default RADIUS server port for authentication
29 */
30 #define AUTH_PORT 1812
31
32 /**
33 * Default RADIUS server port for accounting
34 */
35 #define ACCT_PORT 1813
36
37 typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
38
39 /**
40 * Private data of an eap_radius_plugin_t object.
41 */
42 struct private_eap_radius_plugin_t {
43
44 /**
45 * Public radius_plugin_t interface.
46 */
47 eap_radius_plugin_t public;
48
49 /**
50 * List of RADIUS servers
51 */
52 linked_list_t *servers;
53
54 /**
55 * Lock for server list
56 */
57 rwlock_t *lock;
58
59 /**
60 * RADIUS sessions for accounting
61 */
62 eap_radius_accounting_t *accounting;
63
64 /**
65 * Dynamic authorization extensions
66 */
67 eap_radius_dae_t *dae;
68 };
69
70 /**
71 * Instance of the EAP plugin
72 */
73 static private_eap_radius_plugin_t *instance = NULL;
74
75 /**
76 * Load RADIUS servers from configuration
77 */
78 static void load_servers(private_eap_radius_plugin_t *this)
79 {
80 enumerator_t *enumerator;
81 radius_server_t *server;
82 char *nas_identifier, *secret, *address, *section;
83 int auth_port, acct_port, sockets, preference;
84
85 address = lib->settings->get_str(lib->settings,
86 "charon.plugins.eap-radius.server", NULL);
87 if (address)
88 { /* legacy configuration */
89 secret = lib->settings->get_str(lib->settings,
90 "charon.plugins.eap-radius.secret", NULL);
91 if (!secret)
92 {
93 DBG1(DBG_CFG, "no RADUIS secret defined");
94 return;
95 }
96 nas_identifier = lib->settings->get_str(lib->settings,
97 "charon.plugins.eap-radius.nas_identifier", "strongSwan");
98 auth_port = lib->settings->get_int(lib->settings,
99 "charon.plugins.eap-radius.port", AUTH_PORT);
100 sockets = lib->settings->get_int(lib->settings,
101 "charon.plugins.eap-radius.sockets", 1);
102 server = radius_server_create(address, address, auth_port, ACCT_PORT,
103 nas_identifier, secret, sockets, 0);
104 if (!server)
105 {
106 DBG1(DBG_CFG, "no RADUIS server defined");
107 return;
108 }
109 this->servers->insert_last(this->servers, server);
110 return;
111 }
112
113 enumerator = lib->settings->create_section_enumerator(lib->settings,
114 "charon.plugins.eap-radius.servers");
115 while (enumerator->enumerate(enumerator, &section))
116 {
117 address = lib->settings->get_str(lib->settings,
118 "charon.plugins.eap-radius.servers.%s.address", NULL, section);
119 if (!address)
120 {
121 DBG1(DBG_CFG, "RADIUS server '%s' misses address, skipped", section);
122 continue;
123 }
124 secret = lib->settings->get_str(lib->settings,
125 "charon.plugins.eap-radius.servers.%s.secret", NULL, section);
126 if (!secret)
127 {
128 DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
129 continue;
130 }
131 nas_identifier = lib->settings->get_str(lib->settings,
132 "charon.plugins.eap-radius.servers.%s.nas_identifier",
133 "strongSwan", section);
134 auth_port = lib->settings->get_int(lib->settings,
135 "charon.plugins.eap-radius.servers.%s.auth_port",
136 lib->settings->get_int(lib->settings,
137 "charon.plugins.eap-radius.servers.%s.port",
138 AUTH_PORT, section),
139 section);
140 acct_port = lib->settings->get_int(lib->settings,
141 "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section);
142 sockets = lib->settings->get_int(lib->settings,
143 "charon.plugins.eap-radius.servers.%s.sockets", 1, section);
144 preference = lib->settings->get_int(lib->settings,
145 "charon.plugins.eap-radius.servers.%s.preference", 0, section);
146 server = radius_server_create(section, address, auth_port, acct_port,
147 nas_identifier, secret, sockets, preference);
148 if (!server)
149 {
150 DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
151 continue;
152 }
153 this->servers->insert_last(this->servers, server);
154 }
155 enumerator->destroy(enumerator);
156
157 DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
158 this->servers->get_count(this->servers),
159 this->servers->get_count(this->servers) == 1 ? "" : "s");
160 }
161
162 METHOD(plugin_t, get_name, char*,
163 private_eap_radius_plugin_t *this)
164 {
165 return "eap-radius";
166 }
167
168 METHOD(plugin_t, get_features, int,
169 eap_radius_plugin_t *this, plugin_feature_t *features[])
170 {
171 static plugin_feature_t f[] = {
172 PLUGIN_CALLBACK(eap_method_register, eap_radius_create),
173 PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS),
174 PLUGIN_DEPENDS(HASHER, HASH_MD5),
175 PLUGIN_DEPENDS(SIGNER, AUTH_HMAC_MD5_128),
176 PLUGIN_DEPENDS(RNG, RNG_WEAK),
177 };
178 *features = f;
179 return countof(f);
180 }
181
182 METHOD(plugin_t, reload, bool,
183 private_eap_radius_plugin_t *this)
184 {
185 this->lock->write_lock(this->lock);
186 this->servers->destroy_offset(this->servers,
187 offsetof(radius_server_t, destroy));
188 this->servers = linked_list_create();
189 load_servers(this);
190 this->lock->unlock(this->lock);
191 return TRUE;
192 }
193
194 METHOD(plugin_t, destroy, void,
195 private_eap_radius_plugin_t *this)
196 {
197 DESTROY_IF(this->dae);
198 this->servers->destroy_offset(this->servers,
199 offsetof(radius_server_t, destroy));
200 this->lock->destroy(this->lock);
201 charon->bus->remove_listener(charon->bus, &this->accounting->listener);
202 this->accounting->destroy(this->accounting);
203 free(this);
204 instance = NULL;
205 }
206
207 /*
208 * see header file
209 */
210 plugin_t *eap_radius_plugin_create()
211 {
212 private_eap_radius_plugin_t *this;
213
214 INIT(this,
215 .public = {
216 .plugin = {
217 .get_name = _get_name,
218 .get_features = _get_features,
219 .reload = _reload,
220 .destroy = _destroy,
221 },
222 },
223 .servers = linked_list_create(),
224 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
225 .accounting = eap_radius_accounting_create(),
226 );
227
228 load_servers(this);
229 instance = this;
230
231 if (lib->settings->get_bool(lib->settings,
232 "charon.plugins.eap-radius.accounting", FALSE))
233 {
234 charon->bus->add_listener(charon->bus, &this->accounting->listener);
235 }
236 if (lib->settings->get_bool(lib->settings,
237 "charon.plugins.eap-radius.dae.enable", FALSE))
238 {
239 this->dae = eap_radius_dae_create(this->accounting);
240 }
241
242 return &this->public.plugin;
243 }
244
245 /**
246 * See header
247 */
248 enumerator_t *eap_radius_create_server_enumerator()
249 {
250 if (instance)
251 {
252 instance->lock->read_lock(instance->lock);
253 return enumerator_create_cleaner(
254 instance->servers->create_enumerator(instance->servers),
255 (void*)instance->lock->unlock, instance->lock);
256 }
257 return enumerator_create_empty();
258 }
259