abcb84440f98faa441105afa02cf068d81ce29b4
[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 #ifdef MONOLITHIC
54 /**
55 * load a single plugin in monolithic mode
56 */
57 static plugin_t* load_plugin(private_plugin_loader_t *this,
58 char *path, char *name)
59 {
60 char create[128];
61 plugin_t *plugin;
62 plugin_constructor_t constructor;
63
64 if (snprintf(create, sizeof(create), "%s_plugin_create",
65 name) >= sizeof(create))
66 {
67 return NULL;
68 }
69 translate(create, "-", "_");
70 constructor = dlsym(RTLD_DEFAULT, create);
71 if (constructor == NULL)
72 {
73 DBG1("plugin '%s': failed to load - %s not found", name, create);
74 return NULL;
75 }
76 plugin = constructor();
77 if (plugin == NULL)
78 {
79 DBG1("plugin '%s': failed to load - %s returned NULL", name, create);
80 return NULL;
81 }
82 DBG2("plugin '%s': loaded successfully", name);
83
84 return plugin;
85 }
86 #else
87 /**
88 * load a single plugin
89 */
90 static plugin_t* load_plugin(private_plugin_loader_t *this,
91 char *path, char *name)
92 {
93 char create[128];
94 char file[PATH_MAX];
95 void *handle;
96 plugin_t *plugin;
97 plugin_constructor_t constructor;
98
99 if (snprintf(file, sizeof(file), "%s/libstrongswan-%s.so", path,
100 name) >= sizeof(file) ||
101 snprintf(create, sizeof(create), "%s_plugin_create",
102 name) >= sizeof(create))
103 {
104 return NULL;
105 }
106 translate(create, "-", "_");
107 if (lib->integrity)
108 {
109 if (!lib->integrity->check_file(lib->integrity, name, file))
110 {
111 DBG1("plugin '%s': failed file integrity test of '%s'", name, file);
112 return NULL;
113 }
114 }
115 handle = dlopen(file, RTLD_LAZY);
116 if (handle == NULL)
117 {
118 DBG1("plugin '%s': failed to load '%s' - %s", name, file, dlerror());
119 return NULL;
120 }
121 constructor = dlsym(handle, create);
122 if (constructor == NULL)
123 {
124 DBG1("plugin '%s': failed to load - %s not found", name, create);
125 dlclose(handle);
126 return NULL;
127 }
128 if (lib->integrity)
129 {
130 if (!lib->integrity->check_segment(lib->integrity, name, constructor))
131 {
132 DBG1("plugin '%s': failed segment integrity test", name);
133 dlclose(handle);
134 return NULL;
135 }
136 DBG1("plugin '%s': passed file and segment integrity tests", name);
137 }
138 plugin = constructor();
139 if (plugin == NULL)
140 {
141 DBG1("plugin '%s': failed to load - %s returned NULL", name, create);
142 dlclose(handle);
143 return NULL;
144 }
145 DBG2("plugin '%s': loaded successfully", name);
146
147 /* we do not store or free dlopen() handles, leak_detective requires
148 * the modules to keep loaded until leak report */
149 return plugin;
150 }
151 #endif
152
153 /**
154 * Implementation of plugin_loader_t.load_plugins.
155 */
156 static bool load(private_plugin_loader_t *this, char *path, char *list)
157 {
158 enumerator_t *enumerator;
159 char *token;
160 bool critical_failed = FALSE;
161
162 #ifndef MONOLITHIC
163 if (path == NULL)
164 {
165 path = PLUGINDIR;
166 }
167 #endif
168
169 enumerator = enumerator_create_token(list, " ", " ");
170 while (!critical_failed && enumerator->enumerate(enumerator, &token))
171 {
172 plugin_t *plugin;
173 bool critical = FALSE;
174 int len;
175
176 token = strdup(token);
177 len = strlen(token);
178 if (token[len-1] == '!')
179 {
180 critical = TRUE;
181 token[len-1] = '\0';
182 }
183 plugin = load_plugin(this, path, token);
184 if (plugin)
185 {
186 /* insert in front to destroy them in reverse order */
187 this->plugins->insert_last(this->plugins, plugin);
188 this->names->insert_last(this->names, token);
189 }
190 else
191 {
192 if (critical)
193 {
194 critical_failed = TRUE;
195 DBG1("loading critical plugin '%s' failed", token);
196 }
197 free(token);
198 }
199 }
200 enumerator->destroy(enumerator);
201 return !critical_failed;
202 }
203
204 /**
205 * Implementation of plugin_loader_t.unload
206 */
207 static void unload(private_plugin_loader_t *this)
208 {
209 plugin_t *plugin;
210 char *name;
211
212 while (this->plugins->remove_first(this->plugins,
213 (void**)&plugin) == SUCCESS)
214 {
215 plugin->destroy(plugin);
216 }
217 while (this->names->remove_first(this->names, (void**)&name) == SUCCESS)
218 {
219 free(name);
220 }
221 }
222
223 /**
224 * Implementation of plugin_loader_t.create_plugin_enumerator
225 */
226 static enumerator_t* create_plugin_enumerator(private_plugin_loader_t *this)
227 {
228 return this->names->create_enumerator(this->names);
229 }
230
231 /**
232 * Implementation of plugin_loader_t.destroy
233 */
234 static void destroy(private_plugin_loader_t *this)
235 {
236 this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy));
237 this->names->destroy_function(this->names, free);
238 free(this);
239 }
240
241 /*
242 * see header file
243 */
244 plugin_loader_t *plugin_loader_create()
245 {
246 private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t);
247
248 this->public.load = (bool(*)(plugin_loader_t*, char *path, char *prefix))load;
249 this->public.unload = (void(*)(plugin_loader_t*))unload;
250 this->public.create_plugin_enumerator = (enumerator_t*(*)(plugin_loader_t*))create_plugin_enumerator;
251 this->public.destroy = (void(*)(plugin_loader_t*))destroy;
252
253 this->plugins = linked_list_create();
254 this->names = linked_list_create();
255
256 return &this->public;
257 }
258