aead: Support custom AEAD salt sizes
[strongswan.git] / src / libstrongswan / plugins / plugin_loader.c
1 /*
2 * Copyright (C) 2010-2014 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 <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <dlfcn.h>
25 #include <limits.h>
26 #include <stdio.h>
27
28 #include <utils/debug.h>
29 #include <library.h>
30 #include <collections/hashtable.h>
31 #include <collections/array.h>
32 #include <collections/linked_list.h>
33 #include <plugins/plugin.h>
34 #include <utils/integrity_checker.h>
35
36 typedef struct private_plugin_loader_t private_plugin_loader_t;
37 typedef struct registered_feature_t registered_feature_t;
38 typedef struct provided_feature_t provided_feature_t;
39 typedef struct plugin_entry_t plugin_entry_t;
40
41 /**
42 * private data of plugin_loader
43 */
44 struct private_plugin_loader_t {
45
46 /**
47 * public functions
48 */
49 plugin_loader_t public;
50
51 /**
52 * List of plugins, as plugin_entry_t
53 */
54 linked_list_t *plugins;
55
56 /**
57 * Hashtable for registered features, as registered_feature_t
58 */
59 hashtable_t *features;
60
61 /**
62 * Loaded features (stored in reverse order), as provided_feature_t
63 */
64 linked_list_t *loaded;
65
66 /**
67 * List of paths to search for plugins
68 */
69 linked_list_t *paths;
70
71 /**
72 * List of names of loaded plugins
73 */
74 char *loaded_plugins;
75
76 /**
77 * Statistics collected while loading features
78 */
79 struct {
80 /** Number of features that failed to load */
81 int failed;
82 /** Number of features that failed because of unmet dependencies */
83 int depends;
84 /** Number of features in critical plugins that failed to load */
85 int critical;
86 } stats;
87 };
88
89 /**
90 * Registered plugin feature
91 */
92 struct registered_feature_t {
93
94 /**
95 * The registered feature
96 */
97 plugin_feature_t *feature;
98
99 /**
100 * List of plugins providing this feature, as provided_feature_t
101 */
102 linked_list_t *plugins;
103 };
104
105 /**
106 * Hash a registered feature
107 */
108 static bool registered_feature_hash(registered_feature_t *this)
109 {
110 return plugin_feature_hash(this->feature);
111 }
112
113 /**
114 * Compare two registered features
115 */
116 static bool registered_feature_equals(registered_feature_t *a,
117 registered_feature_t *b)
118 {
119 return plugin_feature_equals(a->feature, b->feature);
120 }
121
122 /**
123 * Feature as provided by a plugin
124 */
125 struct provided_feature_t {
126
127 /**
128 * Plugin providing the feature
129 */
130 plugin_entry_t *entry;
131
132 /**
133 * FEATURE_REGISTER or FEATURE_CALLBACK entry
134 */
135 plugin_feature_t *reg;
136
137 /**
138 * The provided feature (followed by dependencies)
139 */
140 plugin_feature_t *feature;
141
142 /**
143 * Maximum number of dependencies (following feature)
144 */
145 int dependencies;
146
147 /**
148 * TRUE if currently loading this feature (to prevent loops)
149 */
150 bool loading;
151
152 /**
153 * TRUE if feature loaded
154 */
155 bool loaded;
156
157 /**
158 * TRUE if feature failed to load
159 */
160 bool failed;
161 };
162
163 /**
164 * Entry for a plugin
165 */
166 struct plugin_entry_t {
167
168 /**
169 * Plugin instance
170 */
171 plugin_t *plugin;
172
173 /**
174 * TRUE, if the plugin is marked as critical
175 */
176 bool critical;
177
178 /**
179 * dlopen handle, if in separate lib
180 */
181 void *handle;
182
183 /**
184 * List of features, as provided_feature_t
185 */
186 linked_list_t *features;
187 };
188
189 /**
190 * Destroy a plugin entry
191 */
192 static void plugin_entry_destroy(plugin_entry_t *entry)
193 {
194 DESTROY_IF(entry->plugin);
195 if (entry->handle)
196 {
197 dlclose(entry->handle);
198 }
199 entry->features->destroy(entry->features);
200 free(entry);
201 }
202
203 /**
204 * Wrapper for static plugin features
205 */
206 typedef struct {
207
208 /**
209 * Implements plugin_t interface
210 */
211 plugin_t public;
212
213 /**
214 * Name of the module registering these features
215 */
216 char *name;
217
218 /**
219 * Static plugin features
220 */
221 plugin_feature_t *features;
222
223 /**
224 * Number of plugin features
225 */
226 int count;
227
228 } static_features_t;
229
230 METHOD(plugin_t, get_static_name, char*,
231 static_features_t *this)
232 {
233 return this->name;
234 }
235
236 METHOD(plugin_t, get_static_features, int,
237 static_features_t *this, plugin_feature_t *features[])
238 {
239 *features = this->features;
240 return this->count;
241 }
242
243 METHOD(plugin_t, static_destroy, void,
244 static_features_t *this)
245 {
246 free(this->features);
247 free(this->name);
248 free(this);
249 }
250
251 /**
252 * Create a wrapper around static plugin features.
253 */
254 static plugin_t *static_features_create(const char *name,
255 plugin_feature_t features[], int count)
256 {
257 static_features_t *this;
258
259 INIT(this,
260 .public = {
261 .get_name = _get_static_name,
262 .get_features = _get_static_features,
263 .destroy = _static_destroy,
264 },
265 .name = strdup(name),
266 .features = calloc(count, sizeof(plugin_feature_t)),
267 .count = count,
268 );
269
270 memcpy(this->features, features, sizeof(plugin_feature_t) * count);
271
272 return &this->public;
273 }
274
275 /**
276 * create a plugin
277 * returns: NOT_FOUND, if the constructor was not found
278 * FAILED, if the plugin could not be constructed
279 */
280 static status_t create_plugin(private_plugin_loader_t *this, void *handle,
281 char *name, bool integrity, bool critical,
282 plugin_entry_t **entry)
283 {
284 char create[128];
285 plugin_t *plugin;
286 plugin_constructor_t constructor;
287
288 if (snprintf(create, sizeof(create), "%s_plugin_create",
289 name) >= sizeof(create))
290 {
291 return FAILED;
292 }
293 translate(create, "-", "_");
294 constructor = dlsym(handle, create);
295 if (constructor == NULL)
296 {
297 return NOT_FOUND;
298 }
299 if (integrity && lib->integrity)
300 {
301 if (!lib->integrity->check_segment(lib->integrity, name, constructor))
302 {
303 DBG1(DBG_LIB, "plugin '%s': failed segment integrity test", name);
304 return FAILED;
305 }
306 DBG1(DBG_LIB, "plugin '%s': passed file and segment integrity tests",
307 name);
308 }
309 plugin = constructor();
310 if (plugin == NULL)
311 {
312 DBG1(DBG_LIB, "plugin '%s': failed to load - %s returned NULL", name,
313 create);
314 return FAILED;
315 }
316 INIT(*entry,
317 .plugin = plugin,
318 .critical = critical,
319 .features = linked_list_create(),
320 );
321 DBG2(DBG_LIB, "plugin '%s': loaded successfully", name);
322 return SUCCESS;
323 }
324
325 /**
326 * load a single plugin
327 */
328 static plugin_entry_t *load_plugin(private_plugin_loader_t *this, char *name,
329 char *file, bool critical)
330 {
331 plugin_entry_t *entry;
332 void *handle;
333
334 switch (create_plugin(this, RTLD_DEFAULT, name, FALSE, critical, &entry))
335 {
336 case SUCCESS:
337 this->plugins->insert_last(this->plugins, entry);
338 return entry;
339 case NOT_FOUND:
340 if (file)
341 { /* try to load the plugin from a file */
342 break;
343 }
344 /* fall-through */
345 default:
346 return NULL;
347 }
348 if (lib->integrity)
349 {
350 if (!lib->integrity->check_file(lib->integrity, name, file))
351 {
352 DBG1(DBG_LIB, "plugin '%s': failed file integrity test of '%s'",
353 name, file);
354 return NULL;
355 }
356 }
357 handle = dlopen(file, RTLD_LAZY);
358 if (handle == NULL)
359 {
360 DBG1(DBG_LIB, "plugin '%s' failed to load: %s", name, dlerror());
361 return NULL;
362 }
363 if (create_plugin(this, handle, name, TRUE, critical, &entry) != SUCCESS)
364 {
365 dlclose(handle);
366 return NULL;
367 }
368 entry->handle = handle;
369 this->plugins->insert_last(this->plugins, entry);
370 return entry;
371 }
372
373 /**
374 * Convert enumerated provided_feature_t to plugin_feature_t
375 */
376 static bool feature_filter(void *null, provided_feature_t **provided,
377 plugin_feature_t **feature)
378 {
379 *feature = (*provided)->feature;
380 return (*provided)->loaded;
381 }
382
383 /**
384 * Convert enumerated entries to plugin_t
385 */
386 static bool plugin_filter(void *null, plugin_entry_t **entry, plugin_t **plugin,
387 void *in, linked_list_t **list)
388 {
389 plugin_entry_t *this = *entry;
390
391 *plugin = this->plugin;
392 if (list)
393 {
394 enumerator_t *features;
395 features = enumerator_create_filter(
396 this->features->create_enumerator(this->features),
397 (void*)feature_filter, NULL, NULL);
398 *list = linked_list_create_from_enumerator(features);
399 }
400 return TRUE;
401 }
402
403 METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
404 private_plugin_loader_t *this)
405 {
406 return enumerator_create_filter(
407 this->plugins->create_enumerator(this->plugins),
408 (void*)plugin_filter, NULL, NULL);
409 }
410
411 METHOD(plugin_loader_t, has_feature, bool,
412 private_plugin_loader_t *this, plugin_feature_t feature)
413 {
414 enumerator_t *plugins, *features;
415 plugin_t *plugin;
416 linked_list_t *list;
417 plugin_feature_t *current;
418 bool found = FALSE;
419
420 plugins = create_plugin_enumerator(this);
421 while (plugins->enumerate(plugins, &plugin, &list))
422 {
423 features = list->create_enumerator(list);
424 while (features->enumerate(features, &current))
425 {
426 if (plugin_feature_matches(&feature, current))
427 {
428 found = TRUE;
429 break;
430 }
431 }
432 features->destroy(features);
433 list->destroy(list);
434 }
435 plugins->destroy(plugins);
436
437 return found;
438 }
439
440 /**
441 * Create a list of the names of all loaded plugins
442 */
443 static char* loaded_plugins_list(private_plugin_loader_t *this)
444 {
445 int buf_len = 128, len = 0;
446 char *buf, *name;
447 enumerator_t *enumerator;
448 plugin_t *plugin;
449
450 buf = malloc(buf_len);
451 buf[0] = '\0';
452 enumerator = create_plugin_enumerator(this);
453 while (enumerator->enumerate(enumerator, &plugin, NULL))
454 {
455 name = plugin->get_name(plugin);
456 if (len + (strlen(name) + 1) >= buf_len)
457 {
458 buf_len <<= 1;
459 buf = realloc(buf, buf_len);
460 }
461 len += snprintf(&buf[len], buf_len - len, "%s ", name);
462 }
463 enumerator->destroy(enumerator);
464 if (len > 0 && buf[len - 1] == ' ')
465 {
466 buf[len - 1] = '\0';
467 }
468 return buf;
469 }
470
471 /**
472 * Check if a plugin is already loaded
473 */
474 static bool plugin_loaded(private_plugin_loader_t *this, char *name)
475 {
476 enumerator_t *enumerator;
477 bool found = FALSE;
478 plugin_t *plugin;
479
480 enumerator = create_plugin_enumerator(this);
481 while (enumerator->enumerate(enumerator, &plugin, NULL))
482 {
483 if (streq(plugin->get_name(plugin), name))
484 {
485 found = TRUE;
486 break;
487 }
488 }
489 enumerator->destroy(enumerator);
490 return found;
491 }
492
493 /**
494 * Forward declaration
495 */
496 static void load_provided(private_plugin_loader_t *this,
497 provided_feature_t *provided,
498 int level);
499
500 /**
501 * Used to find a loaded feature
502 */
503 static bool is_feature_loaded(provided_feature_t *item)
504 {
505 return item->loaded;
506 }
507
508 /**
509 * Used to find a loadable feature
510 */
511 static bool is_feature_loadable(provided_feature_t *item)
512 {
513 return !item->loading && !item->loaded && !item->failed;
514 }
515
516 /**
517 * Find a loaded and matching feature
518 */
519 static bool loaded_feature_matches(registered_feature_t *a,
520 registered_feature_t *b)
521 {
522 if (plugin_feature_matches(a->feature, b->feature))
523 {
524 return b->plugins->find_first(b->plugins, (void*)is_feature_loaded,
525 NULL) == SUCCESS;
526 }
527 return FALSE;
528 }
529
530 /**
531 * Find a loadable module that equals the requested feature
532 */
533 static bool loadable_feature_equals(registered_feature_t *a,
534 registered_feature_t *b)
535 {
536 if (plugin_feature_equals(a->feature, b->feature))
537 {
538 return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
539 NULL) == SUCCESS;
540 }
541 return FALSE;
542 }
543
544 /**
545 * Find a loadable module that matches the requested feature
546 */
547 static bool loadable_feature_matches(registered_feature_t *a,
548 registered_feature_t *b)
549 {
550 if (plugin_feature_matches(a->feature, b->feature))
551 {
552 return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
553 NULL) == SUCCESS;
554 }
555 return FALSE;
556 }
557
558 /**
559 * Returns a compatible plugin feature for the given depencency
560 */
561 static bool find_compatible_feature(private_plugin_loader_t *this,
562 plugin_feature_t *dependency)
563 {
564 registered_feature_t *feature, lookup = {
565 .feature = dependency,
566 };
567
568 feature = this->features->get_match(this->features, &lookup,
569 (void*)loaded_feature_matches);
570 return feature != NULL;
571 }
572
573 /**
574 * Load a registered plugin feature
575 */
576 static void load_registered(private_plugin_loader_t *this,
577 registered_feature_t *registered,
578 int level)
579 {
580 enumerator_t *enumerator;
581 provided_feature_t *provided;
582
583 enumerator = registered->plugins->create_enumerator(registered->plugins);
584 while (enumerator->enumerate(enumerator, &provided))
585 {
586 load_provided(this, provided, level);
587 }
588 enumerator->destroy(enumerator);
589 }
590
591 /**
592 * Try to load dependencies of the given feature
593 */
594 static bool load_dependencies(private_plugin_loader_t *this,
595 provided_feature_t *provided,
596 int level)
597 {
598 registered_feature_t *registered, lookup;
599 int indent = level * 2;
600 int i;
601
602 /* first entry is provided feature, followed by dependencies */
603 for (i = 1; i < provided->dependencies; i++)
604 {
605 if (provided->feature[i].kind != FEATURE_DEPENDS &&
606 provided->feature[i].kind != FEATURE_SDEPEND)
607 { /* end of dependencies */
608 break;
609 }
610
611 /* we load the feature even if a compatible one is already loaded,
612 * otherwise e.g. a specific database implementation loaded before
613 * another might cause a plugin feature loaded in-between to fail */
614 lookup.feature = &provided->feature[i];
615 do
616 { /* prefer an exactly matching feature, could be omitted but
617 * results in a more predictable behavior */
618 registered = this->features->get_match(this->features,
619 &lookup,
620 (void*)loadable_feature_equals);
621 if (!registered)
622 { /* try fuzzy matching */
623 registered = this->features->get_match(this->features,
624 &lookup,
625 (void*)loadable_feature_matches);
626 }
627 if (registered)
628 {
629 load_registered(this, registered, level);
630 }
631 /* we could stop after finding one but for dependencies like
632 * DB_ANY it might be needed to load all matching features */
633 }
634 while (registered);
635
636 if (!find_compatible_feature(this, &provided->feature[i]))
637 {
638 char *name, *provide, *depend;
639 bool soft = provided->feature[i].kind == FEATURE_SDEPEND;
640
641 name = provided->entry->plugin->get_name(provided->entry->plugin);
642 provide = plugin_feature_get_string(&provided->feature[0]);
643 depend = plugin_feature_get_string(&provided->feature[i]);
644 if (soft)
645 {
646 DBG3(DBG_LIB, "%*sfeature %s in plugin '%s' has unmet soft "
647 "dependency: %s", indent, "", provide, name, depend);
648 }
649 else if (provided->entry->critical)
650 {
651 DBG1(DBG_LIB, "feature %s in critical plugin '%s' has unmet "
652 "dependency: %s", provide, name, depend);
653 }
654 else
655 {
656 DBG2(DBG_LIB, "feature %s in plugin '%s' has unmet dependency: "
657 "%s", provide, name, depend);
658 }
659 free(provide);
660 free(depend);
661 if (soft)
662 { /* it's ok if we can't resolve soft dependencies */
663 continue;
664 }
665 return FALSE;
666 }
667 }
668 return TRUE;
669 }
670
671 /**
672 * Load registered plugin features
673 */
674 static void load_feature(private_plugin_loader_t *this,
675 provided_feature_t *provided,
676 int level)
677 {
678 if (load_dependencies(this, provided, level))
679 {
680 char *name, *provide;
681
682 if (plugin_feature_load(provided->entry->plugin, provided->feature,
683 provided->reg))
684 {
685 provided->loaded = TRUE;
686 /* insert first so we can unload the features in reverse order */
687 this->loaded->insert_first(this->loaded, provided);
688 return;
689 }
690
691 name = provided->entry->plugin->get_name(provided->entry->plugin);
692 provide = plugin_feature_get_string(&provided->feature[0]);
693 if (provided->entry->critical)
694 {
695 DBG1(DBG_LIB, "feature %s in critical plugin '%s' failed to load",
696 provide, name);
697 }
698 else
699 {
700 DBG2(DBG_LIB, "feature %s in plugin '%s' failed to load",
701 provide, name);
702 }
703 free(provide);
704 }
705 else
706 { /* TODO: we could check the current level and set a different flag when
707 * being loaded as dependency. If there are loops there is a chance the
708 * feature can be loaded later when loading the feature directly. */
709 this->stats.depends++;
710 }
711 provided->failed = TRUE;
712 this->stats.critical += provided->entry->critical ? 1 : 0;
713 this->stats.failed++;
714 }
715
716 /**
717 * Load a provided feature
718 */
719 static void load_provided(private_plugin_loader_t *this,
720 provided_feature_t *provided,
721 int level)
722 {
723 char *name, *provide;
724 int indent = level * 2;
725
726 if (provided->loaded || provided->failed)
727 {
728 return;
729 }
730 name = provided->entry->plugin->get_name(provided->entry->plugin);
731 provide = plugin_feature_get_string(provided->feature);
732 if (provided->loading)
733 { /* prevent loop */
734 DBG3(DBG_LIB, "%*sloop detected while loading %s in plugin '%s'",
735 indent, "", provide, name);
736 free(provide);
737 return;
738 }
739 DBG3(DBG_LIB, "%*sloading feature %s in plugin '%s'",
740 indent, "", provide, name);
741 free(provide);
742
743 provided->loading = TRUE;
744 load_feature(this, provided, level + 1);
745 provided->loading = FALSE;
746 }
747
748 /**
749 * Load registered plugin features
750 */
751 static void load_features(private_plugin_loader_t *this)
752 {
753 enumerator_t *enumerator, *inner;
754 plugin_entry_t *plugin;
755 provided_feature_t *provided;
756
757 /* we do this in plugin order to allow implicit dependencies to be resolved
758 * by reordering plugins */
759 enumerator = this->plugins->create_enumerator(this->plugins);
760 while (enumerator->enumerate(enumerator, &plugin))
761 {
762 inner = plugin->features->create_enumerator(plugin->features);
763 while (inner->enumerate(inner, &provided))
764 {
765 load_provided(this, provided, 0);
766 }
767 inner->destroy(inner);
768 }
769 enumerator->destroy(enumerator);
770 }
771
772 /**
773 * Register plugin features provided by the given plugin
774 */
775 static void register_features(private_plugin_loader_t *this,
776 plugin_entry_t *entry)
777 {
778 plugin_feature_t *feature, *reg;
779 registered_feature_t *registered, lookup;
780 provided_feature_t *provided;
781 int count, i;
782
783 if (!entry->plugin->get_features)
784 { /* feature interface not supported */
785 DBG1(DBG_LIB, "plugin '%s' does not provide features, deprecated",
786 entry->plugin->get_name(entry->plugin));
787 return;
788 }
789 reg = NULL;
790 count = entry->plugin->get_features(entry->plugin, &feature);
791 for (i = 0; i < count; i++)
792 {
793 switch (feature->kind)
794 {
795 case FEATURE_PROVIDE:
796 lookup.feature = feature;
797 registered = this->features->get(this->features, &lookup);
798 if (!registered)
799 {
800 INIT(registered,
801 .feature = feature,
802 .plugins = linked_list_create(),
803 );
804 this->features->put(this->features, registered, registered);
805 }
806 INIT(provided,
807 .entry = entry,
808 .feature = feature,
809 .reg = reg,
810 .dependencies = count - i,
811 );
812 registered->plugins->insert_last(registered->plugins,
813 provided);
814 entry->features->insert_last(entry->features, provided);
815 break;
816 case FEATURE_REGISTER:
817 case FEATURE_CALLBACK:
818 reg = feature;
819 break;
820 default:
821 break;
822 }
823 feature++;
824 }
825 }
826
827 /**
828 * Unregister a plugin feature
829 */
830 static void unregister_feature(private_plugin_loader_t *this,
831 provided_feature_t *provided)
832 {
833 registered_feature_t *registered, lookup;
834
835 lookup.feature = provided->feature;
836 registered = this->features->get(this->features, &lookup);
837 if (registered)
838 {
839 registered->plugins->remove(registered->plugins, provided, NULL);
840 if (registered->plugins->get_count(registered->plugins) == 0)
841 {
842 this->features->remove(this->features, &lookup);
843 registered->plugins->destroy(registered->plugins);
844 free(registered);
845 }
846 else if (registered->feature == provided->feature)
847 { /* update feature in case the providing plugin gets unloaded */
848 provided_feature_t *first;
849
850 registered->plugins->get_first(registered->plugins, (void**)&first);
851 registered->feature = first->feature;
852 }
853 }
854 free(provided);
855 }
856
857 /**
858 * Unregister plugin features
859 */
860 static void unregister_features(private_plugin_loader_t *this,
861 plugin_entry_t *entry)
862 {
863 provided_feature_t *provided;
864 enumerator_t *enumerator;
865
866 enumerator = entry->features->create_enumerator(entry->features);
867 while (enumerator->enumerate(enumerator, &provided))
868 {
869 entry->features->remove_at(entry->features, enumerator);
870 unregister_feature(this, provided);
871 }
872 enumerator->destroy(enumerator);
873 }
874
875 /**
876 * Remove plugins we were not able to load any plugin features from.
877 */
878 static void purge_plugins(private_plugin_loader_t *this)
879 {
880 enumerator_t *enumerator;
881 plugin_entry_t *entry;
882
883 enumerator = this->plugins->create_enumerator(this->plugins);
884 while (enumerator->enumerate(enumerator, &entry))
885 {
886 if (!entry->plugin->get_features)
887 { /* feature interface not supported */
888 continue;
889 }
890 if (entry->features->find_first(entry->features,
891 (void*)is_feature_loaded, NULL) != SUCCESS)
892 {
893 DBG2(DBG_LIB, "unloading plugin '%s' without loaded features",
894 entry->plugin->get_name(entry->plugin));
895 this->plugins->remove_at(this->plugins, enumerator);
896 unregister_features(this, entry);
897 plugin_entry_destroy(entry);
898 }
899 }
900 enumerator->destroy(enumerator);
901 }
902
903 METHOD(plugin_loader_t, add_static_features, void,
904 private_plugin_loader_t *this, const char *name,
905 plugin_feature_t features[], int count, bool critical)
906 {
907 plugin_entry_t *entry;
908 plugin_t *plugin;
909
910 plugin = static_features_create(name, features, count);
911
912 INIT(entry,
913 .plugin = plugin,
914 .critical = critical,
915 .features = linked_list_create(),
916 );
917 this->plugins->insert_last(this->plugins, entry);
918 register_features(this, entry);
919 }
920
921 /**
922 * Tries to find the plugin with the given name in the given path.
923 */
924 static bool find_plugin(char *path, char *name, char *buf, char **file)
925 {
926 struct stat stb;
927
928 if (path && snprintf(buf, PATH_MAX, "%s/libstrongswan-%s.so",
929 path, name) < PATH_MAX)
930 {
931 if (stat(buf, &stb) == 0)
932 {
933 *file = buf;
934 return TRUE;
935 }
936 }
937 return FALSE;
938 }
939
940 /**
941 * Used to sort plugins by priority
942 */
943 typedef struct {
944 /* name of the plugin */
945 char *name;
946 /* the plugins priority */
947 int prio;
948 /* default priority */
949 int def;
950 } plugin_priority_t;
951
952 static void plugin_priority_free(const plugin_priority_t *this, int idx,
953 void *user)
954 {
955 free(this->name);
956 }
957
958 /**
959 * Sort plugins and their priority by name
960 */
961 static int plugin_priority_cmp_name(const plugin_priority_t *a,
962 const plugin_priority_t *b)
963 {
964 return strcmp(a->name, b->name);
965 }
966
967 /**
968 * Sort plugins by decreasing priority or default priority then by name
969 */
970 static int plugin_priority_cmp(const plugin_priority_t *a,
971 const plugin_priority_t *b, void *user)
972 {
973 int diff;
974
975 diff = b->prio - a->prio;
976 if (!diff)
977 { /* the same priority, use default order */
978 diff = b->def - a->def;
979 if (!diff)
980 { /* same default priority (i.e. both were not found in that list) */
981 return strcmp(a->name, b->name);
982 }
983 }
984 return diff;
985 }
986
987
988 /**
989 * Determine the list of plugins to load via load option in each plugin's
990 * config section.
991 */
992 static char *modular_pluginlist(char *list)
993 {
994 enumerator_t *enumerator;
995 array_t *given, *final;
996 plugin_priority_t item, *current, found;
997 char *plugin, *plugins = NULL;
998 int i = 0, max_prio;
999
1000 if (!lib->settings->get_bool(lib->settings, "%s.load_modular", FALSE,
1001 lib->ns))
1002 {
1003 return list;
1004 }
1005
1006 given = array_create(sizeof(plugin_priority_t), 0);
1007 final = array_create(sizeof(plugin_priority_t), 0);
1008
1009 enumerator = enumerator_create_token(list, " ", " ");
1010 while (enumerator->enumerate(enumerator, &plugin))
1011 {
1012 item.name = strdup(plugin);
1013 item.prio = i++;
1014 array_insert(given, ARRAY_TAIL, &item);
1015 }
1016 enumerator->destroy(enumerator);
1017 array_sort(given, (void*)plugin_priority_cmp_name, NULL);
1018 /* the maximum priority used for plugins not found in this list */
1019 max_prio = i + 1;
1020
1021 enumerator = lib->settings->create_section_enumerator(lib->settings,
1022 "%s.plugins", lib->ns);
1023 while (enumerator->enumerate(enumerator, &plugin))
1024 {
1025 item.prio = lib->settings->get_int(lib->settings,
1026 "%s.plugins.%s.load", 0, lib->ns, plugin);
1027 if (!item.prio)
1028 {
1029 if (!lib->settings->get_bool(lib->settings,
1030 "%s.plugins.%s.load", FALSE, lib->ns, plugin))
1031 {
1032 continue;
1033 }
1034 item.prio = 1;
1035 }
1036 item.name = plugin;
1037 item.def = max_prio;
1038 if (array_bsearch(given, &item, (void*)plugin_priority_cmp_name,
1039 &found) != -1)
1040 {
1041 item.def = max_prio - found.prio;
1042 }
1043 array_insert(final, ARRAY_TAIL, &item);
1044 }
1045 enumerator->destroy(enumerator);
1046 array_destroy_function(given, (void*)plugin_priority_free, NULL);
1047
1048 array_sort(final, (void*)plugin_priority_cmp, NULL);
1049
1050 plugins = strdup("");
1051 enumerator = array_create_enumerator(final);
1052 while (enumerator->enumerate(enumerator, &current))
1053 {
1054 char *prev = plugins;
1055 if (asprintf(&plugins, "%s %s", plugins ?: "", current->name) < 0)
1056 {
1057 plugins = prev;
1058 break;
1059 }
1060 free(prev);
1061 }
1062 enumerator->destroy(enumerator);
1063 array_destroy(final);
1064 return plugins;
1065 }
1066
1067 METHOD(plugin_loader_t, load_plugins, bool,
1068 private_plugin_loader_t *this, char *list)
1069 {
1070 enumerator_t *enumerator;
1071 char *default_path = NULL, *plugins, *token;
1072 bool critical_failed = FALSE;
1073
1074 #ifdef PLUGINDIR
1075 default_path = PLUGINDIR;
1076 #endif /* PLUGINDIR */
1077
1078 plugins = modular_pluginlist(list);
1079
1080 enumerator = enumerator_create_token(plugins, " ", " ");
1081 while (!critical_failed && enumerator->enumerate(enumerator, &token))
1082 {
1083 plugin_entry_t *entry;
1084 bool critical = FALSE;
1085 char buf[PATH_MAX], *file = NULL;
1086 int len;
1087
1088 token = strdup(token);
1089 len = strlen(token);
1090 if (token[len-1] == '!')
1091 {
1092 critical = TRUE;
1093 token[len-1] = '\0';
1094 }
1095 if (plugin_loaded(this, token))
1096 {
1097 free(token);
1098 continue;
1099 }
1100 if (this->paths)
1101 {
1102 this->paths->find_first(this->paths, (void*)find_plugin, NULL,
1103 token, buf, &file);
1104 }
1105 if (!file)
1106 {
1107 find_plugin(default_path, token, buf, &file);
1108 }
1109 entry = load_plugin(this, token, file, critical);
1110 if (entry)
1111 {
1112 register_features(this, entry);
1113 }
1114 else if (critical)
1115 {
1116 critical_failed = TRUE;
1117 DBG1(DBG_LIB, "loading critical plugin '%s' failed", token);
1118 }
1119 free(token);
1120 }
1121 enumerator->destroy(enumerator);
1122 if (!critical_failed)
1123 {
1124 load_features(this);
1125 if (this->stats.critical > 0)
1126 {
1127 critical_failed = TRUE;
1128 DBG1(DBG_LIB, "failed to load %d critical plugin feature%s",
1129 this->stats.critical, this->stats.critical == 1 ? "" : "s");
1130 }
1131 /* unload plugins that we were not able to load any features for */
1132 purge_plugins(this);
1133 }
1134 if (!critical_failed)
1135 {
1136 free(this->loaded_plugins);
1137 this->loaded_plugins = loaded_plugins_list(this);
1138 }
1139 if (plugins != list)
1140 {
1141 free(plugins);
1142 }
1143 return !critical_failed;
1144 }
1145
1146 /**
1147 * Unload plugin features, they are registered in reverse order
1148 */
1149 static void unload_features(private_plugin_loader_t *this)
1150 {
1151 enumerator_t *enumerator;
1152 provided_feature_t *provided;
1153 plugin_entry_t *entry;
1154
1155 enumerator = this->loaded->create_enumerator(this->loaded);
1156 while (enumerator->enumerate(enumerator, &provided))
1157 {
1158 entry = provided->entry;
1159 plugin_feature_unload(entry->plugin, provided->feature, provided->reg);
1160 this->loaded->remove_at(this->loaded, enumerator);
1161 entry->features->remove(entry->features, provided, NULL);
1162 unregister_feature(this, provided);
1163 }
1164 enumerator->destroy(enumerator);
1165 }
1166
1167 METHOD(plugin_loader_t, unload, void,
1168 private_plugin_loader_t *this)
1169 {
1170 plugin_entry_t *entry;
1171
1172 /* unload features followed by plugins, in reverse order */
1173 unload_features(this);
1174 while (this->plugins->remove_last(this->plugins, (void**)&entry) == SUCCESS)
1175 {
1176 if (lib->leak_detective)
1177 { /* keep handle to report leaks properly */
1178 entry->handle = NULL;
1179 }
1180 unregister_features(this, entry);
1181 plugin_entry_destroy(entry);
1182 }
1183 free(this->loaded_plugins);
1184 this->loaded_plugins = NULL;
1185 memset(&this->stats, 0, sizeof(this->stats));
1186 }
1187
1188 METHOD(plugin_loader_t, add_path, void,
1189 private_plugin_loader_t *this, char *path)
1190 {
1191 if (!this->paths)
1192 {
1193 this->paths = linked_list_create();
1194 }
1195 this->paths->insert_last(this->paths, strdupnull(path));
1196 }
1197
1198 /**
1199 * Reload a plugin by name, NULL for all
1200 */
1201 static u_int reload_by_name(private_plugin_loader_t *this, char *name)
1202 {
1203 u_int reloaded = 0;
1204 enumerator_t *enumerator;
1205 plugin_t *plugin;
1206
1207 enumerator = create_plugin_enumerator(this);
1208 while (enumerator->enumerate(enumerator, &plugin, NULL))
1209 {
1210 if (name == NULL || streq(name, plugin->get_name(plugin)))
1211 {
1212 if (plugin->reload && plugin->reload(plugin))
1213 {
1214 DBG2(DBG_LIB, "reloaded configuration of '%s' plugin",
1215 plugin->get_name(plugin));
1216 reloaded++;
1217 }
1218 }
1219 }
1220 enumerator->destroy(enumerator);
1221 return reloaded;
1222 }
1223
1224 METHOD(plugin_loader_t, reload, u_int,
1225 private_plugin_loader_t *this, char *list)
1226 {
1227 u_int reloaded = 0;
1228 enumerator_t *enumerator;
1229 char *name;
1230
1231 if (list == NULL)
1232 {
1233 return reload_by_name(this, NULL);
1234 }
1235 enumerator = enumerator_create_token(list, " ", "");
1236 while (enumerator->enumerate(enumerator, &name))
1237 {
1238 reloaded += reload_by_name(this, name);
1239 }
1240 enumerator->destroy(enumerator);
1241 return reloaded;
1242 }
1243
1244 METHOD(plugin_loader_t, loaded_plugins, char*,
1245 private_plugin_loader_t *this)
1246 {
1247 return this->loaded_plugins ?: "";
1248 }
1249
1250 METHOD(plugin_loader_t, status, void,
1251 private_plugin_loader_t *this, level_t level)
1252 {
1253 if (this->loaded_plugins)
1254 {
1255 dbg(DBG_LIB, level, "loaded plugins: %s", this->loaded_plugins);
1256
1257 if (this->stats.failed)
1258 {
1259 dbg(DBG_LIB, level, "unable to load %d plugin feature%s (%d due to "
1260 "unmet dependencies)", this->stats.failed,
1261 this->stats.failed == 1 ? "" : "s", this->stats.depends);
1262 }
1263 }
1264 }
1265
1266 METHOD(plugin_loader_t, destroy, void,
1267 private_plugin_loader_t *this)
1268 {
1269 unload(this);
1270 this->features->destroy(this->features);
1271 this->loaded->destroy(this->loaded);
1272 this->plugins->destroy(this->plugins);
1273 DESTROY_FUNCTION_IF(this->paths, free);
1274 free(this->loaded_plugins);
1275 free(this);
1276 }
1277
1278 /*
1279 * see header file
1280 */
1281 plugin_loader_t *plugin_loader_create()
1282 {
1283 private_plugin_loader_t *this;
1284
1285 INIT(this,
1286 .public = {
1287 .add_static_features = _add_static_features,
1288 .load = _load_plugins,
1289 .add_path = _add_path,
1290 .reload = _reload,
1291 .unload = _unload,
1292 .create_plugin_enumerator = _create_plugin_enumerator,
1293 .has_feature = _has_feature,
1294 .loaded_plugins = _loaded_plugins,
1295 .status = _status,
1296 .destroy = _destroy,
1297 },
1298 .plugins = linked_list_create(),
1299 .loaded = linked_list_create(),
1300 .features = hashtable_create(
1301 (hashtable_hash_t)registered_feature_hash,
1302 (hashtable_equals_t)registered_feature_equals, 64),
1303 );
1304
1305 return &this->public;
1306 }
1307
1308 /*
1309 * See header
1310 */
1311 void plugin_loader_add_plugindirs(char *basedir, char *plugins)
1312 {
1313 enumerator_t *enumerator;
1314 char *name, path[PATH_MAX], dir[64];
1315
1316 enumerator = enumerator_create_token(plugins, " ", "");
1317 while (enumerator->enumerate(enumerator, &name))
1318 {
1319 snprintf(dir, sizeof(dir), "%s", name);
1320 translate(dir, "-", "_");
1321 snprintf(path, sizeof(path), "%s/%s/.libs", basedir, dir);
1322 lib->plugins->add_path(lib->plugins, path);
1323 }
1324 enumerator->destroy(enumerator);
1325 }