libhydra: Remove unused hydra->daemon
[strongswan.git] / src / conftest / conftest.c
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
16 #define _GNU_SOURCE
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <getopt.h>
22 #include <dlfcn.h>
23 #include <libgen.h>
24
25 #include "conftest.h"
26 #include "config.h"
27 #include "hooks/hook.h"
28
29 #include <bus/listeners/file_logger.h>
30 #include <threading/thread.h>
31 #include <credentials/certificates/x509.h>
32
33 /**
34 * Conftest globals struct
35 */
36 conftest_t *conftest;
37
38 /**
39 * Print usage information
40 */
41 static void usage(FILE *out)
42 {
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 */
54 static void segv_handler(int signal)
55 {
56 fprintf(stderr, "thread %u received %d\n", thread_current_id(), signal);
57 abort();
58 }
59
60 /**
61 * Load suite and test specific configurations
62 */
63 static 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 }
82 conftest->test = settings_create(suite_file);
83 conftest->test->load_files(conftest->test, test_file, TRUE);
84 conftest->suite_dir = strdup(dirname(suite_file));
85 return TRUE;
86 }
87
88 /**
89 * Load trusted/untrusted certificates
90 */
91 static bool load_cert(settings_t *settings, bool trusted)
92 {
93 enumerator_t *enumerator;
94 char *key, *value;
95
96 enumerator = settings->create_key_value_enumerator(settings,
97 trusted ? "certs.trusted" : "certs.untrusted");
98 while (enumerator->enumerate(enumerator, &key, &value))
99 {
100 certificate_t *cert = NULL;
101
102 if (strncaseeq(key, "x509", strlen("x509")))
103 {
104 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
105 CERT_X509, BUILD_FROM_FILE, value, BUILD_END);
106 }
107 else if (strncaseeq(key, "crl", strlen("crl")))
108 {
109 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
110 CERT_X509_CRL, BUILD_FROM_FILE, value, BUILD_END);
111 }
112 else
113 {
114 fprintf(stderr, "certificate type '%s' not supported\n", key);
115 enumerator->destroy(enumerator);
116 return FALSE;
117 }
118 if (!cert)
119 {
120 fprintf(stderr, "loading %strusted certificate '%s' from '%s' "
121 "failed\n", trusted ? "" : "un", key, value);
122 enumerator->destroy(enumerator);
123 return FALSE;
124 }
125 conftest->creds->add_cert(conftest->creds, trusted, cert);
126 }
127 enumerator->destroy(enumerator);
128 return TRUE;
129 }
130
131 /**
132 * Load certificates from the confiuguration file
133 */
134 static 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
150 if (!load_cert(settings, TRUE) ||
151 !load_cert(settings, FALSE))
152 {
153 return FALSE;
154 }
155
156 if (chdir(wd) != 0)
157 {
158 fprintf(stderr, "opening directory '%s' failed: %s\n",
159 wd, strerror(errno));
160 return FALSE;
161 }
162 return TRUE;
163 }
164
165 /**
166 * Load private keys from the confiuguration file
167 */
168 static 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 {
190 if (strncaseeq(type, "ecdsa", strlen("ecdsa")))
191 {
192 key_type = KEY_ECDSA;
193 }
194 else if (strncaseeq(type, "rsa", strlen("rsa")))
195 {
196 key_type = KEY_RSA;
197 }
198 else
199 {
200 fprintf(stderr, "unknown key type: '%s'\n", type);
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
225 /**
226 * Load certificate distribution points
227 */
228 static void load_cdps(settings_t *settings)
229 {
230 enumerator_t *enumerator;
231 identification_t *id;
232 char *ca, *uri, *section;
233 certificate_type_t type;
234 x509_t *x509;
235
236 enumerator = settings->create_section_enumerator(settings, "cdps");
237 while (enumerator->enumerate(enumerator, &section))
238 {
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
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));
269 conftest->creds->add_cdp(conftest->creds, type, id, uri);
270 DESTROY_IF((certificate_t*)x509);
271 id->destroy(id);
272 }
273 enumerator->destroy(enumerator);
274 }
275
276 /**
277 * Load configured hooks
278 */
279 static bool load_hooks()
280 {
281 enumerator_t *enumerator;
282 char *name, *pos, buf[64];
283 hook_t *(*create)(char*);
284 hook_t *hook;
285
286 enumerator = conftest->test->create_section_enumerator(conftest->test,
287 "hooks");
288 while (enumerator->enumerate(enumerator, &name))
289 {
290 pos = strchr(name, '-');
291 if (pos)
292 {
293 snprintf(buf, sizeof(buf), "%.*s_hook_create", (int)(pos - name),
294 name);
295 }
296 else
297 {
298 snprintf(buf, sizeof(buf), "%s_hook_create", name);
299 }
300 create = dlsym(RTLD_DEFAULT, buf);
301 if (create)
302 {
303 hook = create(name);
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
321 /**
322 * atexit() cleanup handler
323 */
324 static void cleanup()
325 {
326 file_logger_t *logger;
327 hook_t *hook;
328
329 DESTROY_IF(conftest->test);
330 lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set);
331 conftest->creds->destroy(conftest->creds);
332 DESTROY_IF(conftest->actions);
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);
340 if (conftest->config)
341 {
342 if (charon->backends)
343 {
344 charon->backends->remove_backend(charon->backends,
345 &conftest->config->backend);
346 }
347 conftest->config->destroy(conftest->config);
348 }
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);
356 free(conftest->suite_dir);
357 free(conftest);
358 libcharon_deinit();
359 libhydra_deinit();
360 library_deinit();
361 }
362
363 /**
364 * Load log levels for a logger from section
365 */
366 static 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
380 /**
381 * Load logger options for a logger from section
382 */
383 static 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
396 /**
397 * Load logger configuration
398 */
399 static void load_loggers(file_logger_t *logger)
400 {
401 enumerator_t *enumerator;
402 char *section;
403
404 load_log_levels(logger, "stdout");
405 load_logger_options(logger, "stdout");
406 /* Re-add the logger to propagate configuration changes to the
407 * logging system */
408 charon->bus->add_logger(charon->bus, &logger->logger);
409
410 enumerator = conftest->test->create_section_enumerator(conftest->test, "log");
411 while (enumerator->enumerate(enumerator, &section))
412 {
413 if (!streq(section, "stdout"))
414 {
415 logger = file_logger_create(section);
416 load_logger_options(logger, section);
417 logger->open(logger, FALSE, FALSE);
418 load_log_levels(logger, section);
419 charon->bus->add_logger(charon->bus, &logger->logger);
420 conftest->loggers->insert_last(conftest->loggers, logger);
421 }
422 }
423 enumerator->destroy(enumerator);
424 }
425
426 /**
427 * Main function, starts the conftest daemon.
428 */
429 int main(int argc, char *argv[])
430 {
431 struct sigaction action;
432 int status = 0;
433 sigset_t set;
434 int sig;
435 char *suite_file = "suite.conf", *test_file = NULL, *preload, *plugins;
436 file_logger_t *logger;
437
438 if (!library_init(NULL, "conftest"))
439 {
440 library_deinit();
441 return SS_RC_LIBSTRONGSWAN_INTEGRITY;
442 }
443 if (!libhydra_init())
444 {
445 libhydra_deinit();
446 library_deinit();
447 return SS_RC_INITIALIZATION_FAILED;
448 }
449 if (!libcharon_init("conftest"))
450 {
451 libcharon_deinit();
452 libhydra_deinit();
453 library_deinit();
454 return SS_RC_INITIALIZATION_FAILED;
455 }
456
457 INIT(conftest,
458 .creds = mem_cred_create(),
459 .config = config_create(),
460 .hooks = linked_list_create(),
461 .loggers = linked_list_create(),
462 );
463 lib->credmgr->add_set(lib->credmgr, &conftest->creds->set);
464
465 logger = file_logger_create("stdout");
466 logger->set_options(logger, NULL, FALSE);
467 logger->open(logger, FALSE, FALSE);
468 logger->set_level(logger, DBG_ANY, LEVEL_CTRL);
469 charon->bus->add_logger(charon->bus, &logger->logger);
470 conftest->loggers->insert_last(conftest->loggers, logger);
471
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':
488 usage(stdout);
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:
500 usage(stderr);
501 return 1;
502 }
503 break;
504 }
505
506 if (!load_configs(suite_file, test_file))
507 {
508 return 1;
509 }
510 load_loggers(logger);
511
512 preload = conftest->test->get_str(conftest->test, "preload", "");
513 if (asprintf(&plugins, "%s %s", preload, PLUGINS) < 0)
514 {
515 return 1;
516 }
517 if (!charon->initialize(charon, plugins))
518 {
519 free(plugins);
520 return 1;
521 }
522 lib->plugins->status(lib->plugins, LEVEL_CTRL);
523 free(plugins);
524
525 if (!load_certs(conftest->test, conftest->suite_dir))
526 {
527 return 1;
528 }
529 if (!load_keys(conftest->test, conftest->suite_dir))
530 {
531 return 1;
532 }
533 load_cdps(conftest->test);
534 if (!load_hooks())
535 {
536 return 1;
537 }
538 charon->backends->add_backend(charon->backends, &conftest->config->backend);
539 conftest->config->load(conftest->config, conftest->test);
540 conftest->actions = actions_create();
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 }