Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/library.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2009-2018 Tobias Brunner
3
 * Copyright (C) 2008 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
#include "library.h"
19
20
#include <stdlib.h>
21
22
#include <utils/debug.h>
23
#include <threading/thread.h>
24
#include <utils/identification.h>
25
#include <networking/host.h>
26
#include <collections/array.h>
27
#include <collections/hashtable.h>
28
#include <utils/backtrace.h>
29
#include <selectors/traffic_selector.h>
30
#include <crypto/proposal/proposal.h>
31
32
#define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so"
33
34
#ifndef STRONGSWAN_CONF
35
#define STRONGSWAN_CONF NULL
36
#endif
37
38
typedef struct private_library_t private_library_t;
39
40
/**
41
 * private data of library
42
 */
43
struct private_library_t {
44
45
  /**
46
   * public functions
47
   */
48
  library_t public;
49
50
  /**
51
   * Hashtable with registered objects (name => object)
52
   */
53
  hashtable_t *objects;
54
55
  /**
56
   * Integrity check failed?
57
   */
58
  bool init_failed;
59
60
#ifdef LEAK_DETECTIVE
61
  /**
62
   * Where to write leak detective output to
63
   */
64
  FILE *ld_out;
65
#endif
66
67
  /**
68
   * Number of times we have been initialized
69
   */
70
  refcount_t ref;
71
};
72
73
0
#define MAX_NAMESPACES 5
74
75
/**
76
 * Additional namespaces registered using __attribute__((constructor))
77
 */
78
static char *namespaces[MAX_NAMESPACES];
79
static int ns_count;
80
81
/**
82
 * Described in header
83
 */
84
void library_add_namespace(char *ns)
85
0
{
86
0
  if (ns_count < MAX_NAMESPACES - 1)
87
0
  {
88
0
    namespaces[ns_count] = ns;
89
0
    ns_count++;
90
0
  }
91
0
  else
92
0
  {
93
0
    fprintf(stderr, "failed to register additional namespace alias, please "
94
0
        "increase MAX_NAMESPACES");
95
0
  }
96
0
}
97
98
/**
99
 * Register plugins if built statically
100
 */
101
#ifdef STATIC_PLUGIN_CONSTRUCTORS
102
#include "plugin_constructors.c"
103
#endif
104
105
/**
106
 * library instance
107
 */
108
library_t *lib = NULL;
109
110
#ifdef LEAK_DETECTIVE
111
/**
112
 * Default leak report callback
113
 */
114
CALLBACK(report_leaks, void,
115
  private_library_t *this, int count, size_t bytes, backtrace_t *bt,
116
  bool detailed)
117
{
118
  fprintf(this->ld_out, "%zu bytes total, %d allocations, %zu bytes average:\n",
119
      bytes, count, bytes / count);
120
  bt->log(bt, this->ld_out, detailed);
121
}
122
123
/**
124
 * Default leak report summary callback
125
 */
126
CALLBACK(sum_leaks, void,
127
  private_library_t *this, int count, size_t bytes, int whitelisted)
128
{
129
  switch (count)
130
  {
131
    case 0:
132
      fprintf(this->ld_out, "No leaks detected");
133
      break;
134
    case 1:
135
      fprintf(this->ld_out, "One leak detected");
136
      break;
137
    default:
138
      fprintf(this->ld_out, "%d leaks detected, %zu bytes", count, bytes);
139
      break;
140
  }
141
  fprintf(this->ld_out, ", %d suppressed by whitelist\n", whitelisted);
142
}
143
#endif /* LEAK_DETECTIVE */
144
145
/**
146
 * Deinitialize library
147
 */
