implemented Expanded EAP types to support vendor specific methods
[strongswan.git] / src / charon / sa / authenticators / eap / eap_method.c
1 /**
2 * @file eap_method.c
3 *
4 * @brief Generic constructor for eap_methods.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <dirent.h>
26 #include <error.h>
27 #include <dlfcn.h>
28
29 #include "eap_method.h"
30
31 #include <daemon.h>
32 #include <library.h>
33 #include <utils/linked_list.h>
34 #include <utils/identification.h>
35
36
37 ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD,
38 "EAP_IDENTITY",
39 "EAP_NOTIFICATION",
40 "EAP_NAK",
41 "EAP_MD5",
42 "EAP_ONE_TIME_PASSWORD",
43 "EAP_TOKEN_CARD");
44 ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD,
45 "EAP_SIM");
46 ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
47 "EAP_AKA");
48 ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_EXPERIMENTAL, EAP_AKA,
49 "EAP_EXPANDED",
50 "EAP_EXPERIMENTAL");
51 ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
52
53 ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
54 "EAP_REQUEST",
55 "EAP_RESPONSE",
56 "EAP_SUCCESS",
57 "EAP_FAILURE",
58 );
59
60 ENUM(eap_role_names, EAP_SERVER, EAP_PEER,
61 "EAP_SERVER",
62 "EAP_PEER",
63 );
64
65
66 typedef struct module_entry_t module_entry_t;
67
68 /**
69 * Representation of a loaded module: EAP type, library handle, constructor
70 */
71 struct module_entry_t {
72 eap_type_t type;
73 u_int32_t vendor;
74 void *handle;
75 eap_constructor_t constructor;
76 };
77
78 /** List of module_entry_t's */
79 static linked_list_t *modules = NULL;
80
81 /**
82 * unload modules at daemon shutdown
83 */
84 void eap_method_unload()
85 {
86 if (modules)
87 {
88 module_entry_t *entry;
89
90 while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
91 {
92 DBG2(DBG_CFG, "unloaded module EAP module %d-%d",
93 entry->type, entry->vendor);
94 dlclose(entry->handle);
95 free(entry);
96 }
97 modules->destroy(modules);
98 modules = NULL;
99 }
100 }
101
102 /**
103 * Load EAP modules at daemon startup
104 */
105 void eap_method_load(char *directory)
106 {
107 struct dirent* entry;
108 DIR* dir;
109
110 eap_method_unload();
111 modules = linked_list_create();
112
113 dir = opendir(directory);
114 if (dir == NULL)
115 {
116 DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
117 return;
118 }
119
120 DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
121
122 while ((entry = readdir(dir)) != NULL)
123 {
124 char file[256];
125 module_entry_t module, *loaded_module;
126 eap_method_t *method;
127 identification_t *id;
128 char *ending;
129
130 snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
131
132 ending = entry->d_name + strlen(entry->d_name) - 3;
133 if (ending <= entry->d_name || !streq(ending, ".so"))
134 {
135 /* skip anything which does not look like a library */
136 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
137 entry->d_name);
138 continue;
139 }
140
141 /* try to load the library */
142 module.handle = dlopen(file, RTLD_LAZY);
143 if (module.handle == NULL)
144 {
145 DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
146 dlerror());
147 continue;
148 }
149 module.constructor = dlsym(module.handle, "eap_create");
150 if (module.constructor == NULL)
151 {
152 DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
153 entry->d_name);
154 dlclose(module.handle);
155 continue;
156 }
157
158 /* get the type implemented in the method, create an instance for it */
159 id = identification_create_from_string("john@doe.xyz");
160 method = module.constructor(EAP_SERVER, id, id);
161 if (method == NULL)
162 {
163 method = module.constructor(EAP_PEER, id, id);
164 }
165 id->destroy(id);
166 if (method == NULL)
167 {
168 DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
169 entry->d_name);
170 dlclose(module.handle);
171 continue;
172 }
173 module.type = method->get_type(method, &module.vendor);
174 method->destroy(method);
175
176 if (module.vendor)
177 {
178 DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s",
179 module.type, module.vendor, entry->d_name);
180 }
181 else
182 {
183 DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
184 eap_type_names, module.type, entry->d_name);
185 }
186
187 loaded_module = malloc_thing(module_entry_t);
188 memcpy(loaded_module, &module, sizeof(module));
189 modules->insert_last(modules, loaded_module);
190 }
191 closedir(dir);
192 }
193
194 /*
195 * Described in header.
196 */
197 eap_method_t *eap_method_create(eap_type_t type, u_int32_t vendor, eap_role_t role,
198 identification_t *server, identification_t *peer)
199 {
200 eap_method_t *method = NULL;
201 iterator_t *iterator;
202 module_entry_t *entry;
203
204 iterator = modules->create_iterator(modules, TRUE);
205 while (iterator->iterate(iterator, (void**)&entry))
206 {
207 if (entry->type == type && entry->vendor == vendor)
208 {
209 method = entry->constructor(role, server, peer);
210 if (method)
211 {
212 break;
213 }
214 }
215 }
216 iterator->destroy(iterator);
217
218 if (method == NULL)
219 {
220 if (vendor)
221 {
222 DBG1(DBG_CFG, "no vendor %d specific EAP module found for method "
223 "%d %N", vendor, type, eap_role_names, role);
224 }
225 else
226 {
227 DBG1(DBG_CFG, "no EAP module found for %N %N",
228 eap_type_names, type, eap_role_names, role);
229 }
230 }
231 return method;
232 }