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