148
void library_deinit()
149
3.92k
{
150
3.92k
  private_library_t *this = (private_library_t*)lib;
151
3.92k
  bool detailed;
152
153
3.92k
  if (!this || !ref_put(&this->ref))
154
0
  { /* have more users */
155
0
    return;
156
0
  }
157
158
3.92k
  detailed = lib->settings->get_bool(lib->settings,
159
3.92k
                "%s.leak_detective.detailed", TRUE, lib->ns);
160
161
  /* make sure the cache is clear before unloading plugins */
162
3.92k
  lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
163
164
3.92k
  this->public.streams->destroy(this->public.streams);
165
3.92k
  this->public.watcher->destroy(this->public.watcher);
166
3.92k
  this->public.scheduler->destroy(this->public.scheduler);
167
3.92k
  this->public.processor->destroy(this->public.processor);
168
3.92k
  this->public.plugins->destroy(this->public.plugins);
169
3.92k
  this->public.hosts->destroy(this->public.hosts);
170
3.92k
  this->public.settings->destroy(this->public.settings);
171
3.92k
  this->public.credmgr->destroy(this->public.credmgr);
172
3.92k
  this->public.creds->destroy(this->public.creds);
173
3.92k
  this->public.encoding->destroy(this->public.encoding);
174
3.92k
  this->public.ocsp->destroy(this->public.ocsp);
175
3.92k
  this->public.metadata->destroy(this->public.metadata);
176
3.92k
  this->public.crypto->destroy(this->public.crypto);
177
3.92k
  this->public.caps->destroy(this->public.caps);
178
3.92k
  this->public.proposal->destroy(this->public.proposal);
179
3.92k
  this->public.fetcher->destroy(this->public.fetcher);
180
3.92k
  this->public.resolver->destroy(this->public.resolver);
181
3.92k
  this->public.db->destroy(this->public.db);
182
3.92k
  this->public.printf_hook->destroy(this->public.printf_hook);
183
3.92k
  this->objects->destroy(this->objects);
184
3.92k
  if (this->public.integrity)
185
0
  {
186
0
    this->public.integrity->destroy(this->public.integrity);
187
0
  }
188
189
3.92k
  if (lib->leak_detective)
190
0
  {
191
0
    lib->leak_detective->report(lib->leak_detective, detailed);
192
0
    lib->leak_detective->destroy(lib->leak_detective);
193
0
    lib->leak_detective = NULL;
194
0
  }
195
#ifdef LEAK_DETECTIVE
196
  if (this->ld_out && this->ld_out != stderr)
197
  {
198
    fclose(this->ld_out);
199
  }
200
#endif /* LEAK_DETECTIVE */
201
202
3.92k
  backtrace_deinit();
203
3.92k
  arrays_deinit();
204
3.92k
  utils_deinit();
205
3.92k
  threads_deinit();
206
207
3.92k
  free(this->public.conf);
208
3.92k
  free((void*)this->public.ns);
209
3.92k
  free(this);
210
3.92k
  lib = NULL;
211
3.92k
}
212
213
METHOD(library_t, get, void*,
214
  private_library_t *this, char *name)
215
0
{
216
0
  return this->objects->get(this->objects, name);
217
0
}
218
219
METHOD(library_t, set, bool,
220
  private_library_t *this, char *name, void *object)
221
0
{
222
0
  if (object)
223
0
  {
224
0
    if (this->objects->get(this->objects, name))
225
0
    {
226
0
      return FALSE;
227
0
    }
228
0
    this->objects->put(this->objects, name, object);
229
0
    return TRUE;
230
0
  }
231
0
  return this->objects->remove(this->objects, name) != NULL;
232
0
}
233
234
/**
235
 * Hashtable hash function
236
 */
237
static u_int hash(char *key)
238
0
{
239
0
  return chunk_hash(chunk_create(key, strlen(key)));
240
0
}
241
242
/**
243
 * Hashtable equals function
244
 */
245
static bool equals(char *a, char *b)
246
0
{
247
0
  return streq(a, b);
248
0
}
249
250
/**
251
 * Number of words we write and memwipe() in memwipe check
252
 */
