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