Removed an unnecessary include of a header that is not available on Mac OS X.
[strongswan.git] / src / libstrongswan / plugins / plugin_loader.c
index 215ed53..47c244b 100644 (file)
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
- *
- * $Id$
  */
 
+#define _GNU_SOURCE
 #include "plugin_loader.h"
 
+#include <string.h>
 #include <dlfcn.h>
+#include <limits.h>
+#include <stdio.h>
 
 #include <debug.h>
+#include <integrity_checker.h>
 #include <utils/linked_list.h>
 #include <plugins/plugin.h>
 
@@ -39,76 +42,125 @@ struct private_plugin_loader_t {
         * list of loaded plugins
         */
        linked_list_t *plugins;
+       
+       /**
+        * names of loaded plugins
+        */
+       linked_list_t *names;
 };
 
 /**
- * Implementation of plugin_loader_t.load_plugins.
+ * load a single plugin
  */
-static int load(private_plugin_loader_t *this, char *path, char *prefix)
+static plugin_t* load_plugin(private_plugin_loader_t *this,
+                                                        char *path, char *name)
 {
-       enumerator_t *enumerator;
-       char *file, *ending, *rel;
+       char file[PATH_MAX];
        void *handle;
-       int count = 0;
+       plugin_t *plugin;
+       plugin_constructor_t constructor;
+       
+       snprintf(file, sizeof(file), "%s/libstrongswan-%s.so", path, name);
        
-       enumerator = enumerator_create_directory(path);
-       if (!enumerator)
+       if (lib->integrity &&
+               !lib->integrity->check_file(lib->integrity, name, file))
        {
-               DBG1("opening plugin directory %s failed", path);
-               return 0;
+               DBG1("file integrity test of plugin '%s' failed", name);
+               return NULL;
        }
-       DBG1("loading plugins from %s", path);
-       while (enumerator->enumerate(enumerator, &rel, &file, NULL))
+       handle = dlopen(file, RTLD_LAZY);
+       if (handle == NULL)
        {
-               plugin_t *plugin;
-               plugin_constructor_t constructor;
-               
-               ending = file + strlen(file) - 3;
-               if (ending <= file || !streq(ending, ".so"))
-               {       /* only process .so libraries */
-                       continue;
-               }
-               if (!strneq(prefix, rel, strlen(prefix)))
-               {
-                       continue;
-               }
-               handle = dlopen(file, RTLD_LAZY);
-               if (handle == NULL)
-               {
-                       DBG1("loading plugin %s failed: %s", rel, dlerror());
-                       continue;
-               }
-               constructor = dlsym(handle, "plugin_create");
-               if (constructor == NULL)
-               {
-                       DBG1("plugin %s has no plugin_create() function, skipped", rel);
-                       dlclose(handle);
-                       continue;
-               }
-               plugin = constructor();
-               if (plugin == NULL)
-               {
-                       DBG1("plugin %s constructor failed, skipping", rel);
-                       dlclose(handle);
-                       continue;
+               DBG1("loading plugin '%s' failed: %s", name, dlerror());
+               return NULL;
+       }
+       constructor = dlsym(handle, "plugin_create");
+       if (constructor == NULL)
+       {
+               DBG1("loading plugin '%s' failed: no plugin_create() function", name);
+               dlclose(handle);
+               return NULL;
+       }
+       if (lib->integrity &&
+               !lib->integrity->check_segment(lib->integrity, name, constructor))
+       {
+               DBG1("segment integrity test of plugin '%s' failed", name);
+               dlclose(handle);
+               return NULL;
+       }
+       plugin = constructor();
+       if (plugin == NULL)
+       {
+               DBG1("loading plugin '%s' failed: plugin_create() returned NULL", name);
+               dlclose(handle);
+               return NULL;
+       }
+       DBG2("plugin '%s' loaded successfully", name);
+       
+       /* we do not store or free dlopen() handles, leak_detective requires
+        * the modules to keep loaded until leak report */
+       return plugin;
+}
+
+/**
+ * Implementation of plugin_loader_t.load_plugins.
+ */
+static int load(private_plugin_loader_t *this, char *path, char *list)
+{
+       plugin_t *plugin;
+       enumerator_t *enumerator;
+       char *token;
+       int count = 0;
+       
+       enumerator = enumerator_create_token(list, " ", " ");
+       while (enumerator->enumerate(enumerator, &token))
+       {
+               plugin = load_plugin(this, path, token);
+               if (plugin)
+               {       /* insert in front to destroy them in reverse order */
+                       this->plugins->insert_last(this->plugins, plugin);
+                       this->names->insert_last(this->names, strdup(token));
+                       count++;
                }
-               DBG1("plugin %s loaded successfully", rel);
-               /* insert in front to destroy them in reverse order */
-               this->plugins->insert_last(this->plugins, plugin);
-               /* we do not store or free dlopen() handles, leak_detective requires
-                * the modules to keep loaded until leak report */
-               count++;
        }
        enumerator->destroy(enumerator);
        return count;
 }
 
 /**
+ * Implementation of plugin_loader_t.unload
+ */
+static void unload(private_plugin_loader_t *this)
+{
+       plugin_t *plugin;
+       char *name;
+       
+       while (this->plugins->remove_first(this->plugins,
+                                                                          (void**)&plugin) == SUCCESS)
+       {
+               plugin->destroy(plugin);
+       }
+       while (this->names->remove_first(this->names, (void**)&name) == SUCCESS)
+       {
+               free(name);
+       }
+}
+
+/**
+ * Implementation of plugin_loader_t.create_plugin_enumerator
+ */
+static enumerator_t* create_plugin_enumerator(private_plugin_loader_t *this)
+{
+       return this->names->create_enumerator(this->names);
+}       
+
+/**
  * Implementation of plugin_loader_t.destroy
  */
 static void destroy(private_plugin_loader_t *this)
 {
        this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy));
+       this->names->destroy_function(this->names, free);
        free(this);
 }
 
@@ -120,9 +172,12 @@ plugin_loader_t *plugin_loader_create()
        private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t);
        
        this->public.load = (int(*)(plugin_loader_t*, char *path, char *prefix))load;
+       this->public.unload = (void(*)(plugin_loader_t*))unload;
+       this->public.create_plugin_enumerator = (enumerator_t*(*)(plugin_loader_t*))create_plugin_enumerator;
        this->public.destroy = (void(*)(plugin_loader_t*))destroy;
        
        this->plugins = linked_list_create();
+       this->names = linked_list_create();
        
        return &this->public;
 }