253
#define MEMWIPE_WIPE_WORDS 16
254
255
#ifndef NO_CHECK_MEMWIPE
256
257
/**
258
 * Write magic to memory, and try to clear it with memwipe()
259
 */
260
__attribute__((noinline))
261
static void do_magic(int *magic, int **out)
262
{
263
  int buf[MEMWIPE_WIPE_WORDS], i;
264
265
  *out = buf;
266
  for (i = 0; i < countof(buf); i++)
267
  {
268
    buf[i] = *magic;
269
  }
270
  /* passing buf to dbg should make sure the compiler can't optimize out buf.
271
   * we use directly dbg(3), as DBG3() might be stripped with DEBUG_LEVEL. */
272
  dbg(DBG_LIB, 3, "memwipe() pre: %b", buf, sizeof(buf));
273
  memwipe(buf, sizeof(buf));
274
}
275
276
/**
277
 * Check if memwipe works as expected
278
 */
279
static bool check_memwipe()
280
{
281
  int magic = 0xCAFEBABE, *buf, i;
282
283
  do_magic(&magic, &buf);
284
285
  for (i = 0; i < MEMWIPE_WIPE_WORDS; i++)
286
  {
287
    if (buf[i] == magic)
288
    {
289
      DBG1(DBG_LIB, "memwipe() check failed: stackdir: %b",
290
         buf, MEMWIPE_WIPE_WORDS * sizeof(int));
291
      return FALSE;
292
    }
293
  }
294
  return TRUE;
295
}
296
297
#endif
298
299
/*
300
 * see header file
301
 */
