added EAP-SIM authentication
[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_END(eap_type_names, EAP_AKA);
49
50 ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
51 "EAP_REQUEST",
52 "EAP_RESPONSE",
53 "EAP_SUCCESS",
54 "EAP_FAILURE",
55 );
56
57 ENUM(eap_role_names, EAP_SERVER, EAP_PEER,
58 "EAP_SERVER",
59 "EAP_PEER",
60 );
61
62
63 typedef struct module_entry_t module_entry_t;
64
65 /**
66 * Representation of a loaded module: EAP type, library handle, constructor
67 */
68 struct module_entry_t {
69 eap_type_t type;
70 void *handle;
71 eap_constructor_t constructor;
72 };
73
74 /** List of module_entry_t's */
75 static linked_list_t *modules = NULL;
76
77 /**
78 * unload modules at daemon shutdown
79 */
80 void eap_method_unload()
81 {
82 if (modules)
83 {
84 module_entry_t *entry;
85
86 while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
87 {
88 DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type);
89 dlclose(entry->handle);
90 free(entry);
91 }
92 modules->destroy(modules);
93 modules = NULL;
94 }
95 }
96
97 /**
98 * Load EAP modules at daemon startup
99 */
100 void eap_method_load(char *directory)
101 {
102 struct dirent* entry;
103 struct stat stb;
104 DIR* dir;
105
106 eap_method_unload();
107 modules = linked_list_create();
108
109 if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR))
110 {
111 DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
112 return;
113 }
114 if (stb.st_uid != 0)
115 {
116 DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory);
117 return;
118 }
119 if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
120 {
121 DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory);
122 return;
123 }
124
125 dir = opendir(directory);
126 if (dir == NULL)
127 {
128 DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
129 return;
130 }
131
132 DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
133
134 while ((entry = readdir(dir)) != NULL)
135 {
136 char file[256];
137 module_entry_t module, *loaded_module;
138 eap_method_t *method;
139 identification_t *id;
140 char *ending;
141
142 snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
143
144 if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
145 {
146 DBG2(DBG_CFG, " skipping %s, doesn't look like a file",
147 entry->d_name);
148 continue;
149 }
150 ending = entry->d_name + strlen(entry->d_name) - 3;
151 if (ending <= entry->d_name || !streq(ending, ".so"))
152 {
153 /* skip anything which does not look like a library */
154 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
155 entry->d_name);
156 continue;
157 }
158 if (stb.st_uid != 0)
159 {
160 DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name);
161 return;
162 }
163 if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
164 {
165 DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name);
166 continue;
167 }
168
169 /* try to load the library */
170 module.handle = dlopen(file, RTLD_LAZY);
171 if (module.handle == NULL)
172 {
173 DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
174 dlerror());
175 continue;
176 }
177 module.constructor = dlsym(module.handle, "eap_create");
178 if (module.constructor == NULL)
179 {
180 DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
181 entry->d_name);
182 dlclose(module.handle);
183 continue;
184 }
185
186 /* get the type implemented in the method, create an instance for it */
187 id = identification_create_from_string("john@doe.xyz");
188 method = module.constructor(EAP_SERVER, id, id);
189 if (method == NULL)
190 {
191 method = module.constructor(EAP_PEER, id, id);
192 }
193 id->destroy(id);
194 if (method == NULL)
195 {
196 DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
197 entry->d_name);
198 dlclose(module.handle);
199 continue;
200 }
201 module.type = method->get_type(method);
202 method->destroy(method);
203
204 DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
205 eap_type_names, module.type, entry->d_name);
206
207 loaded_module = malloc_thing(module_entry_t);
208 memcpy(loaded_module, &module, sizeof(module));
209 modules->insert_last(modules, loaded_module);
210 }
211 closedir(dir);
212 }
213
214 /*
215 * Described in header.
216 */
217 eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
218 identification_t *server,
219 identification_t *peer)
220 {
221 eap_method_t *method = NULL;
222 iterator_t *iterator;
223 module_entry_t *entry;
224
225 iterator = modules->create_iterator(modules, TRUE);
226 while (iterator->iterate(iterator, (void**)&entry))
227 {
228 if (entry->type == type)
229 {
230 method = entry->constructor(role, server, peer);
231 if (method)
232 {
233 break;
234 }
235 }
236 }
237 iterator->destroy(iterator);
238
239 if (method == NULL)
240 {
241 DBG1(DBG_CFG, "no EAP module found for %N %N",
242 eap_type_names, type, eap_role_names, role);
243 }
244 return method;
245 }