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