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