2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include "plugin_loader.h"
27 #include <integrity_checker.h>
28 #include <utils/linked_list.h>
29 #include <plugins/plugin.h>
31 typedef struct private_plugin_loader_t private_plugin_loader_t
;
32 typedef struct plugin_entry_t plugin_entry_t
;
35 * private data of plugin_loader
37 struct private_plugin_loader_t
{
42 plugin_loader_t
public;
45 * List of plugins, as plugin_entry_t
47 linked_list_t
*plugins
;
53 struct plugin_entry_t
{
61 * dlopen handle, if in separate lib
66 * List of loaded features
68 linked_list_t
*loaded
;
72 * Destroy a plugin entry
74 static void plugin_entry_destroy(plugin_entry_t
*entry
)
76 DESTROY_IF(entry
->plugin
);
79 dlclose(entry
->handle
);
81 entry
->loaded
->destroy(entry
->loaded
);
87 * returns: NOT_FOUND, if the constructor was not found
88 * FAILED, if the plugin could not be constructed
90 static status_t
create_plugin(private_plugin_loader_t
*this, void *handle
,
91 char *name
, bool integrity
, plugin_entry_t
**entry
)
95 plugin_constructor_t constructor
;
97 if (snprintf(create
, sizeof(create
), "%s_plugin_create",
98 name
) >= sizeof(create
))
102 translate(create
, "-", "_");
103 constructor
= dlsym(handle
, create
);
104 if (constructor
== NULL
)
108 if (integrity
&& lib
->integrity
)
110 if (!lib
->integrity
->check_segment(lib
->integrity
, name
, constructor
))
112 DBG1(DBG_LIB
, "plugin '%s': failed segment integrity test", name
);
115 DBG1(DBG_LIB
, "plugin '%s': passed file and segment integrity tests",
118 plugin
= constructor();
121 DBG1(DBG_LIB
, "plugin '%s': failed to load - %s returned NULL", name
,
127 .loaded
= linked_list_create(),
129 DBG2(DBG_LIB
, "plugin '%s': loaded successfully", name
);
134 * load a single plugin
136 static bool load_plugin(private_plugin_loader_t
*this, char *name
, char *file
)
138 plugin_entry_t
*entry
;
141 switch (create_plugin(this, RTLD_DEFAULT
, name
, FALSE
, &entry
))
144 this->plugins
->insert_last(this->plugins
, entry
);
147 /* try to load the plugin from a file */
154 if (!lib
->integrity
->check_file(lib
->integrity
, name
, file
))
156 DBG1(DBG_LIB
, "plugin '%s': failed file integrity test of '%s'",
161 handle
= dlopen(file
, RTLD_LAZY
);
164 DBG1(DBG_LIB
, "plugin '%s' failed to load: %s", name
, dlerror());
167 if (create_plugin(this, handle
, name
, TRUE
, &entry
) != SUCCESS
)
172 entry
->handle
= handle
;
173 this->plugins
->insert_last(this->plugins
, entry
);
178 * Convert enumerated entries to plugin_t
180 static bool plugin_filter(void *null
, plugin_entry_t
**entry
, plugin_t
**plugin
,
181 void *in
, linked_list_t
**list
)
183 *plugin
= (*entry
)->plugin
;
186 *list
= (*entry
)->loaded
;
191 METHOD(plugin_loader_t
, create_plugin_enumerator
, enumerator_t
*,
192 private_plugin_loader_t
*this)
194 return enumerator_create_filter(
195 this->plugins
->create_enumerator(this->plugins
),
196 (void*)plugin_filter
, NULL
, NULL
);
200 * Check if a plugin is already loaded
202 static bool plugin_loaded(private_plugin_loader_t
*this, char *name
)
204 enumerator_t
*enumerator
;
208 enumerator
= create_plugin_enumerator(this);
209 while (enumerator
->enumerate(enumerator
, &plugin
, NULL
))
211 if (streq(plugin
->get_name(plugin
), name
))
217 enumerator
->destroy(enumerator
);
222 * Check if a feature of a plugin is already loaded
224 static bool feature_loaded(private_plugin_loader_t
*this, plugin_entry_t
*entry
,
225 plugin_feature_t
*feature
)
227 return entry
->loaded
->find_first(entry
->loaded
, NULL
,
228 (void**)&feature
) == SUCCESS
;
232 * Check if dependencies are satisfied
234 static bool dependencies_satisfied(private_plugin_loader_t
*this, char *name
,
235 bool soft
, bool report
, plugin_feature_t
*features
, int count
)
239 /* first entry is provided feature, followed by dependencies */
240 for (i
= 1; i
< count
; i
++)
242 enumerator_t
*entries
, *loaded
;
243 plugin_feature_t
*feature
;
244 plugin_entry_t
*entry
;
247 if (features
[i
].kind
!= FEATURE_DEPENDS
&&
248 features
[i
].kind
!= FEATURE_SDEPEND
)
249 { /* end of dependencies */
252 entries
= this->plugins
->create_enumerator(this->plugins
);
253 while (entries
->enumerate(entries
, &entry
))
255 loaded
= entry
->loaded
->create_enumerator(entry
->loaded
);
256 while (loaded
->enumerate(loaded
, &feature
))
258 if (plugin_feature_matches(&features
[i
], feature
))
264 loaded
->destroy(loaded
);
266 entries
->destroy(entries
);
268 if (!found
&& (features
[i
].kind
!= FEATURE_SDEPEND
|| soft
))
272 char *provide
, *depend
;
274 provide
= plugin_feature_get_string(&features
[0]);
275 depend
= plugin_feature_get_string(&features
[i
]);
276 DBG1(DBG_LIB
, "feature %s in '%s' plugin has unsatisfied "
277 "dependency: %s", provide
, name
, depend
);
288 * Load a plugin feature
290 static bool load_feature(private_plugin_loader_t
*this, plugin_entry_t
*entry
,
291 char *name
, plugin_feature_t
*feature
, plugin_feature_t
*reg
)
295 str
= plugin_feature_get_string(feature
);
296 switch (feature
->type
)
298 case FEATURE_CRYPTER
:
305 case FEATURE_PRIVKEY
:
306 case FEATURE_PRIVKEY_GEN
:
308 case FEATURE_CERT_DECODE
:
309 case FEATURE_CERT_ENCODE
:
310 case FEATURE_DATABASE
:
311 case FEATURE_FETCHER
:
312 /* require a registration function */
314 (reg
->kind
== FEATURE_REGISTER
&& reg
->type
!= feature
->type
))
316 DBG1(DBG_LIB
, "loading '%s' plugin feature %s failed: "
317 "invalid registration function", name
, str
);
325 if (reg
&& reg
->kind
== FEATURE_CALLBACK
)
327 if (!reg
->arg
.cb
.f(entry
->plugin
, feature
, TRUE
, reg
->arg
.cb
.data
))
329 DBG1(DBG_LIB
, "loading '%s' plugin feature %s with callback failed",
337 switch (feature
->type
)
339 case FEATURE_CRYPTER
:
340 lib
->crypto
->add_crypter(lib
->crypto
, feature
->arg
.crypter
.alg
,
341 name
, reg
->arg
.reg
.f
);
344 lib
->crypto
->add_aead(lib
->crypto
, feature
->arg
.aead
.alg
,
345 name
, reg
->arg
.reg
.f
);
348 lib
->crypto
->add_signer(lib
->crypto
, feature
->arg
.signer
,
349 name
, reg
->arg
.reg
.f
);
352 lib
->crypto
->add_hasher(lib
->crypto
, feature
->arg
.hasher
,
353 name
, reg
->arg
.reg
.f
);
356 lib
->crypto
->add_prf(lib
->crypto
, feature
->arg
.prf
,
357 name
, reg
->arg
.reg
.f
);
360 lib
->crypto
->add_dh(lib
->crypto
, feature
->arg
.dh_group
,
361 name
, reg
->arg
.reg
.f
);
364 lib
->crypto
->add_rng(lib
->crypto
, feature
->arg
.rng_quality
,
365 name
, reg
->arg
.reg
.f
);
367 case FEATURE_PRIVKEY
:
368 case FEATURE_PRIVKEY_GEN
:
369 lib
->creds
->add_builder(lib
->creds
, CRED_PRIVATE_KEY
,
370 feature
->arg
.privkey
, reg
->arg
.reg
.final
,
374 lib
->creds
->add_builder(lib
->creds
, CRED_PUBLIC_KEY
,
375 feature
->arg
.pubkey
, reg
->arg
.reg
.final
,
378 case FEATURE_CERT_DECODE
:
379 case FEATURE_CERT_ENCODE
:
380 lib
->creds
->add_builder(lib
->creds
, CRED_CERTIFICATE
,
381 feature
->arg
.cert
, reg
->arg
.reg
.final
,
384 case FEATURE_DATABASE
:
385 lib
->db
->add_database(lib
->db
, reg
->arg
.reg
.f
);
387 case FEATURE_FETCHER
:
388 lib
->fetcher
->add_fetcher(lib
->fetcher
, reg
->arg
.reg
.f
,
389 feature
->arg
.fetcher
);
395 DBG2(DBG_LIB
, "loaded '%s' plugin feature %s", name
, str
);
397 entry
->loaded
->insert_last(entry
->loaded
, feature
);
402 * Load plugin features in correct order
404 static int load_features(private_plugin_loader_t
*this, bool soft
, bool report
)
406 enumerator_t
*enumerator
;
407 plugin_feature_t
*features
, *reg
= NULL
;
408 plugin_entry_t
*entry
;
409 int count
, i
, loaded
= 0;
412 enumerator
= this->plugins
->create_enumerator(this->plugins
);
413 while (enumerator
->enumerate(enumerator
, &entry
))
415 if (!entry
->plugin
->get_features
)
416 { /* feature interface not supported */
419 name
= entry
->plugin
->get_name(entry
->plugin
);
420 count
= entry
->plugin
->get_features(entry
->plugin
, &features
);
421 for (i
= 0; i
< count
; i
++)
423 switch (features
[i
].kind
)
425 case FEATURE_PROVIDE
:
426 if (!feature_loaded(this, entry
, &features
[i
]) &&
427 dependencies_satisfied(this, name
, soft
, report
,
428 &features
[i
], count
- i
) &&
429 load_feature(this, entry
, name
, &features
[i
], reg
))
434 case FEATURE_REGISTER
:
435 case FEATURE_CALLBACK
:
443 enumerator
->destroy(enumerator
);
448 * Remove plugins that we were not able to load any features from.
450 static void purge_plugins(private_plugin_loader_t
*this)
452 enumerator_t
*enumerator
;
453 plugin_entry_t
*entry
;
455 enumerator
= this->plugins
->create_enumerator(this->plugins
);
456 while (enumerator
->enumerate(enumerator
, &entry
))
458 if (!entry
->plugin
->get_features
)
459 { /* feature interface not supported */
462 if (!entry
->loaded
->get_count(entry
->loaded
))
464 this->plugins
->remove_at(this->plugins
, enumerator
);
465 plugin_entry_destroy(entry
);
468 enumerator
->destroy(enumerator
);
471 METHOD(plugin_loader_t
, load_plugins
, bool,
472 private_plugin_loader_t
*this, char *path
, char *list
)
474 enumerator_t
*enumerator
;
476 bool critical_failed
= FALSE
;
483 enumerator
= enumerator_create_token(list
, " ", " ");
484 while (!critical_failed
&& enumerator
->enumerate(enumerator
, &token
))
486 bool critical
= FALSE
;
490 token
= strdup(token
);
492 if (token
[len
-1] == '!')
497 if (plugin_loaded(this, token
))
502 if (snprintf(file
, sizeof(file
), "%s/libstrongswan-%s.so",
503 path
, token
) >= sizeof(file
))
507 if (!load_plugin(this, token
, file
) && critical
)
509 critical_failed
= TRUE
;
510 DBG1(DBG_LIB
, "loading critical plugin '%s' failed", token
);
514 enumerator
->destroy(enumerator
);
515 if (!critical_failed
)
517 while (load_features(this, TRUE
, FALSE
))
519 /* try load new features until we don't get new ones */
521 while (load_features(this, FALSE
, FALSE
))
523 /* second round, ignoring soft dependencies */
525 /* report missing dependencies */
526 load_features(this, FALSE
, TRUE
);
527 /* unload plugins that we were not able to load any features for */
530 return !critical_failed
;
533 METHOD(plugin_loader_t
, unload
, void,
534 private_plugin_loader_t
*this)
536 plugin_entry_t
*entry
;
538 /* unload plugins in reverse order */
539 while (this->plugins
->remove_last(this->plugins
,
540 (void**)&entry
) == SUCCESS
)
542 if (lib
->leak_detective
)
543 { /* keep handle to report leaks properly */
544 entry
->handle
= NULL
;
546 plugin_entry_destroy(entry
);
551 * Reload a plugin by name, NULL for all
553 static u_int
reload_by_name(private_plugin_loader_t
*this, char *name
)
556 enumerator_t
*enumerator
;
559 enumerator
= create_plugin_enumerator(this);
560 while (enumerator
->enumerate(enumerator
, &plugin
, NULL
))
562 if (name
== NULL
|| streq(name
, plugin
->get_name(plugin
)))
564 if (plugin
->reload
&& plugin
->reload(plugin
))
566 DBG2(DBG_LIB
, "reloaded configuration of '%s' plugin",
567 plugin
->get_name(plugin
));
572 enumerator
->destroy(enumerator
);
576 METHOD(plugin_loader_t
, reload
, u_int
,
577 private_plugin_loader_t
*this, char *list
)
580 enumerator_t
*enumerator
;
585 return reload_by_name(this, NULL
);
587 enumerator
= enumerator_create_token(list
, " ", "");
588 while (enumerator
->enumerate(enumerator
, &name
))
590 reloaded
+= reload_by_name(this, name
);
592 enumerator
->destroy(enumerator
);
596 METHOD(plugin_loader_t
, destroy
, void,
597 private_plugin_loader_t
*this)
600 this->plugins
->destroy(this->plugins
);
607 plugin_loader_t
*plugin_loader_create()
609 private_plugin_loader_t
*this;
613 .load
= _load_plugins
,
616 .create_plugin_enumerator
= _create_plugin_enumerator
,
619 .plugins
= linked_list_create(),
622 return &this->public;