plugin_loader.c 33 KB

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