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
5.07M
{
126
5.07M
  return plugin_feature_hash(this->feature);
127
5.07M
}
128
129
/**
130
 * Compare two registered features
131
 */
132
static bool registered_feature_equals(registered_feature_t *a,
133
                    registered_feature_t *b)
134
1.47M
{
135
1.47M
  return plugin_feature_equals(a->feature, b->feature);
136
1.47M
}
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
50.3k
{
210
50.3k
  DESTROY_IF(entry->plugin);
211
50.3k
  if (entry->handle)
212
0
  {
213
0
    dlclose(entry->handle);
214
0
  }
215
50.3k
  entry->features->destroy(entry->features);
216
50.3k
  free(entry);
217
50.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
50.3k
{
364
50.3k
  plugin_t *plugin;
365
50.3k
  plugin_constructor_t constructor = NULL;
366
367
50.3k
#ifdef STATIC_PLUGIN_CONSTRUCTORS
368
50.3k
  if (plugin_constructors)
369
50.3k
  {
370
50.3k
    constructor = plugin_constructors->get(plugin_constructors, name);
371
50.3k
  }
372
50.3k
  if (!constructor)
373
0
#endif
374
0
  {
375
0
    constructor = dlsym(handle, create);
376
0
  }
377
50.3k
  if (!constructor)
378
0
  {
379
0
    return NOT_FOUND;
380
0
  }
381
50.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
50.3k
  plugin = constructor();
392
50.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
50.3k
  INIT(*entry,
399
50.3k
    .plugin = plugin,
400
50.3k
    .critical = critical,
401
50.3k
    .features = linked_list_create(),
402
50.3k
  );
403
50.3k
  DBG2(DBG_LIB, "plugin '%s': loaded successfully", name);
404
50.3k
  return SUCCESS;
405
50.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
50.3k
{
413
50.3k
  char create[128];
414
50.3k
  plugin_entry_t *entry;
415
50.3k
  void *handle;
416
50.3k
  int flag = RTLD_LAZY;
417
418
50.3k
  if (snprintf(create, sizeof(create), "%s_plugin_create",
419
50.3k
         name) >= sizeof(create))
420
0
  {
421
0
    return NULL;
422
0
  }
423
50.3k
  translate(create, "-", "_");
424
50.3k
  switch (create_plugin(this, RTLD_DEFAULT, name, create, FALSE, critical,
425
50.3k
              &entry))
426
50.3k
  {
427
50.3k
    case SUCCESS:
428
50.3k
      this->plugins->insert_last(this->plugins, entry);
429
50.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
50.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
235k
{
507
235k
  plugin_entry_t *entry;
508
235k
  linked_list_t **list;
509
235k
  plugin_t **plugin;
510
511
235k
  VA_ARGS_VGET(args, plugin, list);
512
513
235k
  if (orig->enumerate(orig, &entry))
514
176k
  {
515
176k
    *plugin = entry->plugin;
516
176k
    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
176k
    return TRUE;
525
176k
  }
526
58.7k
  return FALSE;
527
235k
}
528
529
METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
530
  private_plugin_loader_t *this)
531
58.7k
{
532
58.7k
  return enumerator_create_filter(
533
58.7k
              this->plugins->create_enumerator(this->plugins),
534
58.7k
              plugin_filter, NULL, NULL);
535
58.7k
}
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
8.39k
{
571
8.39k
  int buf_len = 128, len = 0;
572
8.39k
  char *buf, *name;
573
8.39k
  enumerator_t *enumerator;
574
8.39k
  plugin_t *plugin;
575
576
8.39k
  buf = malloc(buf_len);
577
8.39k
  buf[0] = '\0';
578
8.39k
  enumerator = create_plugin_enumerator(this);
579
58.7k
  while (enumerator->enumerate(enumerator, &plugin, NULL))
580
50.3k
  {
581
50.3k
    name = plugin->get_name(plugin);
582
50.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
50.3k
    len += snprintf(&buf[len], buf_len - len, "%s ", name);
588
50.3k
  }
589
8.39k
  enumerator->destroy(enumerator);
590
8.39k
  if (len > 0 && buf[len - 1] == ' ')
591
8.39k
  {
592
8.39k
    buf[len - 1] = '\0';
593
8.39k
  }
594
8.39k
  return buf;
595
8.39k
}
596
597
/**
598
 * Check if a plugin is already loaded
599
 */
600
static bool plugin_loaded(private_plugin_loader_t *this, char *name)
601
50.3k
{
602
50.3k
  enumerator_t *enumerator;
603
50.3k
  bool found = FALSE;
604
50.3k
  plugin_t *plugin;
605
606
50.3k
  enumerator = create_plugin_enumerator(this);
607
176k
  while (enumerator->enumerate(enumerator, &plugin, NULL))
608
125k
  {
609
125k
    if (streq(plugin->get_name(plugin), name))
610
0
    {
611
0
      found = TRUE;
612
0
      break;
613
0
    }
614
125k
  }
615
50.3k
  enumerator->destroy(enumerator);
616
50.3k
  return found;
617
50.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
604k
{
629
604k
  return item->loaded;
630
604k
}
631
632
CALLBACK(is_feature_loadable, bool,
633
  provided_feature_t *item, va_list args)
634
1.36M
{
635
1.36M
  return !item->loading && !item->loaded && !item->failed;
636
1.36M
}
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
453k
{
644
453k
  if (plugin_feature_matches(a->feature, b->feature))
645
453k
  {
646
453k
    return b->plugins->find_first(b->plugins, is_feature_loaded, NULL);
647
453k
  }
648
0
  return FALSE;
649
453k
}
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
562k
{
657
562k
  if (plugin_feature_equals(a->feature, b->feature))
658
562k
  {
659
562k
    return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
660
562k
  }
661
0
  return FALSE;
662
562k
}
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
453k
{
670
453k
  if (plugin_feature_matches(a->feature, b->feature))
671
453k
  {
672
453k
    return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
673
453k
  }
674
0
  return FALSE;
675
453k
}
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
738k
{
683
738k
  registered_feature_t *feature, lookup = {
684
738k
    .feature = dependency,
685
738k
  };
686
687
738k
  feature = this->features->get_match(this->features, &lookup,
688
738k
                     (void*)loaded_feature_matches);
689
738k
  return feature != NULL;
690
738k
}
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
109k
{
699
109k
  enumerator_t *enumerator;
700
109k
  provided_feature_t *provided;
701
702
109k
  enumerator = registered->plugins->create_enumerator(registered->plugins);
703
302k
  while (enumerator->enumerate(enumerator, &provided))
704
193k
  {
705
193k
    load_provided(this, provided, level);
706
193k
  }
707
109k
  enumerator->destroy(enumerator);
708
109k
}
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
738k
{
717
738k
  registered_feature_t *registered, lookup;
718
738k
  int i;
719
720
  /* first entry is provided feature, followed by dependencies */
721
1.15M
  for (i = 1; i < provided->dependencies; i++)
722
1.11M
  {
723
1.11M
    if (provided->feature[i].kind != FEATURE_DEPENDS &&
724
1.11M
      provided->feature[i].kind != FEATURE_SDEPEND)
725
377k
    { /* end of dependencies */
726
377k
      break;
727
377k
    }
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
738k
    lookup.feature = &provided->feature[i];
733
738k
    do
734
848k
    { /* prefer an exactly matching feature, could be omitted but
735
       * results in a more predictable behavior */
736
848k
      registered = this->features->get_match(this->features,
737
848k
                     &lookup,
738
848k
                     (void*)loadable_feature_equals);
739
848k
      if (!registered)
740
738k
      { /* try fuzzy matching */
741
738k
        registered = this->features->get_match(this->features,
742
738k
                     &lookup,
743
738k
                     (void*)loadable_feature_matches);
744
738k
      }
745
848k
      if (registered)
746
109k
      {
747
109k
        load_registered(this, registered, level);
748
109k
      }
749
      /* we could stop after finding one but for dependencies like
750
       * DB_ANY it might be needed to load all matching features */
751
848k
    }
752
848k
    while (registered);
753
754
738k
    if (!find_compatible_feature(this, &provided->feature[i]))
755
461k
    {
756
461k
      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
461k
      if (soft)
786
134k
      { /* it's ok if we can't resolve soft dependencies */
787
134k
        continue;
788
134k
      }
789
327k
      return FALSE;
790
461k
    }
791
738k
  }
792
411k
  return TRUE;
793
738k
}
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
738k
{
802
738k
  if (load_dependencies(this, provided, level))
803
411k
  {
804
411k
    if (plugin_feature_load(provided->entry->plugin, provided->feature,
805
411k
                provided->reg))
806
411k
    {
807
411k
      provided->loaded = TRUE;
808
      /* insert first so we can unload the features in reverse order */
809
411k
      this->loaded->insert_first(this->loaded, provided);
810
411k
      return;
811
411k
    }
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
411k
  }
831
327k
  else
832
327k
  { /* 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
327k
    this->stats.depends++;
836
327k
  }
837
327k
  provided->failed = TRUE;
838
327k
  this->stats.critical += provided->entry->critical ? 1 : 0;
839
327k
  this->stats.failed++;
840
327k
}
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
932k
{
849
932k
  if (provided->loaded || provided->failed)
850
176k
  {
851
176k
    return;
852
176k
  }
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
755k
  if (provided->loading)
872
16.7k
  {
873
16.7k
    return;
874
16.7k
  }
875
738k
#endif /* USE_FUZZING && DEBUG_LEVEL */
876
877
738k
  provided->loading = TRUE;
878
738k
  load_feature(this, provided, level + 1);
879
738k
  provided->loading = FALSE;
880
738k
}
881
882
/**
883
 * Load registered plugin features
884
 */
885
static void load_features(private_plugin_loader_t *this)
886
8.39k
{
887
8.39k
  enumerator_t *enumerator, *inner;
888
8.39k
  plugin_entry_t *plugin;
889
8.39k
  provided_feature_t *provided;
890
891
  /* we do this in plugin order to allow implicit dependencies to be resolved
892
   * by reordering plugins */
893
8.39k
  enumerator = this->plugins->create_enumerator(this->plugins);
894
58.7k
  while (enumerator->enumerate(enumerator, &plugin))
895
50.3k
  {
896
50.3k
    inner = plugin->features->create_enumerator(plugin->features);
897
789k
    while (inner->enumerate(inner, &provided))
898
738k
    {
899
738k
      load_provided(this, provided, 0);
900
738k
    }
901
50.3k
    inner->destroy(inner);
902
50.3k
  }
903
8.39k
  enumerator->destroy(enumerator);
904
8.39k
}
905
906
/**
907
 * Default implementation for plugin feature retrieval
908
 */
909
static int get_features_default(plugin_t *plugin, plugin_feature_t *features[])
910
50.3k
{
911
50.3k
  return plugin->get_features(plugin, features);
912
50.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
50.3k
{
920
50.3k
  plugin_feature_t *feature, *reg;
921
50.3k
  registered_feature_t *registered, lookup;
922
50.3k
  provided_feature_t *provided;
923
50.3k
  int count, i;
924
925
50.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
50.3k
  reg = NULL;
932
50.3k
  count = this->get_features(entry->plugin, &feature);
933
1.94M
  for (i = 0; i < count; i++)
934
1.89M
  {
935
1.89M
    switch (feature->kind)
936
1.89M
    {
937
738k
      case FEATURE_PROVIDE:
938
738k
        lookup.feature = feature;
939
738k
        registered = this->features->ht.get(&this->features->ht,
940
738k
                          &lookup);
941
738k
        if (!registered)
942
638k
        {
943
638k
          INIT(registered,
944
638k
            .feature = feature,
945
638k
            .plugins = linked_list_create(),
946
638k
          );
947
638k
          this->features->ht.put(&this->features->ht, registered,
948
638k
                       registered);
949
638k
        }
950
738k
        INIT(provided,
951
738k
          .entry = entry,
952
738k
          .feature = feature,
953
738k
          .reg = reg,
954
738k
          .dependencies = count - i,
955
738k
        );
956
738k
        registered->plugins->insert_last(registered->plugins,
957
738k
                         provided);
958
738k
        entry->features->insert_last(entry->features, provided);
959
738k
        break;
960
403k
      case FEATURE_REGISTER:
961
403k
      case FEATURE_CALLBACK:
962
403k
        reg = feature;
963
403k
        break;
964
755k
      default:
965
755k
        break;
966
1.89M
    }
967
1.89M
    feature++;
968
1.89M
  }
969
50.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
738k
{
977
738k
  registered_feature_t *registered, lookup;
978
979
738k
  lookup.feature = provided->feature;
980
738k
  registered = this->features->ht.get(&this->features->ht, &lookup);
981
738k
  if (registered)
982
738k
  {
983
738k
    registered->plugins->remove(registered->plugins, provided, NULL);
984
738k
    if (registered->plugins->get_count(registered->plugins) == 0)
985
638k
    {
986
638k
      this->features->ht.remove(&this->features->ht, &lookup);
987
638k
      registered->plugins->destroy(registered->plugins);
988
638k
      free(registered);
989
638k
    }
990
100k
    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
738k
  }
998
738k
  free(provided);
999
738k
}
1000
1001
/**
1002
 * Unregister plugin features
1003
 */
1004
static void unregister_features(private_plugin_loader_t *this,
1005
                plugin_entry_t *entry)
1006
50.3k
{
1007
50.3k
  provided_feature_t *provided;
1008
50.3k
  enumerator_t *enumerator;
1009
1010
50.3k
  enumerator = entry->features->create_enumerator(entry->features);
1011
377k
  while (enumerator->enumerate(enumerator, &provided))
1012
327k
  {
1013
327k
    entry->features->remove_at(entry->features, enumerator);
1014
327k
    unregister_feature(this, provided);
1015
327k
  }
1016
50.3k
  enumerator->destroy(enumerator);
1017
50.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
8.39k
{
1024
8.39k
  enumerator_t *enumerator;
1025
8.39k
  plugin_entry_t *entry;
1026
1027
8.39k
  enumerator = this->plugins->create_enumerator(this->plugins);
1028
58.7k
  while (enumerator->enumerate(enumerator, &entry))
1029
50.3k
  {
1030
50.3k
    if (!entry->plugin->get_features)
1031
0
    { /* feature interface not supported */
1032
0
      continue;
1033
0
    }
1034
50.3k
    if (!entry->features->find_first(entry->features, is_feature_loaded,
1035
50.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
50.3k
  }
1044
8.39k
  enumerator->destroy(enumerator);
1045
8.39k
}
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
352k
{
1071
352k
  struct stat stb;
1072
1073
352k
  if (path && snprintf(buf, PATH_MAX, "%s/libstrongswan-%s.so",
1074
352k
             path, name) < PATH_MAX)
1075
352k
  {
1076
352k
    if (stat(buf, &stb) == 0)
1077
0
    {
1078
0
      *file = buf;
1079
0
      return TRUE;
1080
0
    }
1081
352k
  }
1082
352k
  return FALSE;
1083
352k
}
1084
1085
CALLBACK(find_plugin_cb, bool,
1086
  char *path, va_list args)
1087
302k
{
1088
302k
  char *name, *buf, **file;
1089
1090
302k
  VA_ARGS_VGET(args, name, buf, file);
1091
302k
  return find_plugin(path, name, buf, file);
1092
302k
}
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
50.3k
{
1109
50.3k
  free(this->name);
1110
50.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
193k
{
1118
193k
  return strcmp(a->name, b->name);
1119
193k
}
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
75.5k
{
1127
75.5k
  int diff;
1128
1129
75.5k
  diff = b->prio - a->prio;
1130
75.5k
  if (!diff)
1131
75.5k
  { /* the same priority, use default order */
1132
75.5k
    diff = b->def - a->def;
1133
75.5k
    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
75.5k
  }
1138
75.5k
  return diff;
1139
75.5k
}
1140
1141
CALLBACK(plugin_priority_filter, bool,
1142
  void *null, enumerator_t *orig, va_list args)
1143
58.7k
{
1144
58.7k
  plugin_priority_t *prio;
1145
58.7k
  char **name;
1146
1147
58.7k
  VA_ARGS_VGET(args, name);
1148
1149
58.7k
  if (orig->enumerate(orig, &prio))
1150
50.3k
  {
1151
50.3k
    *name = prio->name;
1152
50.3k
    return TRUE;
1153
50.3k
  }
1154
8.39k
  return FALSE;
1155
58.7k
}
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
8.39k
{
1163
8.39k
  enumerator_t *enumerator;
1164
8.39k
  array_t *given, *final;
1165
8.39k
  plugin_priority_t item, *current, found;
1166
8.39k
  char *plugin, *plugins = NULL;
1167
8.39k
  int i = 0, max_prio;
1168
8.39k
  bool load_def = FALSE;
1169
1170
8.39k
  given = array_create(sizeof(plugin_priority_t), 0);
1171
8.39k
  final = array_create(sizeof(plugin_priority_t), 0);
1172
1173
8.39k
  enumerator = enumerator_create_token(list, " ", " ");
1174
58.7k
  while (enumerator->enumerate(enumerator, &plugin))
1175
50.3k
  {
1176
50.3k
    item.name = strdup(plugin);
1177
50.3k
    item.prio = i++;
1178
50.3k
    array_insert(given, ARRAY_TAIL, &item);
1179
50.3k
  }
1180
8.39k
  enumerator->destroy(enumerator);
1181
8.39k
  array_sort(given, (void*)plugin_priority_cmp_name, NULL);
1182
  /* the maximum priority used for plugins not found in this list */
1183
8.39k
  max_prio = i + 1;
1184
1185
8.39k
  if (lib->settings->get_bool(lib->settings, "%s.load_modular", FALSE,
1186
8.39k
                lib->ns))
1187
0
  {
1188
0
    enumerator = lib->settings->create_section_enumerator(lib->settings,
1189
0
                            "%s.plugins", lib->ns);
1190
0
  }
1191
8.39k
  else
1192
8.39k
  {
1193
8.39k
    enumerator = enumerator_create_filter(array_create_enumerator(given),
1194
8.39k
                    plugin_priority_filter, NULL, NULL);
1195
8.39k
    load_def = TRUE;
1196
8.39k
  }
1197
58.7k
  while (enumerator->enumerate(enumerator, &plugin))
1198
50.3k
  {
1199
50.3k
    item.prio = lib->settings->get_int(lib->settings,
1200
50.3k
              "%s.plugins.%s.load", 0, lib->ns, plugin);
1201
50.3k
    if (!item.prio)
1202
50.3k
    {
1203
50.3k
      if (!lib->settings->get_bool(lib->settings,
1204
50.3k
              "%s.plugins.%s.load", load_def, lib->ns, plugin))
1205
0
      {
1206
0
        continue;
1207
0
      }
1208
50.3k
      item.prio = 1;
1209
50.3k
    }
1210
50.3k
    item.name = plugin;
1211
50.3k
    item.def = max_prio;
1212
50.3k
    if (array_bsearch(given, &item, (void*)plugin_priority_cmp_name,
1213
50.3k
              &found) != -1)
1214
50.3k
    {
1215
50.3k
      item.def = max_prio - found.prio;
1216
50.3k
    }
1217
50.3k
    array_insert(final, ARRAY_TAIL, &item);
1218
50.3k
  }
1219
8.39k
  enumerator->destroy(enumerator);
1220
1221
8.39k
  array_sort(final, (void*)plugin_priority_cmp, NULL);
1222
1223
8.39k
  plugins = strdup("");
1224
8.39k
  enumerator = array_create_enumerator(final);
1225
58.7k
  while (enumerator->enumerate(enumerator, &current))
1226
50.3k
  {
1227
50.3k
    char *prev = plugins;
1228
50.3k
    if (asprintf(&plugins, "%s %s", plugins ?: "", current->name) < 0)
1229
0
    {
1230
0
      plugins = prev;
1231
0
      break;
1232
0
    }
1233
50.3k
    free(prev);
1234
50.3k
  }
1235
8.39k
  enumerator->destroy(enumerator);
1236
8.39k
  array_destroy_function(given, (void*)plugin_priority_free, NULL);
1237
8.39k
  array_destroy(final);
1238
8.39k
  return plugins;
1239
8.39k
}
1240
1241
METHOD(plugin_loader_t, load_plugins, bool,
1242
  private_plugin_loader_t *this, char *list)
1243
8.39k
{
1244
8.39k
  enumerator_t *enumerator;
1245
8.39k
  char *default_path = NULL, *plugins, *token;
1246
8.39k
  bool critical_failed = FALSE;
1247
1248
8.39k
#ifdef PLUGINDIR
1249
8.39k
  default_path = PLUGINDIR;
1250
8.39k
#endif /* PLUGINDIR */
1251
1252
8.39k
  plugins = modular_pluginlist(list);
1253
1254
8.39k
  enumerator = enumerator_create_token(plugins, " ", " ");
1255
58.7k
  while (!critical_failed && enumerator->enumerate(enumerator, &token))
1256
50.3k
  {
1257
50.3k
    plugin_entry_t *entry;
1258
50.3k
    bool critical = FALSE;
1259
50.3k
    char buf[PATH_MAX], *file = NULL;
1260
50.3k
    int len;
1261
1262
50.3k
    token = strdup(token);
1263
50.3k
    len = strlen(token);
1264
50.3k
    if (token[len-1] == '!')
1265
0
    {
1266
0
      critical = TRUE;
1267
0
      token[len-1] = '\0';
1268
0
    }
1269
50.3k
    if (plugin_loaded(this, token))
1270
0
    {
1271
0
      free(token);
1272
0
      continue;
1273
0
    }
1274
50.3k
    if (this->paths)
1275
50.3k
    {
1276
50.3k
      this->paths->find_first(this->paths, find_plugin_cb, NULL, token,
1277
50.3k
                  buf, &file);
1278
50.3k
    }
1279
50.3k
    if (!file)
1280
50.3k
    {
1281
50.3k
      find_plugin(default_path, token, buf, &file);
1282
50.3k
    }
1283
50.3k
    entry = load_plugin(this, token, file, critical);
1284
50.3k
    if (entry)
1285
50.3k
    {
1286
50.3k
      register_features(this, entry);
1287
50.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
50.3k
    free(token);
1294
50.3k
  }
1295
8.39k
  enumerator->destroy(enumerator);
1296
8.39k
  if (!critical_failed)
1297
8.39k
  {
1298
8.39k
    load_features(this);
1299
8.39k
    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
8.39k
    purge_plugins(this);
1307
8.39k
  }
1308
8.39k
  if (!critical_failed)
1309
8.39k
  {
1310
8.39k
    free(this->loaded_plugins);
1311
8.39k
    this->loaded_plugins = loaded_plugins_list(this);
1312
8.39k
  }
1313
8.39k
  if (plugins != list)
1314
8.39k
  {
1315
8.39k
    free(plugins);
1316
8.39k
  }
1317
8.39k
  return !critical_failed;
1318
8.39k
}
1319
1320
/**
1321
 * Unload plugin features, they are registered in reverse order
1322
 */
1323
static void unload_features(private_plugin_loader_t *this)
1324
16.7k
{
1325
16.7k
  enumerator_t *enumerator;
1326
16.7k
  provided_feature_t *provided;
1327
16.7k
  plugin_entry_t *entry;
1328
1329
16.7k
  enumerator = this->loaded->create_enumerator(this->loaded);
1330
428k
  while (enumerator->enumerate(enumerator, &provided))
1331
411k
  {
1332
411k
    entry = provided->entry;
1333
411k
    plugin_feature_unload(entry->plugin, provided->feature, provided->reg);
1334
411k
    this->loaded->remove_at(this->loaded, enumerator);
1335
411k
    entry->features->remove(entry->features, provided, NULL);
1336
411k
    unregister_feature(this, provided);
1337
411k
  }
1338
16.7k
  enumerator->destroy(enumerator);
1339
16.7k
}
1340
1341
METHOD(plugin_loader_t, unload, void,
1342
  private_plugin_loader_t *this)
1343
16.7k
{
1344
16.7k
  plugin_entry_t *entry;
1345
1346
  /* unload features followed by plugins, in reverse order */
1347
16.7k
  unload_features(this);
1348
67.1k
  while (this->plugins->remove_last(this->plugins, (void**)&entry) == SUCCESS)
1349
50.3k
  {
1350
50.3k
    if (lib->leak_detective)
1351
0
    { /* keep handle to report leaks properly */
1352
0
      entry->handle = NULL;
1353
0
    }
1354
50.3k
    unregister_features(this, entry);
1355
50.3k
    plugin_entry_destroy(entry);
1356
50.3k
  }
1357
16.7k
  free(this->loaded_plugins);
1358
16.7k
  this->loaded_plugins = NULL;
1359
16.7k
  memset(&this->stats, 0, sizeof(this->stats));
1360
16.7k
}
1361
1362
METHOD(plugin_loader_t, add_path, void,
1363
  private_plugin_loader_t *this, char *path)
1364
50.3k
{
1365
50.3k
  if (!this->paths)
1366
8.39k
  {
1367
8.39k
    this->paths = linked_list_create();
1368
8.39k
  }
1369
50.3k
  this->paths->insert_last(this->paths, strdupnull(path));
1370
50.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
8.39k
{
1443
8.39k
  unload(this);
1444
8.39k
  this->features->destroy(this->features);
1445
8.39k
  this->loaded->destroy(this->loaded);
1446
8.39k
  this->plugins->destroy(this->plugins);
1447
8.39k
  DESTROY_FUNCTION_IF(this->paths, free);
1448
8.39k
  free(this->loaded_plugins);
1449
8.39k
  free(this);
1450
8.39k
}
1451
1452
/*
1453
 * see header file
1454
 */
1455
plugin_loader_t *plugin_loader_create()
1456
8.39k
{
1457
8.39k
  private_plugin_loader_t *this;
1458
1459
8.39k
  INIT(this,
1460
8.39k
    .public = {
1461
8.39k
      .add_static_features = _add_static_features,
1462
8.39k
      .load = _load_plugins,
1463
8.39k
      .add_path = _add_path,
1464
8.39k
      .reload = _reload,
1465
8.39k
      .unload = _unload,
1466
8.39k
      .create_plugin_enumerator = _create_plugin_enumerator,
1467
8.39k
      .has_feature = _has_feature,
1468
8.39k
      .loaded_plugins = _loaded_plugins,
1469
8.39k
      .status = _status,
1470
8.39k
      .destroy = _destroy,
1471
8.39k
    },
1472
8.39k
    .plugins = linked_list_create(),
1473
8.39k
    .loaded = linked_list_create(),
1474
8.39k
    .features = hashlist_create(
1475
8.39k
              (hashtable_hash_t)registered_feature_hash,
1476
8.39k
              (hashtable_equals_t)registered_feature_equals, 64),
1477
8.39k
    .get_features = dlsym(RTLD_DEFAULT, "plugin_loader_feature_filter"),
1478
8.39k
  );
1479
1480
8.39k
  if (!this->get_features)
1481
8.39k
  {
1482
8.39k
    this->get_features = get_features_default;
1483
8.39k
  }
1484
1485
8.39k
  return &this->public;
1486
8.39k
}
1487
1488
/*
1489
 * See header
1490
 */
1491
void plugin_loader_add_plugindirs(char *basedir, char *plugins)
1492
8.39k
{
1493
8.39k
  enumerator_t *enumerator;
1494
8.39k
  char *name, path[PATH_MAX], dir[64];
1495
1496
8.39k
  enumerator = enumerator_create_token(plugins, " ", "!");
1497
58.7k
  while (enumerator->enumerate(enumerator, &name))
1498
50.3k
  {
1499
50.3k
    snprintf(dir, sizeof(dir), "%s", name);
1500
50.3k
    translate(dir, "-", "_");
1501
50.3k
    snprintf(path, sizeof(path), "%s/%s/.libs", basedir, dir);
1502
50.3k
    lib->plugins->add_path(lib->plugins, path);
1503
50.3k
  }
1504
8.39k
  enumerator->destroy(enumerator);
1505
8.39k
}