Register TKM bus listener in charon-tkm
[strongswan.git] / src / charon-tkm / src / charon-tkm.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Reto Buerki
4 * Copyright (C) 2012 Adrian-Ken Rueegsegger
5 * 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
28 #include <hydra.h>
29 #include <daemon.h>
30
31 #include <library.h>
32 #include <utils/backtrace.h>
33 #include <threading/thread.h>
34 #include <sa/keymat.h>
35
36 #include "tkm.h"
37 #include "tkm_nonceg.h"
38 #include "tkm_diffie_hellman.h"
39 #include "tkm_keymat.h"
40 #include "tkm_listener.h"
41
42 /**
43 * TKM bus listener for IKE authorize events.
44 */
45 static tkm_listener_t *listener;
46
47 /**
48 * PID file, in which charon-tkm stores its process id
49 */
50 static char *pidfile_name = NULL;
51
52 /**
53 * Global reference to PID file (required to truncate, if undeletable)
54 */
55 static FILE *pidfile = NULL;
56
57 /**
58 * Hook in library for debugging messages
59 */
60 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
61
62 /**
63 * Simple logging hook for library logs, using syslog output
64 */
65 static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
66 {
67 if (level <= 1)
68 {
69 char buffer[8192];
70 va_list args;
71
72 va_start(args, fmt);
73 /* write in memory buffer first */
74 vsnprintf(buffer, sizeof(buffer), fmt, args);
75 syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", debug_names->names[group],
76 buffer);
77 va_end(args);
78 }
79 }
80
81 /**
82 * Run the daemon and handle unix signals
83 */
84 static void run()
85 {
86 sigset_t set;
87
88 /* handle SIGINT and SIGTERM in this handler */
89 sigemptyset(&set);
90 sigaddset(&set, SIGINT);
91 sigaddset(&set, SIGTERM);
92 sigprocmask(SIG_BLOCK, &set, NULL);
93
94 while (TRUE)
95 {
96 int sig;
97 int error;
98
99 error = sigwait(&set, &sig);
100 if (error)
101 {
102 DBG1(DBG_DMN, "error %d while waiting for a signal", error);
103 return;
104 }
105 switch (sig)
106 {
107 case SIGINT:
108 {
109 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
110 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
111 return;
112 }
113 case SIGTERM:
114 {
115 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
116 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
117 return;
118 }
119 default:
120 {
121 DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
122 break;
123 }
124 }
125 }
126 }
127
128 /**
129 * Handle SIGSEGV/SIGILL signals raised by threads
130 */
131 static void segv_handler(int signal)
132 {
133 backtrace_t *backtrace;
134
135 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
136 backtrace = backtrace_create(2);
137 backtrace->log(backtrace, stderr, TRUE);
138 backtrace->destroy(backtrace);
139
140 DBG1(DBG_DMN, "killing ourself, received critical signal");
141 abort();
142 }
143
144 /**
145 * Lookup UID and GID
146 */
147 static bool lookup_uid_gid()
148 {
149 #ifdef IPSEC_USER
150 if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER))
151 {
152 return FALSE;
153 }
154 #endif
155 #ifdef IPSEC_GROUP
156 if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP))
157 {
158 return FALSE;
159 }
160 #endif
161 return TRUE;
162 }
163
164 /**
165 * Check/create PID file, return TRUE if already running
166 */
167 static bool check_pidfile()
168 {
169 struct stat stb;
170
171 if (stat(pidfile_name, &stb) == 0)
172 {
173 pidfile = fopen(pidfile_name, "r");
174 if (pidfile)
175 {
176 char buf[64];
177 pid_t pid = 0;
178
179 memset(buf, 0, sizeof(buf));
180 if (fread(buf, 1, sizeof(buf), pidfile))
181 {
182 buf[sizeof(buf) - 1] = '\0';
183 pid = atoi(buf);
184 }
185 fclose(pidfile);
186 if (pid && kill(pid, 0) == 0)
187 { /* such a process is running */
188 return TRUE;
189 }
190 }
191 DBG1(DBG_DMN, "removing pidfile '%s', process not running", pidfile_name);
192 unlink(pidfile_name);
193 }
194
195 /* create new pidfile */
196 pidfile = fopen(pidfile_name, "w");
197 if (pidfile)
198 {
199 ignore_result(fchown(fileno(pidfile),
200 charon->caps->get_uid(charon->caps),
201 charon->caps->get_gid(charon->caps)));
202 fprintf(pidfile, "%d\n", getpid());
203 fflush(pidfile);
204 }
205 return FALSE;
206 }
207
208 /**
209 * Delete/truncate the PID file
210 */
211 static void unlink_pidfile()
212 {
213 /* because unlinking the PID file may fail, we truncate it to ensure the
214 * daemon can be properly restarted. one probable cause for this is the
215 * combination of not running as root and the effective user lacking
216 * permissions on the parent dir(s) of the PID file */
217 if (pidfile)
218 {
219 ignore_result(ftruncate(fileno(pidfile), 0));
220 fclose(pidfile);
221 }
222 unlink(pidfile_name);
223 }
224 /**
225 * Main function, starts TKM backend.
226 */
227 int main(int argc, char *argv[])
228 {
229 char *dmn_name;
230 if (argc > 0 && strlen(argv[0]) > 0)
231 {
232 dmn_name = basename(argv[0]);
233 }
234 else
235 {
236 dmn_name = "charon-tkm";
237 }
238
239 struct sigaction action;
240 int status = SS_RC_INITIALIZATION_FAILED;
241
242 /* logging for library during initialization, as we have no bus yet */
243 dbg = dbg_syslog;
244
245 /* initialize library */
246 if (!library_init(NULL))
247 {
248 library_deinit();
249 exit(status);
250 }
251
252 if (!libhydra_init(dmn_name))
253 {
254 dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
255 libhydra_deinit();
256 library_deinit();
257 exit(status);
258 }
259
260 if (!libcharon_init(dmn_name))
261 {
262 dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
263 goto deinit;
264 }
265
266 if (!lookup_uid_gid())
267 {
268 dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting %s", dmn_name);
269 goto deinit;
270 }
271
272 /* make sure we log to the DAEMON facility by default */
273 lib->settings->set_int(lib->settings, "%s.syslog.daemon.default",
274 lib->settings->get_int(lib->settings, "%s.syslog.daemon.default", 1,
275 dmn_name), dmn_name);
276 charon->load_loggers(charon, NULL, FALSE);
277
278 DBG1(DBG_DMN, "Starting charon with TKM backend (strongSwan "VERSION")");
279
280 /* register TKM specific plugins */
281 static plugin_feature_t features[] = {
282 PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create),
283 PLUGIN_PROVIDE(NONCE_GEN),
284 PLUGIN_REGISTER(DH, tkm_diffie_hellman_create),
285 PLUGIN_PROVIDE(DH, MODP_3072_BIT),
286 PLUGIN_PROVIDE(DH, MODP_4096_BIT),
287 };
288 lib->plugins->add_static_features(lib->plugins, "tkm-backend", features,
289 countof(features), TRUE);
290
291 /* register TKM keymat variant */
292 keymat_register_constructor(IKEV2, (keymat_constructor_t)tkm_keymat_create);
293
294 /* initialize daemon */
295 if (!charon->initialize(charon, PLUGINS))
296 {
297 DBG1(DBG_DMN, "initialization failed - aborting %s", dmn_name);
298 goto deinit;
299 }
300
301 /* set global pidfile name depending on daemon name */
302 if (asprintf(&pidfile_name, IPSEC_PIDDIR"/%s.pid", dmn_name) < 0)
303 {
304 DBG1(DBG_DMN, "unable to set pidfile name - aborting %s", dmn_name);
305 goto deinit;
306 };
307
308 if (check_pidfile())
309 {
310 DBG1(DBG_DMN, "%s already running (\"%s\" exists)", dmn_name,
311 pidfile_name);
312 goto deinit;
313 }
314
315 if (!charon->caps->drop(charon->caps))
316 {
317 DBG1(DBG_DMN, "capability dropping failed - aborting %s", dmn_name);
318 goto deinit;
319 }
320
321 /* initialize TKM client */
322 if (!tkm_init())
323 {
324 DBG1(DBG_DMN, "init of TKM client failed - aborting %s", dmn_name);
325 goto deinit;
326 }
327
328 /* register TKM authorization hook */
329 listener = tkm_listener_create();
330 charon->bus->add_listener(charon->bus, &listener->listener);
331
332 /* add handler for SEGV and ILL,
333 * INT and TERM are handled by sigwait() in run() */
334 action.sa_handler = segv_handler;
335 action.sa_flags = 0;
336 sigemptyset(&action.sa_mask);
337 sigaddset(&action.sa_mask, SIGINT);
338 sigaddset(&action.sa_mask, SIGTERM);
339 sigaction(SIGSEGV, &action, NULL);
340 sigaction(SIGILL, &action, NULL);
341 sigaction(SIGBUS, &action, NULL);
342 action.sa_handler = SIG_IGN;
343 sigaction(SIGPIPE, &action, NULL);
344
345 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
346
347 /* start daemon (i.e. the threads in the thread-pool) */
348 charon->start(charon);
349
350 /* main thread goes to run loop */
351 run();
352
353 unlink_pidfile();
354 status = 0;
355 charon->bus->remove_listener(charon->bus, &listener->listener);
356 listener->destroy(listener);
357
358 deinit:
359 libcharon_deinit();
360 libhydra_deinit();
361 library_deinit();
362 tkm_deinit();
363 return status;
364 }