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