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