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