mem-cred: Add method to remove a private key with a specific fingerprint
[strongswan.git] / src / charon-systemd / charon-systemd.c
1 /*
2 * Copyright (C) 2006-2012 Tobias Brunner
3 * Copyright (C) 2005-2014 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
7 * Copyright (C) 2014 revosec AG
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 #include <signal.h>
21 #include <stdio.h>
22 #include <pthread.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/utsname.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 /* won't make sense from our logging hook */
30 #define SD_JOURNAL_SUPPRESS_LOCATION
31 #include <systemd/sd-daemon.h>
32 #include <systemd/sd-journal.h>
33
34 #include <daemon.h>
35
36 #include <library.h>
37 #include <utils/backtrace.h>
38 #include <threading/thread.h>
39 #include <threading/rwlock.h>
40
41 /**
42 * Default user and group
43 */
44 #ifndef IPSEC_USER
45 #define IPSEC_USER NULL
46 #endif
47
48 #ifndef IPSEC_GROUP
49 #define IPSEC_GROUP NULL
50 #endif
51
52 /**
53 * hook in library for debugging messages
54 */
55 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
56
57 /**
58 * Logging hook for library logs, using stderr output
59 */
60 static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
61 {
62 va_list args;
63
64 if (level <= 1)
65 {
66 va_start(args, fmt);
67 fprintf(stderr, "00[%N] ", debug_names, group);
68 vfprintf(stderr, fmt, args);
69 fprintf(stderr, "\n");
70 va_end(args);
71 }
72 }
73
74 typedef struct journal_logger_t journal_logger_t;
75
76 /**
77 * Logger implementation using systemd-journal
78 */
79 struct journal_logger_t {
80
81 /**
82 * Implements logger_t
83 */
84 logger_t logger;
85
86 /**
87 * Configured loglevels
88 */
89 level_t levels[DBG_MAX];
90
91 /**
92 * Lock for levels
93 */
94 rwlock_t *lock;
95 };
96
97 METHOD(logger_t, vlog, void,
98 journal_logger_t *this, debug_t group, level_t level, int thread,
99 ike_sa_t *ike_sa, const char *fmt, va_list args)
100 {
101 char buf[4096], *msg = buf;
102 ssize_t len;
103 va_list copy;
104
105 va_copy(copy, args);
106 len = vsnprintf(msg, sizeof(buf), fmt, copy);
107 va_end(copy);
108
109 if (len >= sizeof(buf))
110 {
111 len++;
112 msg = malloc(len);
113 va_copy(copy, args);
114 len = vsnprintf(msg, len, fmt, copy);
115 va_end(copy);
116 }
117 if (len > 0)
118 {
119 char unique[64] = "", name[256] = "";
120 int priority;
121
122 if (ike_sa)
123 {
124 snprintf(unique, sizeof(unique), "IKE_SA_UNIQUE_ID=%u",
125 ike_sa->get_unique_id(ike_sa));
126 if (ike_sa->get_peer_cfg(ike_sa))
127 {
128 snprintf(name, sizeof(name), "IKE_SA_NAME=%s",
129 ike_sa->get_name(ike_sa));
130 }
131 }
132 switch (level)
133 {
134 case LEVEL_AUDIT:
135 priority = LOG_NOTICE;
136 break;
137 case LEVEL_CTRL:
138 priority = LOG_INFO;
139 break;
140 default:
141 priority = LOG_DEBUG;
142 break;
143 }
144 sd_journal_send(
145 "MESSAGE=%s", msg,
146 "MESSAGE_ID=57d2708c-d607-43bd-8c39-66bf%.8x",
147 chunk_hash_static(chunk_from_str((char*)fmt)),
148 "PRIORITY=%d", priority,
149 "GROUP=%N", debug_names, group,
150 "LEVEL=%d", level,
151 "THREAD=%d", thread,
152 unique[0] ? unique : NULL,
153 name[0] ? name : NULL,
154 NULL);
155 }
156 if (msg != buf)
157 {
158 free(msg);
159 }
160 }
161
162 METHOD(logger_t, get_level, level_t,
163 journal_logger_t *this, debug_t group)
164 {
165 level_t level;
166
167 this->lock->read_lock(this->lock);
168 level = this->levels[group];
169 this->lock->unlock(this->lock);
170
171 return level;
172 }
173
174 /**
175 * Reload journal logger configuration
176 */
177 CALLBACK(journal_reload, bool,
178 journal_logger_t **journal)
179 {
180 journal_logger_t *this = *journal;
181 debug_t group;
182 level_t def;
183
184 def = lib->settings->get_int(lib->settings, "%s.journal.default", 1, lib->ns);
185
186 this->lock->write_lock(this->lock);
187 for (group = 0; group < DBG_MAX; group++)
188 {
189 this->levels[group] =
190 lib->settings->get_int(lib->settings,
191 "%s.journal.%N", def, lib->ns, debug_lower_names, group);
192 }
193 this->lock->unlock(this->lock);
194
195 charon->bus->add_logger(charon->bus, &this->logger);
196
197 return TRUE;
198 }
199
200 /**
201 * Initialize/deinitialize journal logger
202 */
203 static bool journal_register(void *plugin, plugin_feature_t *feature,
204 bool reg, journal_logger_t **logger)
205 {
206 journal_logger_t *this;
207
208 if (reg)
209 {
210 INIT(this,
211 .logger = {
212 .vlog = _vlog,
213 .get_level = _get_level,
214 },
215 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
216 );
217
218 journal_reload(&this);
219
220 *logger = this;
221 return TRUE;
222 }
223 else
224 {
225 this = *logger;
226
227 charon->bus->remove_logger(charon->bus, &this->logger);
228
229 this->lock->destroy(this->lock);
230 free(this);
231
232 return TRUE;
233 }
234 }
235
236 /**
237 * Run the daemon and handle unix signals
238 */
239 static int run()
240 {
241 sigset_t set;
242
243 sigemptyset(&set);
244 sigaddset(&set, SIGHUP);
245 sigaddset(&set, SIGTERM);
246 sigprocmask(SIG_BLOCK, &set, NULL);
247
248 sd_notify(0, "READY=1\n");
249
250 while (TRUE)
251 {
252 int sig;
253
254 sig = sigwaitinfo(&set, NULL);
255 if (sig == -1)
256 {
257 if (errno == EINTR)
258 { /* ignore signals we didn't wait for */
259 continue;
260 }
261 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
262 return SS_RC_INITIALIZATION_FAILED;
263 }
264 switch (sig)
265 {
266 case SIGHUP:
267 {
268 DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading "
269 "configuration");
270 if (lib->settings->load_files(lib->settings, lib->conf, FALSE))
271 {
272 charon->load_loggers(charon);
273 lib->plugins->reload(lib->plugins, NULL);
274 }
275 else
276 {
277 DBG1(DBG_DMN, "reloading config failed, keeping old");
278 }
279 break;
280 }
281 case SIGTERM:
282 {
283 DBG1(DBG_DMN, "SIGTERM received, shutting down");
284 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
285 return 0;
286 }
287 }
288 }
289 }
290
291 /**
292 * lookup UID and GID
293 */
294 static bool lookup_uid_gid()
295 {
296 char *name;
297
298 name = lib->settings->get_str(lib->settings, "%s.user", IPSEC_USER,
299 lib->ns);
300 if (name && !lib->caps->resolve_uid(lib->caps, name))
301 {
302 return FALSE;
303 }
304 name = lib->settings->get_str(lib->settings, "%s.group", IPSEC_GROUP,
305 lib->ns);
306 if (name && !lib->caps->resolve_gid(lib->caps, name))
307 {
308 return FALSE;
309 }
310 return TRUE;
311 }
312
313 /**
314 * Handle SIGSEGV/SIGILL signals raised by threads
315 */
316 static void segv_handler(int signal)
317 {
318 backtrace_t *backtrace;
319
320 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
321 backtrace = backtrace_create(2);
322 backtrace->log(backtrace, NULL, TRUE);
323 backtrace->log(backtrace, stderr, TRUE);
324 backtrace->destroy(backtrace);
325
326 DBG1(DBG_DMN, "killing ourself, received critical signal");
327 abort();
328 }
329
330 /**
331 * The journal logger instance
332 */
333 static journal_logger_t *journal;
334
335 /**
336 * Journal static features
337 */
338 static plugin_feature_t features[] = {
339 PLUGIN_CALLBACK((plugin_feature_callback_t)journal_register, &journal),
340 PLUGIN_PROVIDE(CUSTOM, "systemd-journal"),
341 };
342
343 /**
344 * Add namespace alias
345 */
346 static void __attribute__ ((constructor))register_namespace()
347 {
348 /* inherit settings from charon */
349 library_add_namespace("charon");
350 }
351
352 /**
353 * Main function, starts the daemon.
354 */
355 int main(int argc, char *argv[])
356 {
357 struct sigaction action;
358 struct utsname utsname;
359
360 dbg = dbg_stderr;
361
362 if (uname(&utsname) != 0)
363 {
364 memset(&utsname, 0, sizeof(utsname));
365 }
366
367 sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
368 VERSION, utsname.sysname, utsname.release, utsname.machine);
369
370 atexit(library_deinit);
371 if (!library_init(NULL, "charon-systemd"))
372 {
373 sd_notifyf(0, "STATUS=libstrongswan initialization failed");
374 return SS_RC_INITIALIZATION_FAILED;
375 }
376 if (lib->integrity &&
377 !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0]))
378 {
379 sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
380 return SS_RC_INITIALIZATION_FAILED;
381 }
382 atexit(libcharon_deinit);
383 if (!libcharon_init())
384 {
385 sd_notifyf(0, "STATUS=libcharon initialization failed");
386 return SS_RC_INITIALIZATION_FAILED;
387 }
388 if (!lookup_uid_gid())
389 {
390 sd_notifyf(0, "STATUS=unknown uid/gid");
391 return SS_RC_INITIALIZATION_FAILED;
392 }
393 charon->load_loggers(charon);
394
395 lib->plugins->add_static_features(lib->plugins, lib->ns, features,
396 countof(features), TRUE, journal_reload, &journal);
397
398 if (!charon->initialize(charon,
399 lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns)))
400 {
401 sd_notifyf(0, "STATUS=charon initialization failed");
402 return SS_RC_INITIALIZATION_FAILED;
403 }
404 lib->plugins->status(lib->plugins, LEVEL_CTRL);
405
406 if (!lib->caps->drop(lib->caps))
407 {
408 sd_notifyf(0, "STATUS=dropping capabilities failed");
409 return SS_RC_INITIALIZATION_FAILED;
410 }
411
412 /* add handler for SEGV and ILL,
413 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
414 action.sa_handler = segv_handler;
415 action.sa_flags = 0;
416 sigemptyset(&action.sa_mask);
417 sigaddset(&action.sa_mask, SIGINT);
418 sigaddset(&action.sa_mask, SIGTERM);
419 sigaddset(&action.sa_mask, SIGHUP);
420 sigaction(SIGSEGV, &action, NULL);
421 sigaction(SIGILL, &action, NULL);
422 sigaction(SIGBUS, &action, NULL);
423 action.sa_handler = SIG_IGN;
424 sigaction(SIGPIPE, &action, NULL);
425
426 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
427
428 charon->start(charon);
429
430 sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
431 VERSION, utsname.sysname, utsname.release, utsname.machine);
432
433 return run();
434 }