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