]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/conftest/conftest.c
lib: Add global config namespace
[people/ms/strongswan.git] / src / conftest / conftest.c
CommitLineData
e78ec86d
MW
1/*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
f452a5a1 16#define _GNU_SOURCE
e78ec86d
MW
17#include <unistd.h>
18#include <stdio.h>
19#include <errno.h>
20#include <signal.h>
21#include <getopt.h>
f452a5a1 22#include <dlfcn.h>
b318e0ab 23#include <libgen.h>
e78ec86d
MW
24
25#include "conftest.h"
d1041fa4 26#include "config.h"
f452a5a1 27#include "hooks/hook.h"
e78ec86d 28
d35d6691 29#include <bus/listeners/file_logger.h>
e78ec86d 30#include <threading/thread.h>
968e5e66 31#include <credentials/certificates/x509.h>
e78ec86d
MW
32
33/**
34 * Conftest globals struct
35 */
36conftest_t *conftest;
37
38/**
39 * Print usage information
40 */
f452a5a1 41static void usage(FILE *out)
e78ec86d 42{
e78ec86d
MW
43 fprintf(out, "Usage:\n");
44 fprintf(out, " --help show usage information\n");
45 fprintf(out, " --version show conftest version\n");
46 fprintf(out, " --suite <file> global testsuite configuration "
47 "(default: ./suite.conf)\n");
48 fprintf(out, " --test <file> test specific configuration\n");
49}
50
51/**
52 * Handle SIGSEGV/SIGILL signals raised by threads
53 */
54static void segv_handler(int signal)
55{
b318e0ab 56 fprintf(stderr, "thread %u received %d\n", thread_current_id(), signal);
e78ec86d
MW
57 abort();
58}
59
60/**
61 * Load suite and test specific configurations
62 */
63static bool load_configs(char *suite_file, char *test_file)
64{
65 if (!test_file)
66 {
67 fprintf(stderr, "Missing test configuration file.\n");
68 return FALSE;
69 }
70 if (access(suite_file, R_OK) != 0)
71 {
72 fprintf(stderr, "Reading suite configuration file '%s' failed: %s.\n",
73 suite_file, strerror(errno));
74 return FALSE;
75 }
76 if (access(test_file, R_OK) != 0)
77 {
78 fprintf(stderr, "Reading test configuration file '%s' failed: %s.\n",
79 test_file, strerror(errno));
80 return FALSE;
81 }
98ef2865 82 conftest->test = settings_create(suite_file);
32973044 83 conftest->test->load_files(conftest->test, test_file, TRUE);
98ef2865 84 conftest->suite_dir = strdup(dirname(suite_file));
b318e0ab
MW
85 return TRUE;
86}
87
88/**
90994a8a 89 * Load trusted/untrusted certificates
b318e0ab 90 */
48ef0011 91static bool load_cert(settings_t *settings, bool trusted)
b318e0ab
MW
92{
93 enumerator_t *enumerator;
90994a8a 94 char *key, *value;
b318e0ab 95
90994a8a
MW
96 enumerator = settings->create_key_value_enumerator(settings,
97 trusted ? "certs.trusted" : "certs.untrusted");
b318e0ab
MW
98 while (enumerator->enumerate(enumerator, &key, &value))
99 {
90994a8a
MW
100 certificate_t *cert = NULL;
101
48ef0011 102 if (strncaseeq(key, "x509", strlen("x509")))
a784c9e0 103 {
90994a8a
MW
104 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
105 CERT_X509, BUILD_FROM_FILE, value, BUILD_END);
a784c9e0 106 }
48ef0011 107 else if (strncaseeq(key, "crl", strlen("crl")))
b318e0ab 108 {
90994a8a
MW
109 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
110 CERT_X509_CRL, BUILD_FROM_FILE, value, BUILD_END);
b318e0ab 111 }
90994a8a 112 else
a784c9e0
MW
113 {
114 fprintf(stderr, "certificate type '%s' not supported\n", key);
115 enumerator->destroy(enumerator);
116 return FALSE;
117 }
b318e0ab
MW
118 if (!cert)
119 {
90994a8a
MW
120 fprintf(stderr, "loading %strusted certificate '%s' from '%s' "
121 "failed\n", trusted ? "" : "un", key, value);
b318e0ab
MW
122 enumerator->destroy(enumerator);
123 return FALSE;
124 }
90994a8a 125 conftest->creds->add_cert(conftest->creds, trusted, cert);
b318e0ab
MW
126 }
127 enumerator->destroy(enumerator);
90994a8a
MW
128 return TRUE;
129}
130
131/**
132 * Load certificates from the confiuguration file
133 */
134static bool load_certs(settings_t *settings, char *dir)
135{
136 char wd[PATH_MAX];
137
138 if (getcwd(wd, sizeof(wd)) == NULL)
139 {
140 fprintf(stderr, "getting cwd failed: %s\n", strerror(errno));
141 return FALSE;
142 }
143 if (chdir(dir) != 0)
144 {
145 fprintf(stderr, "opening directory '%s' failed: %s\n",
146 dir, strerror(errno));
147 return FALSE;
148 }
149
48ef0011
MW
150 if (!load_cert(settings, TRUE) ||
151 !load_cert(settings, FALSE))
90994a8a
MW
152 {
153 return FALSE;
154 }
b318e0ab 155
a13c1d64
MW
156 if (chdir(wd) != 0)
157 {
158 fprintf(stderr, "opening directory '%s' failed: %s\n",
159 wd, strerror(errno));
160 return FALSE;
161 }
e78ec86d
MW
162 return TRUE;
163}
164
3f759bb7
MW
165/**
166 * Load private keys from the confiuguration file
167 */
168static bool load_keys(settings_t *settings, char *dir)
169{
170 enumerator_t *enumerator;
171 char *type, *value, wd[PATH_MAX];
172 private_key_t *key;
173 key_type_t key_type;
174
175 if (getcwd(wd, sizeof(wd)) == NULL)
176 {
177 fprintf(stderr, "getting cwd failed: %s\n", strerror(errno));
178 return FALSE;
179 }
180 if (chdir(dir) != 0)
181 {
182 fprintf(stderr, "opening directory '%s' failed: %s\n",
183 dir, strerror(errno));
184 return FALSE;
185 }
186
187 enumerator = settings->create_key_value_enumerator(settings, "keys");
188 while (enumerator->enumerate(enumerator, &type, &value))
189 {
48ef0011 190 if (strncaseeq(type, "ecdsa", strlen("ecdsa")))
3f759bb7
MW
191 {
192 key_type = KEY_ECDSA;
193 }
48ef0011 194 else if (strncaseeq(type, "rsa", strlen("rsa")))
3f759bb7
MW
195 {
196 key_type = KEY_RSA;
197 }
198 else
199 {
84545f6e 200 fprintf(stderr, "unknown key type: '%s'\n", type);
3f759bb7
MW
201 enumerator->destroy(enumerator);
202 return FALSE;
203 }
204 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
205 BUILD_FROM_FILE, value, BUILD_END);
206 if (!key)
207 {
208 fprintf(stderr, "loading %s key from '%s' failed\n", type, value);
209 enumerator->destroy(enumerator);
210 return FALSE;
211 }
212 conftest->creds->add_key(conftest->creds, key);
213 }
214 enumerator->destroy(enumerator);
215
216 if (chdir(wd) != 0)
217 {
218 fprintf(stderr, "opening directory '%s' failed: %s\n",
219 wd, strerror(errno));
220 return FALSE;
221 }
222 return TRUE;
223}
224
968e5e66
MW
225/**
226 * Load certificate distribution points
227 */
228static void load_cdps(settings_t *settings)
229{
230 enumerator_t *enumerator;
231 identification_t *id;
232 char *ca, *uri, *section;
97d30f00 233 certificate_type_t type;
968e5e66
MW
234 x509_t *x509;
235
236 enumerator = settings->create_section_enumerator(settings, "cdps");
237 while (enumerator->enumerate(enumerator, &section))
238 {
97d30f00
MW
239 if (strncaseeq(section, "crl", strlen("crl")))
240 {
241 type = CERT_X509_CRL;
242 }
243 else if (strncaseeq(section, "ocsp", strlen("ocsp")))
244 {
245 type = CERT_X509_OCSP_RESPONSE;
246 }
247 else
968e5e66
MW
248 {
249 fprintf(stderr, "unknown cdp type '%s', ignored\n", section);
250 continue;
251 }
252
253 uri = settings->get_str(settings, "cdps.%s.uri", NULL, section);
254 ca = settings->get_str(settings, "cdps.%s.ca", NULL, section);
255 if (!ca || !uri)
256 {
257 fprintf(stderr, "cdp '%s' misses ca/uri, ignored\n", section);
258 continue;
259 }
260 x509 = lib->creds->create(lib->creds, CRED_CERTIFICATE,
261 CERT_X509, BUILD_FROM_FILE, ca, BUILD_END);
262 if (!x509)
263 {
264 fprintf(stderr, "loading cdp '%s' ca failed, ignored\n", section);
265 continue;
266 }
267 id = identification_create_from_encoding(ID_KEY_ID,
268 x509->get_subjectKeyIdentifier(x509));
97d30f00 269 conftest->creds->add_cdp(conftest->creds, type, id, uri);
968e5e66
MW
270 DESTROY_IF((certificate_t*)x509);
271 id->destroy(id);
272 }
273 enumerator->destroy(enumerator);
274}
275
f452a5a1
MW
276/**
277 * Load configured hooks
278 */
279static bool load_hooks()
280{
281 enumerator_t *enumerator;
a60b8928
MW
282 char *name, *pos, buf[64];
283 hook_t *(*create)(char*);
f452a5a1
MW
284 hook_t *hook;
285
286 enumerator = conftest->test->create_section_enumerator(conftest->test,
287 "hooks");
288 while (enumerator->enumerate(enumerator, &name))
289 {
a60b8928
MW
290 pos = strchr(name, '-');
291 if (pos)
292 {
a05f3b20
TB
293 snprintf(buf, sizeof(buf), "%.*s_hook_create", (int)(pos - name),
294 name);
a60b8928
MW
295 }
296 else
297 {
298 snprintf(buf, sizeof(buf), "%s_hook_create", name);
299 }
f452a5a1
MW
300 create = dlsym(RTLD_DEFAULT, buf);
301 if (create)
302 {
a60b8928 303 hook = create(name);
f452a5a1
MW
304 if (hook)
305 {
306 conftest->hooks->insert_last(conftest->hooks, hook);
307 charon->bus->add_listener(charon->bus, &hook->listener);
308 }
309 }
310 else
311 {
312 fprintf(stderr, "dlsym() for hook '%s' failed: %s\n", name, dlerror());
313 enumerator->destroy(enumerator);
314 return FALSE;
315 }
316 }
317 enumerator->destroy(enumerator);
318 return TRUE;
319}
320
e78ec86d
MW
321/**
322 * atexit() cleanup handler
323 */
324static void cleanup()
325{
18a8893e 326 file_logger_t *logger;
f452a5a1
MW
327 hook_t *hook;
328
e78ec86d 329 DESTROY_IF(conftest->test);
b318e0ab
MW
330 lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set);
331 conftest->creds->destroy(conftest->creds);
73a3013f 332 DESTROY_IF(conftest->actions);
f452a5a1
MW
333 while (conftest->hooks->remove_last(conftest->hooks,
334 (void**)&hook) == SUCCESS)
335 {
336 charon->bus->remove_listener(charon->bus, &hook->listener);
337 hook->destroy(hook);
338 }
339 conftest->hooks->destroy(conftest->hooks);
d1041fa4
MW
340 if (conftest->config)
341 {
3b3e5c0d
MW
342 if (charon->backends)
343 {
344 charon->backends->remove_backend(charon->backends,
345 &conftest->config->backend);
346 }
d1041fa4
MW
347 conftest->config->destroy(conftest->config);
348 }
18a8893e
TB
349 while (conftest->loggers->remove_last(conftest->loggers,
350 (void**)&logger) == SUCCESS)
351 {
352 charon->bus->remove_logger(charon->bus, &logger->logger);
353 logger->destroy(logger);
354 }
355 conftest->loggers->destroy(conftest->loggers);
b318e0ab 356 free(conftest->suite_dir);
e78ec86d
MW
357 free(conftest);
358 libcharon_deinit();
359 libhydra_deinit();
360 library_deinit();
361}
362
dbec133e
MW
363/**
364 * Load log levels for a logger from section
365 */
366static void load_log_levels(file_logger_t *logger, char *section)
367{
368 debug_t group;
369 level_t def;
370
371 def = conftest->test->get_int(conftest->test, "log.%s.default", 1, section);
372 for (group = 0; group < DBG_MAX; group++)
373 {
374 logger->set_level(logger, group,
375 conftest->test->get_int(conftest->test, "log.%s.%N", def,
376 section, debug_lower_names, group));
377 }
378}
379
13c17785
TK
380/**
381 * Load logger options for a logger from section
382 */
383static void load_logger_options(file_logger_t *logger, char *section)
384{
385 bool ike_name;
386 char *time_format;
387
388 time_format = conftest->test->get_str(conftest->test,
389 "log.%s.time_format", NULL, section);
390 ike_name = conftest->test->get_bool(conftest->test,
391 "log.%s.ike_name", FALSE, section);
392
393 logger->set_options(logger, time_format, ike_name);
394}
395
dbec133e
MW
396/**
397 * Load logger configuration
398 */
399static void load_loggers(file_logger_t *logger)
400{
401 enumerator_t *enumerator;
402 char *section;
dbec133e
MW
403
404 load_log_levels(logger, "stdout");
13c17785 405 load_logger_options(logger, "stdout");
b78698f7
TK
406 /* Re-add the logger to propagate configuration changes to the
407 * logging system */
408 charon->bus->add_logger(charon->bus, &logger->logger);
dbec133e
MW
409
410 enumerator = conftest->test->create_section_enumerator(conftest->test, "log");
411 while (enumerator->enumerate(enumerator, &section))
412 {
413 if (!streq(section, "stdout"))
414 {
d35d6691 415 logger = file_logger_create(section);
13c17785 416 load_logger_options(logger, section);
d35d6691 417 logger->open(logger, FALSE, FALSE);
dbec133e 418 load_log_levels(logger, section);
172fdf8b 419 charon->bus->add_logger(charon->bus, &logger->logger);
18a8893e 420 conftest->loggers->insert_last(conftest->loggers, logger);
dbec133e
MW
421 }
422 }
423 enumerator->destroy(enumerator);
424}
425
e78ec86d
MW
426/**
427 * Main function, starts the conftest daemon.
428 */
429int main(int argc, char *argv[])
430{
431 struct sigaction action;
432 int status = 0;
433 sigset_t set;
434 int sig;
11ac36b0 435 char *suite_file = "suite.conf", *test_file = NULL, *preload, *plugins;
e78ec86d
MW
436 file_logger_t *logger;
437
34d3bfcf 438 if (!library_init(NULL, "conftest"))
e78ec86d
MW
439 {
440 library_deinit();
441 return SS_RC_LIBSTRONGSWAN_INTEGRITY;
442 }
443 if (!libhydra_init("conftest"))
444 {
445 libhydra_deinit();
446 library_deinit();
447 return SS_RC_INITIALIZATION_FAILED;
448 }
18758e3d 449 if (!libcharon_init("conftest"))
e78ec86d
MW
450 {
451 libcharon_deinit();
452 libhydra_deinit();
453 library_deinit();
454 return SS_RC_INITIALIZATION_FAILED;
455 }
456
457 INIT(conftest,
b318e0ab 458 .creds = mem_cred_create(),
18a8893e
TB
459 .config = config_create(),
460 .hooks = linked_list_create(),
461 .loggers = linked_list_create(),
e78ec86d 462 );
18a8893e 463 lib->credmgr->add_set(lib->credmgr, &conftest->creds->set);
dbec133e 464
d35d6691
TB
465 logger = file_logger_create("stdout");
466 logger->set_options(logger, NULL, FALSE);
467 logger->open(logger, FALSE, FALSE);
e78ec86d 468 logger->set_level(logger, DBG_ANY, LEVEL_CTRL);
172fdf8b 469 charon->bus->add_logger(charon->bus, &logger->logger);
18a8893e 470 conftest->loggers->insert_last(conftest->loggers, logger);
b318e0ab 471
e78ec86d
MW
472 atexit(cleanup);
473
474 while (TRUE)
475 {
476 struct option long_opts[] = {
477 { "help", no_argument, NULL, 'h' },
478 { "version", no_argument, NULL, 'v' },
479 { "suite", required_argument, NULL, 's' },
480 { "test", required_argument, NULL, 't' },
481 { 0,0,0,0 }
482 };
483 switch (getopt_long(argc, argv, "", long_opts, NULL))
484 {
485 case EOF:
486 break;
487 case 'h':
f452a5a1 488 usage(stdout);
e78ec86d
MW
489 return 0;
490 case 'v':
491 printf("strongSwan %s conftest\n", VERSION);
492 return 0;
493 case 's':
494 suite_file = optarg;
495 continue;
496 case 't':
497 test_file = optarg;
498 continue;
499 default:
f452a5a1 500 usage(stderr);
e78ec86d
MW
501 return 1;
502 }
503 break;
504 }
505
506 if (!load_configs(suite_file, test_file))
507 {
508 return 1;
509 }
dbec133e
MW
510 load_loggers(logger);
511
11ac36b0
TB
512 preload = conftest->test->get_str(conftest->test, "preload", "");
513 if (asprintf(&plugins, "%s %s", preload, PLUGINS) < 0)
9a99b745
MW
514 {
515 return 1;
516 }
11ac36b0 517 if (!charon->initialize(charon, plugins))
e78ec86d 518 {
11ac36b0 519 free(plugins);
e78ec86d
MW
520 return 1;
521 }
607f8e99 522 lib->plugins->status(lib->plugins, LEVEL_CTRL);
11ac36b0 523 free(plugins);
607f8e99 524
98ef2865 525 if (!load_certs(conftest->test, conftest->suite_dir))
b318e0ab
MW
526 {
527 return 1;
528 }
98ef2865 529 if (!load_keys(conftest->test, conftest->suite_dir))
3f759bb7
MW
530 {
531 return 1;
532 }
968e5e66 533 load_cdps(conftest->test);
f452a5a1
MW
534 if (!load_hooks())
535 {
536 return 1;
537 }
d1041fa4 538 charon->backends->add_backend(charon->backends, &conftest->config->backend);
d1041fa4 539 conftest->config->load(conftest->config, conftest->test);
73a3013f 540 conftest->actions = actions_create();
e78ec86d
MW
541
542 /* set up thread specific handlers */
543 action.sa_handler = segv_handler;
544 action.sa_flags = 0;
545 sigemptyset(&action.sa_mask);
546 sigaddset(&action.sa_mask, SIGINT);
547 sigaddset(&action.sa_mask, SIGTERM);
548 sigaddset(&action.sa_mask, SIGHUP);
549 sigaction(SIGSEGV, &action, NULL);
550 sigaction(SIGILL, &action, NULL);
551 sigaction(SIGBUS, &action, NULL);
552 action.sa_handler = SIG_IGN;
553 sigaction(SIGPIPE, &action, NULL);
554 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
555
556 /* start thread pool */
557 charon->start(charon);
558
559 /* handle SIGINT/SIGTERM in main thread */
560 sigemptyset(&set);
561 sigaddset(&set, SIGINT);
562 sigaddset(&set, SIGHUP);
563 sigaddset(&set, SIGTERM);
564 sigprocmask(SIG_BLOCK, &set, NULL);
565
566 while (sigwait(&set, &sig) == 0)
567 {
568 switch (sig)
569 {
570 case SIGINT:
571 case SIGTERM:
572 fprintf(stderr, "\nshutting down...\n");
573 break;
574 default:
575 continue;
576 }
577 break;
578 }
579 return status;
580}