Coverage Report

Created: 2026-06-30 06:14

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