changing UID/GID after startup of pluto/charon
[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 DIR* dir;
104
105 eap_method_unload();
106 modules = linked_list_create();
107
108 dir = opendir(directory);
109 if (dir == NULL)
110 {
111 DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
112 return;
113 }
114
115 DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
116
117 while ((entry = readdir(dir)) != NULL)
118 {
119 char file[256];
120 module_entry_t module, *loaded_module;
121 eap_method_t *method;
122 identification_t *id;
123 char *ending;
124
125 snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
126
127 ending = entry->d_name + strlen(entry->d_name) - 3;
128 if (ending <= entry->d_name || !streq(ending, ".so"))
129 {
130 /* skip anything which does not look like a library */
131 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
132 entry->d_name);
133 continue;
134 }
135
136 /* try to load the library */
137 module.handle = dlopen(file, RTLD_LAZY);
138 if (module.handle == NULL)
139 {
140 DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
141 dlerror());
142 continue;
143 }
144 module.constructor = dlsym(module.handle, "eap_create");
145 if (module.constructor == NULL)
146 {
147 DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
148 entry->d_name);
149 dlclose(module.handle);
150 continue;
151 }
152
153 /* get the type implemented in the method, create an instance for it */
154 id = identification_create_from_string("john@doe.xyz");
155 method = module.constructor(EAP_SERVER, id, id);
156 if (method == NULL)
157 {
158 method = module.constructor(EAP_PEER, id, id);
159 }
160 id->destroy(id);
161 if (method == NULL)
162 {
163 DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
164 entry->d_name);
165 dlclose(module.handle);
166 continue;
167 }
168 module.type = method->get_type(method);
169 method->destroy(method);
170
171 DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
172 eap_type_names, module.type, entry->d_name);
173
174 loaded_module = malloc_thing(module_entry_t);
175 memcpy(loaded_module, &module, sizeof(module));
176 modules->insert_last(modules, loaded_module);
177 }
178 closedir(dir);
179 }
180
181 /*
182 * Described in header.
183 */
184 eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
185 identification_t *server,
186 identification_t *peer)
187 {
188 eap_method_t *method = NULL;
189 iterator_t *iterator;
190 module_entry_t *entry;
191
192 iterator = modules->create_iterator(modules, TRUE);
193 while (iterator->iterate(iterator, (void**)&entry))
194 {
195 if (entry->type == type)
196 {
197 method = entry->constructor(role, server, peer);
198 if (method)
199 {
200 break;
201 }
202 }
203 }
204 iterator->destroy(iterator);
205
206 if (method == NULL)
207 {
208 DBG1(DBG_CFG, "no EAP module found for %N %N",
209 eap_type_names, type, eap_role_names, role);
210 }
211 return method;
212 }