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