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