Load hooks based on listener dynamically
[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 "hooks/hook.h"
27
28 #include <threading/thread.h>
29
30 /**
31 * Conftest globals struct
32 */
33 conftest_t *conftest;
34
35 /**
36 * Print usage information
37 */
38 static void usage(FILE *out)
39 {
40 fprintf(out, "Usage:\n");
41 fprintf(out, " --help show usage information\n");
42 fprintf(out, " --version show conftest version\n");
43 fprintf(out, " --suite <file> global testsuite configuration "
44 "(default: ./suite.conf)\n");
45 fprintf(out, " --test <file> test specific configuration\n");
46 }
47
48 /**
49 * Handle SIGSEGV/SIGILL signals raised by threads
50 */
51 static void segv_handler(int signal)
52 {
53 fprintf(stderr, "thread %u received %d\n", thread_current_id(), signal);
54 abort();
55 }
56
57 /**
58 * Load suite and test specific configurations
59 */
60 static bool load_configs(char *suite_file, char *test_file)
61 {
62 if (!test_file)
63 {
64 fprintf(stderr, "Missing test configuration file.\n");
65 return FALSE;
66 }
67 if (access(suite_file, R_OK) != 0)
68 {
69 fprintf(stderr, "Reading suite configuration file '%s' failed: %s.\n",
70 suite_file, strerror(errno));
71 return FALSE;
72 }
73 if (access(test_file, R_OK) != 0)
74 {
75 fprintf(stderr, "Reading test configuration file '%s' failed: %s.\n",
76 test_file, strerror(errno));
77 return FALSE;
78 }
79 conftest->suite = settings_create(suite_file);
80 conftest->test = settings_create(test_file);
81 suite_file = dirname(suite_file);
82 test_file = dirname(test_file);
83 conftest->suite_dir = strdup(suite_file);
84 conftest->test_dir = strdup(test_file);
85 return TRUE;
86 }
87
88 /**
89 * Load certificates from the confiuguration file
90 */
91 static bool load_certs()
92 {
93 enumerator_t *enumerator;
94 char *key, *value;
95 certificate_t *cert;
96
97 if (chdir(conftest->suite_dir) != 0)
98 {
99 fprintf(stderr, "opening suite directory '%s' failed",
100 conftest->suite_dir);
101 return FALSE;
102 }
103
104 enumerator = conftest->suite->create_key_value_enumerator(
105 conftest->suite, "certs.trusted");
106 while (enumerator->enumerate(enumerator, &key, &value))
107 {
108 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
109 BUILD_FROM_FILE, value, BUILD_END);
110 if (!cert)
111 {
112 fprintf(stderr, "loading trusted certificate "
113 "'%s' from '%s' failed\n", key, value);
114 enumerator->destroy(enumerator);
115 return FALSE;
116 }
117 conftest->creds->add_cert(conftest->creds, TRUE, cert);
118 }
119 enumerator->destroy(enumerator);
120
121 enumerator = conftest->suite->create_key_value_enumerator(
122 conftest->suite, "certs.untrusted");
123 while (enumerator->enumerate(enumerator, &key, &value))
124 {
125 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
126 BUILD_FROM_FILE, value, BUILD_END);
127 if (!cert)
128 {
129 fprintf(stderr, "loading untrusted certificate "
130 "'%s' from '%s' failed\n", key, value);
131 enumerator->destroy(enumerator);
132 return FALSE;
133 }
134 conftest->creds->add_cert(conftest->creds, FALSE, cert);
135 }
136 enumerator->destroy(enumerator);
137
138 return TRUE;
139 }
140
141 /**
142 * Load configured hooks
143 */
144 static bool load_hooks()
145 {
146 enumerator_t *enumerator;
147 char *name, buf[64];
148 hook_t *(*create)(void);
149 hook_t *hook;
150
151 enumerator = conftest->test->create_section_enumerator(conftest->test,
152 "hooks");
153 while (enumerator->enumerate(enumerator, &name))
154 {
155 snprintf(buf, sizeof(buf), "%s_hook_create", name);
156 create = dlsym(RTLD_DEFAULT, buf);
157 if (create)
158 {
159 hook = create();
160 if (hook)
161 {
162 conftest->hooks->insert_last(conftest->hooks, hook);
163 charon->bus->add_listener(charon->bus, &hook->listener);
164 }
165 }
166 else
167 {
168 fprintf(stderr, "dlsym() for hook '%s' failed: %s\n", name, dlerror());
169 enumerator->destroy(enumerator);
170 return FALSE;
171 }
172 }
173 enumerator->destroy(enumerator);
174 return TRUE;
175 }
176
177 /**
178 * atexit() cleanup handler
179 */
180 static void cleanup()
181 {
182 hook_t *hook;
183
184 DESTROY_IF(conftest->suite);
185 DESTROY_IF(conftest->test);
186 lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set);
187 conftest->creds->destroy(conftest->creds);
188 while (conftest->hooks->remove_last(conftest->hooks,
189 (void**)&hook) == SUCCESS)
190 {
191 charon->bus->remove_listener(charon->bus, &hook->listener);
192 hook->destroy(hook);
193 }
194 conftest->hooks->destroy(conftest->hooks);
195 free(conftest->suite_dir);
196 free(conftest->test_dir);
197 free(conftest);
198 libcharon_deinit();
199 libhydra_deinit();
200 library_deinit();
201 }
202
203 /**
204 * Main function, starts the conftest daemon.
205 */
206 int main(int argc, char *argv[])
207 {
208 struct sigaction action;
209 int status = 0;
210 sigset_t set;
211 int sig;
212 char *suite_file = "suite.conf", *test_file = NULL;
213 file_logger_t *logger;
214
215 if (!library_init(NULL))
216 {
217 library_deinit();
218 return SS_RC_LIBSTRONGSWAN_INTEGRITY;
219 }
220 if (!libhydra_init("conftest"))
221 {
222 libhydra_deinit();
223 library_deinit();
224 return SS_RC_INITIALIZATION_FAILED;
225 }
226 if (!libcharon_init())
227 {
228 libcharon_deinit();
229 libhydra_deinit();
230 library_deinit();
231 return SS_RC_INITIALIZATION_FAILED;
232 }
233
234 INIT(conftest,
235 .creds = mem_cred_create(),
236 );
237 logger = file_logger_create(stdout, NULL, FALSE);
238 logger->set_level(logger, DBG_ANY, LEVEL_CTRL);
239 charon->bus->add_listener(charon->bus, &logger->listener);
240 charon->file_loggers->insert_last(charon->file_loggers, logger);
241
242 lib->credmgr->add_set(lib->credmgr, &conftest->creds->set);
243 conftest->hooks = linked_list_create();
244
245 atexit(cleanup);
246
247 while (TRUE)
248 {
249 struct option long_opts[] = {
250 { "help", no_argument, NULL, 'h' },
251 { "version", no_argument, NULL, 'v' },
252 { "suite", required_argument, NULL, 's' },
253 { "test", required_argument, NULL, 't' },
254 { 0,0,0,0 }
255 };
256 switch (getopt_long(argc, argv, "", long_opts, NULL))
257 {
258 case EOF:
259 break;
260 case 'h':
261 usage(stdout);
262 return 0;
263 case 'v':
264 printf("strongSwan %s conftest\n", VERSION);
265 return 0;
266 case 's':
267 suite_file = optarg;
268 continue;
269 case 't':
270 test_file = optarg;
271 continue;
272 default:
273 usage(stderr);
274 return 1;
275 }
276 break;
277 }
278
279 if (!load_configs(suite_file, test_file))
280 {
281 return 1;
282 }
283 if (!charon->initialize(charon))
284 {
285 return 1;
286 }
287 if (!load_certs(suite_file))
288 {
289 return 1;
290 }
291 if (!load_hooks())
292 {
293 return 1;
294 }
295
296 /* set up thread specific handlers */
297 action.sa_handler = segv_handler;
298 action.sa_flags = 0;
299 sigemptyset(&action.sa_mask);
300 sigaddset(&action.sa_mask, SIGINT);
301 sigaddset(&action.sa_mask, SIGTERM);
302 sigaddset(&action.sa_mask, SIGHUP);
303 sigaction(SIGSEGV, &action, NULL);
304 sigaction(SIGILL, &action, NULL);
305 sigaction(SIGBUS, &action, NULL);
306 action.sa_handler = SIG_IGN;
307 sigaction(SIGPIPE, &action, NULL);
308 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
309
310 /* start thread pool */
311 charon->start(charon);
312
313 /* handle SIGINT/SIGTERM in main thread */
314 sigemptyset(&set);
315 sigaddset(&set, SIGINT);
316 sigaddset(&set, SIGHUP);
317 sigaddset(&set, SIGTERM);
318 sigprocmask(SIG_BLOCK, &set, NULL);
319
320 while (sigwait(&set, &sig) == 0)
321 {
322 switch (sig)
323 {
324 case SIGINT:
325 case SIGTERM:
326 fprintf(stderr, "\nshutting down...\n");
327 break;
328 default:
329 continue;
330 }
331 break;
332 }
333 return status;
334 }