]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/charon-systemd/charon-systemd.c
Update copyright headers after acquisition by secunet
[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
19ef2aec
TB
6 *
7 * Copyright (C) secunet Security Networks 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
fe3ae5be 284#ifndef DISABLE_SIGNAL_HANDLER
73ed38e7
MW
285/**
286 * Handle SIGSEGV/SIGILL signals raised by threads
287 */
288static void segv_handler(int signal)
289{
290 backtrace_t *backtrace;
291
292 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
293 backtrace = backtrace_create(2);
294 backtrace->log(backtrace, NULL, TRUE);
295 backtrace->log(backtrace, stderr, TRUE);
296 backtrace->destroy(backtrace);
297
298 DBG1(DBG_DMN, "killing ourself, received critical signal");
299 abort();
300}
fe3ae5be 301#endif /* DISABLE_SIGNAL_HANDLER */
73ed38e7 302
bc4e689d
TB
303/**
304 * Add namespace alias
305 */
306static void __attribute__ ((constructor))register_namespace()
307{
308 /* inherit settings from charon */
309 library_add_namespace("charon");
310}
311
0ca0fa71
TB
312/**
313 * Register journal logger
314 */
315static void __attribute__ ((constructor))register_logger()
316{
317 register_custom_logger("journal", journal_logger_create);
318}
319
73ed38e7
MW
320/**
321 * Main function, starts the daemon.
322 */
323int main(int argc, char *argv[])
324{
325 struct sigaction action;
326 struct utsname utsname;
cbe9e575 327 int status = SS_RC_INITIALIZATION_FAILED;
73ed38e7
MW
328
329 dbg = dbg_stderr;
330
331 if (uname(&utsname) != 0)
332 {
333 memset(&utsname, 0, sizeof(utsname));
334 }
335
336 sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
337 VERSION, utsname.sysname, utsname.release, utsname.machine);
338
339 atexit(library_deinit);
340 if (!library_init(NULL, "charon-systemd"))
341 {
342 sd_notifyf(0, "STATUS=libstrongswan initialization failed");
343 return SS_RC_INITIALIZATION_FAILED;
344 }
345 if (lib->integrity &&
346 !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0]))
347 {
348 sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
349 return SS_RC_INITIALIZATION_FAILED;
350 }
73ed38e7
MW
351 if (!libcharon_init())
352 {
353 sd_notifyf(0, "STATUS=libcharon initialization failed");
cbe9e575 354 goto error;
73ed38e7
MW
355 }
356 if (!lookup_uid_gid())
357 {
245979ab 358 sd_notifyf(0, "STATUS=unknown uid/gid");
cbe9e575 359 goto error;
73ed38e7 360 }
0ca0fa71
TB
361 /* we registered the journal logger as custom logger, which gets its
362 * settings from <ns>.customlog.journal, let it fallback to <ns>.journal */
363 lib->settings->add_fallback(lib->settings, "%s.customlog.journal",
364 "%s.journal", lib->ns);
365 /* load the journal logger by default */
366 lib->settings->set_default_str(lib->settings, "%s.journal.default", "1",
367 lib->ns);
73ed38e7 368
0ca0fa71 369 charon->load_loggers(charon);
e2d9f27c 370
d2f4345b
TB
371 if (!charon->initialize(charon,
372 lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns)))
73ed38e7
MW
373 {
374 sd_notifyf(0, "STATUS=charon initialization failed");
cbe9e575 375 goto error;
73ed38e7
MW
376 }
377 lib->plugins->status(lib->plugins, LEVEL_CTRL);
378
379 if (!lib->caps->drop(lib->caps))
380 {
381 sd_notifyf(0, "STATUS=dropping capabilities failed");
cbe9e575 382 goto error;
73ed38e7
MW
383 }
384
fe3ae5be 385 /* add handler for fatal signals,
85814809 386 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
73ed38e7
MW
387 action.sa_flags = 0;
388 sigemptyset(&action.sa_mask);
389 sigaddset(&action.sa_mask, SIGINT);
390 sigaddset(&action.sa_mask, SIGTERM);
391 sigaddset(&action.sa_mask, SIGHUP);
fe3ae5be
SM
392
393 /* optionally let the external system handle fatal signals */
394#ifndef DISABLE_SIGNAL_HANDLER
395 action.sa_handler = segv_handler;
73ed38e7
MW
396 sigaction(SIGSEGV, &action, NULL);
397 sigaction(SIGILL, &action, NULL);
398 sigaction(SIGBUS, &action, NULL);
fe3ae5be
SM
399#endif /* DISABLE_SIGNAL_HANDLER */
400
73ed38e7
MW
401 action.sa_handler = SIG_IGN;
402 sigaction(SIGPIPE, &action, NULL);
403
404 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
405
406 charon->start(charon);
407
408 sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
409 VERSION, utsname.sysname, utsname.release, utsname.machine);
410
cbe9e575
TB
411 status = run();
412
413error:
414 libcharon_deinit();
415 return status;
73ed38e7 416}