Enabling the plugin loader to be able to load plugins without explicitly loading...
[strongswan.git] / src / libstrongswan / plugins / plugin_loader.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include "plugin_loader.h"
19
20 #include <string.h>
21 #include <dlfcn.h>
22 #include <limits.h>
23 #include <stdio.h>
24
25 #include <debug.h>
26 #include <integrity_checker.h>
27 #include <utils/linked_list.h>
28 #include <plugins/plugin.h>
29
30 typedef struct private_plugin_loader_t private_plugin_loader_t;
31
32 /**
33 * private data of plugin_loader
34 */
35 struct private_plugin_loader_t {
36
37 /**
38 * public functions
39 */
40 plugin_loader_t public;
41
42 /**
43 * list of loaded plugins
44 */
45 linked_list_t *plugins;
46
47 /**
48 * names of loaded plugins
49 */
50 linked_list_t *names;
51 };
52
53 /**
54 * Replace '-' with '_' to use str as identifier.
55 */
56 static char* sanitize(char *str)
57 {
58 char *pos = str;
59 while (pos && *pos)
60 {
61 if (*pos == '-')
62 {
63 *pos = '_';
64 }
65 pos++;
66 }
67 return str;
68 }
69
70 #ifdef MONOLITHIC
71 /**
72 * load a single plugin in monolithic mode
73 */
74 static plugin_t* load_plugin(private_plugin_loader_t *this,
75 char *path, char *name)
76 {
77 char create[128];
78 plugin_t *plugin;
79 plugin_constructor_t constructor;
80
81 if (snprintf(create, sizeof(create), "%s_plugin_create",
82 name) >= sizeof(create))
83 {
84 return NULL;
85 }
86 sanitize(create);
87 constructor = dlsym(RTLD_DEFAULT, create);
88 if (constructor == NULL)
89 {
90 DBG1("plugin '%s': failed to load - %s not found", name, create);
91 return NULL;
92 }
93 plugin = constructor();
94 if (plugin == NULL)
95 {
96 DBG1("plugin '%s': failed to load - %s returned NULL", name, create);
97 return NULL;
98 }
99 DBG2("plugin '%s': loaded successfully", name);
100
101 return plugin;
102 }
103 #else
104 /**
105 * load a single plugin
106 */
107 static plugin_t* load_plugin(private_plugin_loader_t *this,
108 char *path, char *name)
109 {
110 char create[128];
111 char file[PATH_MAX];
112 void *handle;
113 plugin_t *plugin;
114 plugin_constructor_t constructor;
115
116 if (snprintf(file, sizeof(file), "%s/libstrongswan-%s.so", path,
117 name) >= sizeof(file) ||
118 snprintf(create, sizeof(create), "%s_plugin_create",
119 name) >= sizeof(create))
120 {
121 return NULL;
122 }
123 sanitize(create);
124 if (lib->integrity)
125 {
126 if (!lib->integrity->check_file(lib->integrity, name, file))
127 {
128 DBG1("plugin '%s': failed file integrity test of '%s'", name, file);
129 return NULL;
130 }
131 }
132 handle = dlopen(file, RTLD_LAZY);
133 if (handle == NULL)
134 {
135 DBG1("plugin '%s': failed to load '%s' - %s", name, file, dlerror());
136 return NULL;
137 }
138 constructor = dlsym(handle, create);
139 if (constructor == NULL)
140 {
141 DBG1("plugin '%s': failed to load - %s not found", name, create);
142 dlclose(handle);
143 return NULL;
144 }
145 if (lib->integrity)
146 {
147 if (!lib->integrity->check_segment(lib->integrity, name, constructor))
148 {
149 DBG1("plugin '%s': failed segment integrity test", name);
150 dlclose(handle);
151 return NULL;
152 }
153 DBG1("plugin '%s': passed file and segment integrity tests", name);
154 }
155 plugin = constructor();
156 if (plugin == NULL)
157 {
158 DBG1("plugin '%s': failed to load - %s returned NULL", name, create);
159 dlclose(handle);
160 return NULL;
161 }
162 DBG2("plugin '%s': loaded successfully", name);
163
164 /* we do not store or free dlopen() handles, leak_detective requires
165 * the modules to keep loaded until leak report */
166 return plugin;
167 }
168 #endif
169
170 /**
171 * Implementation of plugin_loader_t.load_plugins.
172 */
173 static bool load(private_plugin_loader_t *this, char *path, char *list)
174 {
175 enumerator_t *enumerator;
176 char *token;
177 bool critical_failed = FALSE;
178
179 #ifndef MONOLITHIC
180 if (path == NULL)
181 {
182 path = PLUGINDIR;
183 }
184 #endif
185
186 enumerator = enumerator_create_token(list, " ", " ");
187 while (!critical_failed && enumerator->enumerate(enumerator, &token))
188 {
189 plugin_t *plugin;
190 bool critical = FALSE;
191 int len;
192
193 token = strdup(token);
194 len = strlen(token);
195 if (token[len-1] == '!')
196 {
197 critical = TRUE;
198 token[len-1] = '\0';
199 }
200 plugin = load_plugin(this, path, token);
201 if (plugin)
202 {
203 /* insert in front to destroy them in reverse order */
204 this->plugins->insert_last(this->plugins, plugin);
205 this->names->insert_last(this->names, token);
206 }
207 else
208 {
209 if (critical)
210 {
211 critical_failed = TRUE;
212 DBG1("loading critical plugin '%s' failed", token);
213 }
214 free(token);
215 }
216 }
217 enumerator->destroy(enumerator);
218 return !critical_failed;
219 }
220
221 /**
222 * Implementation of plugin_loader_t.unload
223 */
224 static void unload(private_plugin_loader_t *this)
225 {
226 plugin_t *plugin;
227 char *name;
228
229 while (this->plugins->remove_first(this->plugins,
230 (void**)&plugin) == SUCCESS)
231 {
232 plugin->destroy(plugin);
233 }
234 while (this->names->remove_first(this->names, (void**)&name) == SUCCESS)
235 {
236 free(name);
237 }
238 }
239
240 /**
241 * Implementation of plugin_loader_t.create_plugin_enumerator
242 */
243 static enumerator_t* create_plugin_enumerator(private_plugin_loader_t *this)
244 {
245 return this->names->create_enumerator(this->names);
246 }
247
248 /**
249 * Implementation of plugin_loader_t.destroy
250 */
251 static void destroy(private_plugin_loader_t *this)
252 {
253 this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy));
254 this->names->destroy_function(this->names, free);
255 free(this);
256 }
257
258 /*
259 * see header file
260 */
261 plugin_loader_t *plugin_loader_create()
262 {
263 private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t);
264
265 this->public.load = (bool(*)(plugin_loader_t*, char *path, char *prefix))load;
266 this->public.unload = (void(*)(plugin_loader_t*))unload;
267 this->public.create_plugin_enumerator = (enumerator_t*(*)(plugin_loader_t*))create_plugin_enumerator;
268 this->public.destroy = (void(*)(plugin_loader_t*))destroy;
269
270 this->plugins = linked_list_create();
271 this->names = linked_list_create();
272
273 return &this->public;
274 }
275