Coverage Report

Created: 2024-02-29 06:05

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