]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/charon-tkm/src/charon-tkm.c
Add compile option to disable internal handling of fatal signals
[thirdparty/strongswan.git] / src / charon-tkm / src / charon-tkm.c
1 /*
2 * Copyright (C) 2012-2017 Tobias Brunner
3 * Copyright (C) 2012 Reto Buerki
4 * Copyright (C) 2012 Adrian-Ken Rueegsegger
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <syslog.h>
22 #include <signal.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <libgen.h>
27 #include <fcntl.h>
28 #include <errno.h>
29
30 #include <daemon.h>
31 #include <library.h>
32 #include <utils/backtrace.h>
33 #include <threading/thread.h>
34 #include <sa/keymat.h>
35 #include <credentials/credential_manager.h>
36
37 #include "tkm.h"
38 #include "tkm_nonceg.h"
39 #include "tkm_diffie_hellman.h"
40 #include "tkm_keymat.h"
41 #include "tkm_listener.h"
42 #include "tkm_kernel_ipsec.h"
43 #include "tkm_public_key.h"
44 #include "tkm_cred.h"
45 #include "tkm_encoder.h"
46
47 /**
48 * TKM bus listener for IKE authorize events.
49 */
50 static tkm_listener_t *listener;
51
52 /**
53 * Name of the daemon
54 */
55 static char *dmn_name;
56
57 /**
58 * PID file, in which charon-tkm stores its process id
59 */
60 static char *pidfile_name = NULL;
61
62 /**
63 * Global reference to PID file (required to truncate, if undeletable)
64 */
65 static FILE *pidfile = NULL;
66
67 /**
68 * Hook in library for debugging messages
69 */
70 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
71
72 /**
73 * Simple logging hook for library logs, using syslog output
74 */
75 static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
76 {
77 if (level <= 1)
78 {
79 char buffer[8192];
80 va_list args;
81
82 va_start(args, fmt);
83 /* write in memory buffer first */
84 vsnprintf(buffer, sizeof(buffer), fmt, args);
85 syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", debug_names->names[group],
86 buffer);
87 va_end(args);
88 }
89 }
90
91 /**
92 * Run the daemon and handle unix signals
93 */
94 static void run()
95 {
96 sigset_t set;
97
98 /* handle SIGINT and SIGTERM in this handler */
99 sigemptyset(&set);
100 sigaddset(&set, SIGINT);
101 sigaddset(&set, SIGTERM);
102 sigprocmask(SIG_BLOCK, &set, NULL);
103
104 while (TRUE)
105 {
106 int sig;
107
108 sig = sigwaitinfo(&set, NULL);
109 if (sig == -1)
110 {
111 if (errno == EINTR)
112 { /* ignore signals we didn't wait for */
113 continue;
114 }
115 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
116 return;
117 }
118 switch (sig)
119 {
120 case SIGINT:
121 {
122 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
123 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
124 return;
125 }
126 case SIGTERM:
127 {
128 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
129 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
130 return;
131 }
132 }
133 }
134 }
135
136 #ifndef DISABLE_SIGNAL_HANDLER
137 /**
138 * Handle SIGSEGV/SIGILL signals raised by threads
139 */
140 static void segv_handler(int signal)
141 {
142 backtrace_t *backtrace;
143
144 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
145 backtrace = backtrace_create(2);
146 backtrace->log(backtrace, stderr, TRUE);
147 backtrace->destroy(backtrace);
148
149 DBG1(DBG_DMN, "killing ourself, received critical signal");
150 abort();
151 }
152 #endif /* DISABLE_SIGNAL_HANDLER */
153
154 /**
155 * Lookup UID and GID
156 */
157 static bool lookup_uid_gid()
158 {
159 #ifdef IPSEC_USER
160 if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER))
161 {
162 return FALSE;
163 }
164 #endif
165 #ifdef IPSEC_GROUP
166 if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP))
167 {
168 return FALSE;
169 }
170 #endif
171 return TRUE;
172 }
173
174 /**
175 * Check/create PID file, return TRUE if already running
176 */
177 static bool check_pidfile()
178 {
179 struct stat stb;
180
181 if (stat(pidfile_name, &stb) == 0)
182 {
183 pidfile = fopen(pidfile_name, "r");
184 if (pidfile)
185 {
186 char buf[64];
187 pid_t pid = 0;
188
189 memset(buf, 0, sizeof(buf));
190 if (fread(buf, 1, sizeof(buf), pidfile))
191 {
192 buf[sizeof(buf) - 1] = '\0';
193 pid = atoi(buf);
194 }
195 fclose(pidfile);
196 pidfile = NULL;
197 if (pid && pid != getpid() && kill(pid, 0) == 0)
198 {
199 DBG1(DBG_DMN, "%s already running ('%s' exists)", dmn_name,
200 pidfile_name);
201 return TRUE;
202 }
203 }
204 DBG1(DBG_DMN, "removing pidfile '%s', process not running", pidfile_name);
205 unlink(pidfile_name);
206 }
207
208 /* create new pidfile */
209 pidfile = fopen(pidfile_name, "w");
210 if (pidfile)
211 {
212 int fd;
213
214 fd = fileno(pidfile);
215 if (fd == -1)
216 {
217 DBG1(DBG_DMN, "unable to determine fd for '%s'", pidfile_name);
218 return TRUE;
219 }
220 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
221 {
222 DBG1(DBG_LIB, "setting FD_CLOEXEC for '%s' failed: %s",
223 pidfile_name, strerror(errno));
224 }
225 ignore_result(fchown(fd,
226 lib->caps->get_uid(lib->caps),
227 lib->caps->get_gid(lib->caps)));
228 fprintf(pidfile, "%d\n", getpid());
229 fflush(pidfile);
230 return FALSE;
231 }
232 else
233 {
234 DBG1(DBG_DMN, "unable to create pidfile '%s'", pidfile_name);
235 return TRUE;
236 }
237 }
238
239 /**
240 * Delete/truncate the PID file
241 */
242 static void unlink_pidfile()
243 {
244 /* because unlinking the PID file may fail, we truncate it to ensure the
245 * daemon can be properly restarted. one probable cause for this is the
246 * combination of not running as root and the effective user lacking
247 * permissions on the parent dir(s) of the PID file */
248 if (pidfile)
249 {
250 ignore_result(ftruncate(fileno(pidfile), 0));
251 fclose(pidfile);
252 unlink(pidfile_name);
253 }
254 }
255
256 /**
257 * Main function, starts TKM backend.
258 */
259 int main(int argc, char *argv[])
260 {
261 if (argc > 0 && strlen(argv[0]) > 0)
262 {
263 dmn_name = basename(argv[0]);
264 }
265 else
266 {
267 dmn_name = "charon-tkm";
268 }
269
270 /* TKM credential set */
271 tkm_cred_t *creds;
272
273 struct sigaction action;
274 int status = SS_RC_INITIALIZATION_FAILED;
275
276 /* logging for library during initialization, as we have no bus yet */
277 dbg = dbg_syslog;
278
279 /* initialize library */
280 if (!library_init(NULL, dmn_name))
281 {
282 library_deinit();
283 exit(status);
284 }
285
286 if (!libcharon_init())
287 {
288 dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
289 goto deinit;
290 }
291
292 if (!lookup_uid_gid())
293 {
294 dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting %s", dmn_name);
295 goto deinit;
296 }
297
298 /* the authorize hook currently does not support RFC 7427 signature auth */
299 lib->settings->set_bool(lib->settings, "%s.signature_authentication", FALSE,
300 dmn_name);
301
302 /* make sure we log to the DAEMON facility by default */
303 lib->settings->set_int(lib->settings, "%s.syslog.daemon.default",
304 lib->settings->get_int(lib->settings, "%s.syslog.daemon.default", 1,
305 dmn_name), dmn_name);
306 charon->load_loggers(charon);
307
308 DBG1(DBG_DMN, "Starting charon with TKM backend (strongSwan "VERSION")");
309
310 /* register TKM specific plugins */
311 static plugin_feature_t features[] = {
312 PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create),
313 PLUGIN_PROVIDE(NONCE_GEN),
314 PLUGIN_REGISTER(PUBKEY, tkm_public_key_load, TRUE),
315 PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
316 PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
317 PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
318 PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create),
319 PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
320 };
321 lib->plugins->add_static_features(lib->plugins, "tkm-backend", features,
322 countof(features), TRUE, NULL, NULL);
323
324 if (!register_dh_mapping())
325 {
326 DBG1(DBG_DMN, "no DH group mapping defined - aborting %s", dmn_name);
327 goto deinit;
328 }
329
330 /* register TKM keymat variant */
331 keymat_register_constructor(IKEV2, (keymat_constructor_t)tkm_keymat_create);
332
333 /* initialize daemon */
334 if (!charon->initialize(charon, PLUGINS))
335 {
336 DBG1(DBG_DMN, "initialization failed - aborting %s", dmn_name);
337 goto deinit;
338 }
339 lib->plugins->status(lib->plugins, LEVEL_CTRL);
340
341 /* set global pidfile name depending on daemon name */
342 if (asprintf(&pidfile_name, IPSEC_PIDDIR"/%s.pid", dmn_name) < 0)
343 {
344 DBG1(DBG_DMN, "unable to set pidfile name - aborting %s", dmn_name);
345 goto deinit;
346 };
347
348 if (check_pidfile())
349 {
350 goto deinit;
351 }
352
353 if (!lib->caps->drop(lib->caps))
354 {
355 DBG1(DBG_DMN, "capability dropping failed - aborting %s", dmn_name);
356 goto deinit;
357 }
358
359 /* initialize TKM client */
360 if (!tkm_init())
361 {
362 DBG1(DBG_DMN, "init of TKM client failed - aborting %s", dmn_name);
363 goto deinit;
364 }
365
366 /* register TKM authorization hook */
367 listener = tkm_listener_create();
368 charon->bus->add_listener(charon->bus, &listener->listener);
369
370 /* register TKM credential set */
371 creds = tkm_cred_create();
372 lib->credmgr->add_set(lib->credmgr, (credential_set_t*)creds);
373
374 /* register TKM credential encoder */
375 lib->encoding->add_encoder(lib->encoding, tkm_encoder_encode);
376
377 /* add handler for fatal signals,
378 * INT and TERM are handled by sigwaitinfo() in run() */
379 action.sa_flags = 0;
380 sigemptyset(&action.sa_mask);
381 sigaddset(&action.sa_mask, SIGINT);
382 sigaddset(&action.sa_mask, SIGTERM);
383
384 /* optionally let the external system handle fatal signals */
385 #ifndef DISABLE_SIGNAL_HANDLER
386 action.sa_handler = segv_handler;
387 sigaction(SIGSEGV, &action, NULL);
388 sigaction(SIGILL, &action, NULL);
389 sigaction(SIGBUS, &action, NULL);
390 #endif /* DISABLE_SIGNAL_HANDLER */
391
392 action.sa_handler = SIG_IGN;
393 sigaction(SIGPIPE, &action, NULL);
394
395 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
396
397 /* start daemon (i.e. the threads in the thread-pool) */
398 charon->start(charon);
399
400 /* main thread goes to run loop */
401 run();
402
403 status = 0;
404 charon->bus->remove_listener(charon->bus, &listener->listener);
405 listener->destroy(listener);
406 creds->destroy(creds);
407 lib->encoding->remove_encoder(lib->encoding, tkm_encoder_encode);
408
409 deinit:
410 destroy_dh_mapping();
411 libcharon_deinit();
412 tkm_deinit();
413 unlink_pidfile();
414 free(pidfile_name);
415 library_deinit();
416 return status;
417 }