302
bool library_init(char *settings, const char *namespace)
303
3.92k
{
304
3.92k
  private_library_t *this;
305
3.92k
  printf_hook_t *pfh;
306
3.92k
  int i;
307
308
3.92k
  if (lib)
309
0
  { /* already initialized, increase refcount */
310
0
    this = (private_library_t*)lib;
311
0
    ref_get(&this->ref);
312
0
    return !this->init_failed;
313
0
  }
314
315
3.92k
  chunk_hash_seed();
316
317
3.92k
  INIT(this,
318
3.92k
    .public = {
319
3.92k
      .get = _get,
320
3.92k
      .set = _set,
321
3.92k
      .ns = strdup(namespace ?: "libstrongswan"),
322
3.92k
      .conf = strdupnull(settings ?: (getenv("STRONGSWAN_CONF") ?: STRONGSWAN_CONF)),
323
3.92k
    },
324
3.92k
    .ref = 1,
325
3.92k
  );
326
3.92k
  lib = &this->public;
327
328
3.92k
  threads_init();
329
3.92k
  utils_init();
330
3.92k
  arrays_init();
331
3.92k
  backtrace_init();
332
333
#ifdef LEAK_DETECTIVE
334
  {
335
    FILE *out = NULL;
336
    char *log;
337
338
    log = getenv("LEAK_DETECTIVE_LOG");
339
    if (log)
340
    {
341
      out = fopen(log, "a");
342
    }
343
    this->ld_out = out ?: stderr;
344
  }
345
  lib->leak_detective = leak_detective_create();
346
  if (lib->leak_detective)
347
  {
348
    lib->leak_detective->set_report_cb(lib->leak_detective,
349
                       report_leaks, sum_leaks, this);
350
  }
351
#endif /* LEAK_DETECTIVE */
352
353
3.92k
  pfh = printf_hook_create();
354
3.92k
  this->public.printf_hook = pfh;
355
356
3.92k
  pfh->add_handler(pfh, 'b', mem_printf_hook,
357
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT,
358
3.92k
           PRINTF_HOOK_ARGTYPE_END);
359
3.92k
  pfh->add_handler(pfh, 'B', chunk_printf_hook,
360
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
361
3.92k
  pfh->add_handler(pfh, 'H', host_printf_hook,
362
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
363
3.92k
  pfh->add_handler(pfh, 'N', enum_printf_hook,
364
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT,
365
3.92k
           PRINTF_HOOK_ARGTYPE_END);
366
3.92k
  pfh->add_handler(pfh, 'T', time_printf_hook,
367
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT,
368
3.92k
           PRINTF_HOOK_ARGTYPE_END);
369
3.92k
  pfh->add_handler(pfh, 'V', time_delta_printf_hook,
370
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_POINTER,
371
3.92k
           PRINTF_HOOK_ARGTYPE_END);
372
3.92k
  pfh->add_handler(pfh, 'Y', identification_printf_hook,
373
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
374
3.92k
  pfh->add_handler(pfh, 'R', traffic_selector_printf_hook,
375
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
376
3.92k
  pfh->add_handler(pfh, 'P', proposal_printf_hook,
377
3.92k
           PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
378
379
3.92k
  this->objects = hashtable_create((hashtable_hash_t)hash,
380
3.92k
                   (hashtable_equals_t)equals, 4);
381
382
3.92k
  this->public.settings = settings_create(NULL);
383
3.92k
  if (!this->public.settings->load_files(this->public.settings,
384
3.92k
                       this->public.conf, FALSE))
385
3.92k
  {
386
3.92k
    DBG1(DBG_LIB, "abort initialization due to invalid configuration");
387
3.92k
    this->init_failed = TRUE;
388
3.92k
  }
389
390
  /* add registered aliases */
391
3.92k
  for (i = 0; i < ns_count; ++i)
392
0
  {
393
0
    lib->settings->add_fallback(lib->settings, lib->ns, namespaces[i]);
394
0
  }
395
  /* all namespace settings may fall back to libstrongswan */
396
3.92k
  lib->settings->add_fallback(lib->settings, lib->ns, "libstrongswan");
397
398
3.92k
  this->public.hosts = host_resolver_create();
399
3.92k
  this->public.proposal = proposal_keywords_create();
400
3.92k
  this->public.caps = capabilities_create();
401
3.92k
  this->public.crypto = crypto_factory_create();
402
3.92k
  this->public.creds = credential_factory_create();
403
3.92k
  this->public.credmgr = credential_manager_create();
404
3.92k
  this->public.encoding = cred_encoding_create();
405
3.92k
  this->public.ocsp = ocsp_responders_create();
406
3.92k
  this->public.metadata = metadata_factory_create();
407
3.92k
  this->public.fetcher = fetcher_manager_create();
408
3.92k
  this->public.resolver = resolver_manager_create();
409
3.92k
  this->public.db = database_factory_create();
410
3.92k
  this->public.processor = processor_create();
411
3.92k
  this->public.scheduler = scheduler_create();
412
3.92k
  this->public.watcher = watcher_create();
413
3.92k
  this->public.streams = stream_manager_create();
414
3.92k
  this->public.plugins = plugin_loader_create();
415
416
#ifndef NO_CHECK_MEMWIPE
417
  if (!check_memwipe())
418
  {
419
    return FALSE;
420
  }
421
#endif
422
423
3.92k
  if (lib->settings->get_bool(lib->settings,
424
3.92k
                "%s.integrity_test", FALSE, lib->ns))
425
0
  {
426
#ifdef INTEGRITY_TEST
427
    this->public.integrity = integrity_checker_create(CHECKSUM_LIBRARY);
428
    if (!lib->integrity->check(lib->integrity, "libstrongswan", library_init))
429
    {
430
      DBG1(DBG_LIB, "integrity check of libstrongswan failed");
431
      this->init_failed = TRUE;
432
    }
433
#else /* !INTEGRITY_TEST */
434
0
    DBG1(DBG_LIB, "integrity test enabled, but not supported");
435
0
    this->init_failed = TRUE;
436
0
#endif /* INTEGRITY_TEST */
437
0
  }
438
439
3.92k
  diffie_hellman_init();
440
441
3.92k
  return !this->init_failed;
442
3.92k
}