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