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