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