]>
Commit | Line | Data |
---|---|---|
6b3292da | 1 | /* |
d25ce370 | 2 | * Copyright (C) 2009 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> |
12642a68 | 25 | #include <collections/hashtable.h> |
4c6c9346 | 26 | #include <utils/backtrace.h> |
5493ffde | 27 | #include <selectors/traffic_selector.h> |
db7ef624 | 28 | |
60d62b9e | 29 | #define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so" |
0179d468 | 30 | |
552cc11b | 31 | typedef struct private_library_t private_library_t; |
db7ef624 | 32 | |
f27f6296 | 33 | /** |
552cc11b | 34 | * private data of library |
f27f6296 | 35 | */ |
552cc11b | 36 | struct private_library_t { |
f27f6296 | 37 | |
552cc11b MW |
38 | /** |
39 | * public functions | |
40 | */ | |
41 | library_t public; | |
2ce569cc MW |
42 | |
43 | /** | |
44 | * Hashtable with registered objects (name => object) | |
45 | */ | |
46 | hashtable_t *objects; | |
1e5e1fb6 MW |
47 | |
48 | /** | |
49 | * Integrity check failed? | |
50 | */ | |
51 | bool integrity_failed; | |
52 | ||
53 | /** | |
54 | * Number of times we have been initialized | |
55 | */ | |
56 | refcount_t ref; | |
552cc11b | 57 | }; |
60356f33 | 58 | |
db7ef624 | 59 | /** |
552cc11b | 60 | * library instance |
db7ef624 | 61 | */ |
1e5e1fb6 | 62 | library_t *lib = NULL; |
db7ef624 | 63 | |
a426851f MW |
64 | #ifdef LEAK_DETECTIVE |
65 | /** | |
66 | * Default leak report callback | |
67 | */ | |
68 | static void report_leaks(void *user, int count, size_t bytes, | |
69 | backtrace_t *bt, bool detailed) | |
70 | { | |
71 | fprintf(stderr, "%zu bytes total, %d allocations, %zu bytes average:\n", | |
72 | bytes, count, bytes / count); | |
73 | bt->log(bt, stderr, detailed); | |
74 | } | |
75 | ||
76 | /** | |
77 | * Default leak report summary callback | |
78 | */ | |
79 | static void sum_leaks(void* user, int count, size_t bytes, int whitelisted) | |
80 | { | |
81 | switch (count) | |
82 | { | |
83 | case 0: | |
84 | fprintf(stderr, "No leaks detected"); | |
85 | break; | |
86 | case 1: | |
87 | fprintf(stderr, "One leak detected"); | |
88 | break; | |
89 | default: | |
90 | fprintf(stderr, "%d leaks detected, %zu bytes", count, bytes); | |
91 | break; | |
92 | } | |
93 | fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted); | |
94 | } | |
95 | #endif /* LEAK_DETECTIVE */ | |
96 | ||
db7ef624 | 97 | /** |
2ce569cc | 98 | * Deinitialize library |
db7ef624 | 99 | */ |
552cc11b | 100 | void library_deinit() |
db7ef624 | 101 | { |
552cc11b | 102 | private_library_t *this = (private_library_t*)lib; |
091d1780 MW |
103 | bool detailed; |
104 | ||
1e5e1fb6 MW |
105 | if (!this || !ref_put(&this->ref)) |
106 | { /* have more users */ | |
107 | return; | |
108 | } | |
109 | ||
091d1780 MW |
110 | detailed = lib->settings->get_bool(lib->settings, |
111 | "libstrongswan.leak_detective.detailed", TRUE); | |
552cc11b | 112 | |
a5951a28 TB |
113 | /* make sure the cache is clear before unloading plugins */ |
114 | lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); | |
115 | ||
2ba27601 | 116 | this->public.streams->destroy(this->public.streams); |
32b2a5e0 | 117 | this->public.watcher->destroy(this->public.watcher); |
e18556e9 TB |
118 | this->public.scheduler->destroy(this->public.scheduler); |
119 | this->public.processor->destroy(this->public.processor); | |
552cc11b | 120 | this->public.plugins->destroy(this->public.plugins); |
292d8f41 | 121 | this->public.hosts->destroy(this->public.hosts); |
552cc11b | 122 | this->public.settings->destroy(this->public.settings); |
2ccc02a4 | 123 | this->public.credmgr->destroy(this->public.credmgr); |
552cc11b | 124 | this->public.creds->destroy(this->public.creds); |
d9b24887 | 125 | this->public.encoding->destroy(this->public.encoding); |
552cc11b | 126 | this->public.crypto->destroy(this->public.crypto); |
a2eb5817 | 127 | this->public.caps->destroy(this->public.caps); |
4c57c630 | 128 | this->public.proposal->destroy(this->public.proposal); |
552cc11b | 129 | this->public.fetcher->destroy(this->public.fetcher); |
b1505b34 | 130 | this->public.resolver->destroy(this->public.resolver); |
552cc11b MW |
131 | this->public.db->destroy(this->public.db); |
132 | this->public.printf_hook->destroy(this->public.printf_hook); | |
8fde0b66 | 133 | this->objects->destroy(this->objects); |
960e0c10 MW |
134 | if (this->public.integrity) |
135 | { | |
136 | this->public.integrity->destroy(this->public.integrity); | |
137 | } | |
7daf5226 | 138 | |
f37e8252 | 139 | if (lib->leak_detective) |
db7ef624 | 140 | { |
f37e8252 MW |
141 | lib->leak_detective->report(lib->leak_detective, detailed); |
142 | lib->leak_detective->destroy(lib->leak_detective); | |
db7ef624 | 143 | } |
4a5a5dd2 TB |
144 | |
145 | threads_deinit(); | |
4c6c9346 | 146 | backtrace_deinit(); |
4a5a5dd2 | 147 | |
34d3bfcf | 148 | free((void*)this->public.ns); |
552cc11b MW |
149 | free(this); |
150 | lib = NULL; | |
db7ef624 MW |
151 | } |
152 | ||
2ce569cc MW |
153 | METHOD(library_t, get, void*, |
154 | private_library_t *this, char *name) | |
155 | { | |
156 | return this->objects->get(this->objects, name); | |
157 | } | |
158 | ||
159 | METHOD(library_t, set, bool, | |
160 | private_library_t *this, char *name, void *object) | |
161 | { | |
162 | if (object) | |
163 | { | |
164 | if (this->objects->get(this->objects, name)) | |
165 | { | |
166 | return FALSE; | |
167 | } | |
168 | this->objects->put(this->objects, name, object); | |
169 | return TRUE; | |
170 | } | |
171 | return this->objects->remove(this->objects, name) != NULL; | |
172 | } | |
173 | ||
174 | /** | |
175 | * Hashtable hash function | |
176 | */ | |
177 | static u_int hash(char *key) | |
178 | { | |
179 | return chunk_hash(chunk_create(key, strlen(key))); | |
180 | } | |
181 | ||
182 | /** | |
183 | * Hashtable equals function | |
184 | */ | |
185 | static bool equals(char *a, char *b) | |
186 | { | |
187 | return streq(a, b); | |
188 | } | |
189 | ||
1657b4ef MW |
190 | /** |
191 | * Number of words we write and memwipe() in memwipe check | |
192 | */ | |
193 | #define MEMWIPE_WIPE_WORDS 16 | |
194 | ||
e6ba688a MW |
195 | /** |
196 | * Write magic to memory, and try to clear it with memwipe() | |
197 | */ | |
198 | __attribute__((noinline)) | |
bc1c92c9 | 199 | static void do_magic(int *magic, int **out) |
e6ba688a | 200 | { |
1657b4ef | 201 | int buf[MEMWIPE_WIPE_WORDS], i; |
e6ba688a | 202 | |
bc1c92c9 | 203 | *out = buf; |
e6ba688a MW |
204 | for (i = 0; i < countof(buf); i++) |
205 | { | |
9312fbc7 | 206 | buf[i] = *magic; |
e6ba688a MW |
207 | } |
208 | /* passing buf to dbg should make sure the compiler can't optimize out buf. | |
209 | * we use directly dbg(3), as DBG3() might be stripped with DEBUG_LEVEL. */ | |
210 | dbg(DBG_LIB, 3, "memwipe() pre: %b", buf, sizeof(buf)); | |
211 | memwipe(buf, sizeof(buf)); | |
212 | } | |
213 | ||
214 | /** | |
215 | * Check if memwipe works as expected | |
216 | */ | |
217 | static bool check_memwipe() | |
218 | { | |
bc1c92c9 | 219 | int magic = 0xCAFEBABE, *buf, i; |
e6ba688a | 220 | |
bc1c92c9 | 221 | do_magic(&magic, &buf); |
e6ba688a | 222 | |
bc1c92c9 | 223 | for (i = 0; i < MEMWIPE_WIPE_WORDS; i++) |
e6ba688a | 224 | { |
bc1c92c9 | 225 | if (buf[i] == magic) |
e6ba688a | 226 | { |
bc1c92c9 MW |
227 | DBG1(DBG_LIB, "memwipe() check failed: stackdir: %b", |
228 | buf, MEMWIPE_WIPE_WORDS * sizeof(int)); | |
e6ba688a MW |
229 | return FALSE; |
230 | } | |
231 | } | |
232 | return TRUE; | |
233 | } | |
234 | ||
552cc11b MW |
235 | /* |
236 | * see header file | |
db7ef624 | 237 | */ |
34d3bfcf | 238 | bool library_init(char *settings, const char *namespace) |
db7ef624 | 239 | { |
2ce569cc | 240 | private_library_t *this; |
552cc11b | 241 | printf_hook_t *pfh; |
2ce569cc | 242 | |
1e5e1fb6 MW |
243 | if (lib) |
244 | { /* already initialized, increase refcount */ | |
245 | this = (private_library_t*)lib; | |
246 | ref_get(&this->ref); | |
247 | return !this->integrity_failed; | |
248 | } | |
249 | ||
2ce569cc MW |
250 | INIT(this, |
251 | .public = { | |
252 | .get = _get, | |
253 | .set = _set, | |
34d3bfcf | 254 | .ns = strdup(namespace ?: "libstrongswan"), |
2ce569cc | 255 | }, |
1e5e1fb6 | 256 | .ref = 1, |
2ce569cc | 257 | ); |
552cc11b | 258 | lib = &this->public; |
7daf5226 | 259 | |
4c6c9346 | 260 | backtrace_init(); |
4a5a5dd2 TB |
261 | threads_init(); |
262 | ||
552cc11b | 263 | #ifdef LEAK_DETECTIVE |
f37e8252 | 264 | lib->leak_detective = leak_detective_create(); |
a426851f MW |
265 | lib->leak_detective->set_report_cb(lib->leak_detective, |
266 | report_leaks, sum_leaks, NULL); | |
552cc11b | 267 | #endif /* LEAK_DETECTIVE */ |
2f5914a3 | 268 | |
552cc11b MW |
269 | pfh = printf_hook_create(); |
270 | this->public.printf_hook = pfh; | |
7daf5226 | 271 | |
d25ce370 TB |
272 | pfh->add_handler(pfh, 'b', mem_printf_hook, |
273 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT, | |
274 | PRINTF_HOOK_ARGTYPE_END); | |
275 | pfh->add_handler(pfh, 'B', chunk_printf_hook, | |
276 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END); | |
d25ce370 TB |
277 | pfh->add_handler(pfh, 'H', host_printf_hook, |
278 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END); | |
279 | pfh->add_handler(pfh, 'N', enum_printf_hook, | |
280 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT, | |
281 | PRINTF_HOOK_ARGTYPE_END); | |
282 | pfh->add_handler(pfh, 'T', time_printf_hook, | |
283 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_INT, | |
284 | PRINTF_HOOK_ARGTYPE_END); | |
285 | pfh->add_handler(pfh, 'V', time_delta_printf_hook, | |
286 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_POINTER, | |
287 | PRINTF_HOOK_ARGTYPE_END); | |
d24a74c5 TB |
288 | pfh->add_handler(pfh, 'Y', identification_printf_hook, |
289 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END); | |
5493ffde MW |
290 | pfh->add_handler(pfh, 'R', traffic_selector_printf_hook, |
291 | PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END); | |
7daf5226 | 292 | |
2ce569cc MW |
293 | this->objects = hashtable_create((hashtable_hash_t)hash, |
294 | (hashtable_equals_t)equals, 4); | |
28a0728b | 295 | this->public.settings = settings_create(settings); |
7a684aec TB |
296 | /* all namespace settings may fall back to libstrongswan */ |
297 | lib->settings->add_fallback(lib->settings, lib->ns, "libstrongswan"); | |
298 | ||
b4f6c39e | 299 | this->public.hosts = host_resolver_create(); |
4c57c630 | 300 | this->public.proposal = proposal_keywords_create(); |
a2eb5817 | 301 | this->public.caps = capabilities_create(); |
552cc11b MW |
302 | this->public.crypto = crypto_factory_create(); |
303 | this->public.creds = credential_factory_create(); | |
2ccc02a4 | 304 | this->public.credmgr = credential_manager_create(); |
da9724e6 | 305 | this->public.encoding = cred_encoding_create(); |
552cc11b | 306 | this->public.fetcher = fetcher_manager_create(); |
b1505b34 | 307 | this->public.resolver = resolver_manager_create(); |
552cc11b | 308 | this->public.db = database_factory_create(); |
e18556e9 TB |
309 | this->public.processor = processor_create(); |
310 | this->public.scheduler = scheduler_create(); | |
32b2a5e0 | 311 | this->public.watcher = watcher_create(); |
2ba27601 | 312 | this->public.streams = stream_manager_create(); |
552cc11b | 313 | this->public.plugins = plugin_loader_create(); |
7daf5226 | 314 | |
e6ba688a MW |
315 | if (!check_memwipe()) |
316 | { | |
e6ba688a MW |
317 | return FALSE; |
318 | } | |
319 | ||
960e0c10 MW |
320 | if (lib->settings->get_bool(lib->settings, |
321 | "libstrongswan.integrity_test", FALSE)) | |
322 | { | |
bef50875 | 323 | #ifdef INTEGRITY_TEST |
0179d468 | 324 | this->public.integrity = integrity_checker_create(CHECKSUM_LIBRARY); |
6a8c8815 | 325 | if (!lib->integrity->check(lib->integrity, "libstrongswan", library_init)) |
059c479a | 326 | { |
8b0e0910 | 327 | DBG1(DBG_LIB, "integrity check of libstrongswan failed"); |
1e5e1fb6 | 328 | this->integrity_failed = TRUE; |
059c479a | 329 | } |
bef50875 | 330 | #else /* !INTEGRITY_TEST */ |
8b0e0910 | 331 | DBG1(DBG_LIB, "integrity test enabled, but not supported"); |
1e5e1fb6 | 332 | this->integrity_failed = TRUE; |
bef50875 | 333 | #endif /* INTEGRITY_TEST */ |
960e0c10 | 334 | } |
4c6c9346 | 335 | |
1e5e1fb6 | 336 | return !this->integrity_failed; |
db7ef624 | 337 | } |