]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/charon-systemd/charon-systemd.c
charon-systemd: Don't use atexit() to deinitialize the daemon
[thirdparty/strongswan.git] / src / charon-systemd / charon-systemd.c
CommitLineData
73ed38e7 1/*
0ca0fa71 2 * Copyright (C) 2006-2018 Tobias Brunner
e2d9f27c 3 * Copyright (C) 2005-2014 Martin Willi
73ed38e7
MW
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
1b671669 6 * HSR Hochschule fuer Technik Rapperswil
e2d9f27c 7 * Copyright (C) 2014 revosec AG
73ed38e7
MW
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>
e2d9f27c
MW
28
29/* won't make sense from our logging hook */
30#define SD_JOURNAL_SUPPRESS_LOCATION
73ed38e7 31#include <systemd/sd-daemon.h>
e2d9f27c 32#include <systemd/sd-journal.h>
73ed38e7 33
73ed38e7
MW
34#include <daemon.h>
35
36#include <library.h>
37#include <utils/backtrace.h>
38#include <threading/thread.h>
e2d9f27c 39#include <threading/rwlock.h>
73ed38e7 40
f3c83322
TB
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
73ed38e7
MW
52/**
53 * hook in library for debugging messages
54 */
55extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
56
57/**
58 * Logging hook for library logs, using stderr output
59 */
60static 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
e2d9f27c
MW
74typedef struct journal_logger_t journal_logger_t;
75
76/**
77 * Logger implementation using systemd-journal
78 */
79struct journal_logger_t {
80
81 /**
0ca0fa71 82 * Public interface
e2d9f27c 83 */
0ca0fa71 84 custom_logger_t public;
e2d9f27c
MW
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
97METHOD(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
162METHOD(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
0ca0fa71
TB
174METHOD(custom_logger_t, set_level, void,
175 journal_logger_t *this, debug_t group, level_t level)
e2d9f27c 176{
e2d9f27c 177 this->lock->write_lock(this->lock);
0ca0fa71 178 this->levels[group] = level;
e2d9f27c 179 this->lock->unlock(this->lock);
0ca0fa71 180}
e2d9f27c 181
0ca0fa71
TB
182METHOD(custom_logger_t, logger_destroy, void,
183 journal_logger_t *this)
184{
185 this->lock->destroy(this->lock);
186 free(this);
e2d9f27c
MW
187}
188
0ca0fa71 189static custom_logger_t *journal_logger_create(const char *name)
e2d9f27c
MW
190{
191 journal_logger_t *this;
192
0ca0fa71
TB
193 INIT(this,
194 .public = {
e2d9f27c
MW
195 .logger = {
196 .vlog = _vlog,
197 .get_level = _get_level,
198 },
0ca0fa71
TB
199 .set_level = _set_level,
200 .destroy = _logger_destroy,
201 },
202 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
203 );
204 return &this->public;
e2d9f27c
MW
205}
206
73ed38e7
MW
207/**
208 * Run the daemon and handle unix signals
209 */
210static int run()
211{
212 sigset_t set;
213
214 sigemptyset(&set);
ff22d53b 215 sigaddset(&set, SIGHUP);
73ed38e7
MW
216 sigaddset(&set, SIGTERM);
217 sigprocmask(SIG_BLOCK, &set, NULL);
218
219 sd_notify(0, "READY=1\n");
220
221 while (TRUE)
222 {
85814809 223 int sig;
73ed38e7 224
85814809
TB
225 sig = sigwaitinfo(&set, NULL);
226 if (sig == -1)
73ed38e7 227 {
88b85e02
TB
228 if (errno == EINTR)
229 { /* ignore signals we didn't wait for */
230 continue;
231 }
31956501 232 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
73ed38e7
MW
233 return SS_RC_INITIALIZATION_FAILED;
234 }
235 switch (sig)
236 {
ff22d53b
TB
237 case SIGHUP:
238 {
239 DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading "
240 "configuration");
241 if (lib->settings->load_files(lib->settings, lib->conf, FALSE))
242 {
9665686b 243 charon->load_loggers(charon);
ff22d53b
TB
244 lib->plugins->reload(lib->plugins, NULL);
245 }
246 else
247 {
248 DBG1(DBG_DMN, "reloading config failed, keeping old");
249 }
250 break;
251 }
73ed38e7
MW
252 case SIGTERM:
253 {
254 DBG1(DBG_DMN, "SIGTERM received, shutting down");
255 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
256 return 0;
257 }
73ed38e7
MW
258 }
259 }
260}
261
262/**
263 * lookup UID and GID
264 */
265static bool lookup_uid_gid()
266{
9c3c41f2 267 char *name;
f3c83322
TB
268
269 name = lib->settings->get_str(lib->settings, "%s.user", IPSEC_USER,
270 lib->ns);
271 if (name && !lib->caps->resolve_uid(lib->caps, name))
73ed38e7
MW
272 {
273 return FALSE;
274 }
f3c83322
TB
275 name = lib->settings->get_str(lib->settings, "%s.group", IPSEC_GROUP,
276 lib->ns);
277 if (name && !lib->caps->resolve_gid(lib->caps, name))
73ed38e7
MW
278 {
279 return FALSE;
280 }
73ed38e7
MW
281 return TRUE;
282}
283
284/**
285 * Handle SIGSEGV/SIGILL signals raised by threads
286 */
287static void segv_handler(int signal)
288{
289 backtrace_t *backtrace;
290
291 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
292 backtrace = backtrace_create(2);
293 backtrace->log(backtrace, NULL, TRUE);
294 backtrace->log(backtrace, stderr, TRUE);
295 backtrace->destroy(backtrace);
296
297 DBG1(DBG_DMN, "killing ourself, received critical signal");
298 abort();
299}
300
bc4e689d
TB
301/**
302 * Add namespace alias
303 */
304static void __attribute__ ((constructor))register_namespace()
305{
306 /* inherit settings from charon */
307 library_add_namespace("charon");
308}
309
0ca0fa71
TB
310/**
311 * Register journal logger
312 */
313static void __attribute__ ((constructor))register_logger()
314{
315 register_custom_logger("journal", journal_logger_create);
316}
317
73ed38e7
MW
318/**
319 * Main function, starts the daemon.
320 */
321int main(int argc, char *argv[])
322{
323 struct sigaction action;
324 struct utsname utsname;
cbe9e575 325 int status = SS_RC_INITIALIZATION_FAILED;
73ed38e7
MW
326
327 dbg = dbg_stderr;
328
329 if (uname(&utsname) != 0)
330 {
331 memset(&utsname, 0, sizeof(utsname));
332 }
333
334 sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
335 VERSION, utsname.sysname, utsname.release, utsname.machine);
336
337 atexit(library_deinit);
338 if (!library_init(NULL, "charon-systemd"))
339 {
340 sd_notifyf(0, "STATUS=libstrongswan initialization failed");
341 return SS_RC_INITIALIZATION_FAILED;
342 }
343 if (lib->integrity &&
344 !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0]))
345 {
346 sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
347 return SS_RC_INITIALIZATION_FAILED;
348 }
73ed38e7
MW
349 if (!libcharon_init())
350 {
351 sd_notifyf(0, "STATUS=libcharon initialization failed");
cbe9e575 352 goto error;
73ed38e7
MW
353 }
354 if (!lookup_uid_gid())
355 {
245979ab 356 sd_notifyf(0, "STATUS=unknown uid/gid");
cbe9e575 357 goto error;
73ed38e7 358 }
0ca0fa71
TB
359 /* we registered the journal logger as custom logger, which gets its
360 * settings from <ns>.customlog.journal, let it fallback to <ns>.journal */
361 lib->settings->add_fallback(lib->settings, "%s.customlog.journal",
362 "%s.journal", lib->ns);
363 /* load the journal logger by default */
364 lib->settings->set_default_str(lib->settings, "%s.journal.default", "1",
365 lib->ns);
73ed38e7 366
0ca0fa71 367 charon->load_loggers(charon);
e2d9f27c 368
d2f4345b
TB
369 if (!charon->initialize(charon,
370 lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns)))
73ed38e7
MW
371 {
372 sd_notifyf(0, "STATUS=charon initialization failed");
cbe9e575 373 goto error;
73ed38e7
MW
374 }
375 lib->plugins->status(lib->plugins, LEVEL_CTRL);
376
377 if (!lib->caps->drop(lib->caps))
378 {
379 sd_notifyf(0, "STATUS=dropping capabilities failed");
cbe9e575 380 goto error;
73ed38e7
MW
381 }
382
383 /* add handler for SEGV and ILL,
85814809 384 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
73ed38e7
MW
385 action.sa_handler = segv_handler;
386 action.sa_flags = 0;
387 sigemptyset(&action.sa_mask);
388 sigaddset(&action.sa_mask, SIGINT);
389 sigaddset(&action.sa_mask, SIGTERM);
390 sigaddset(&action.sa_mask, SIGHUP);
391 sigaction(SIGSEGV, &action, NULL);
392 sigaction(SIGILL, &action, NULL);
393 sigaction(SIGBUS, &action, NULL);
394 action.sa_handler = SIG_IGN;
395 sigaction(SIGPIPE, &action, NULL);
396
397 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
398
399 charon->start(charon);
400
401 sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
402 VERSION, utsname.sysname, utsname.release, utsname.machine);
403
cbe9e575
TB
404 status = run();
405
406error:
407 libcharon_deinit();
408 return status;
73ed38e7 409}