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