2 * Copyright (C) 2006-2018 Tobias Brunner
3 * Copyright (C) 2005-2014 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * HSR Hochschule fuer Technik Rapperswil
7 * Copyright (C) 2014 revosec AG
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>.
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
24 #include <sys/types.h>
25 #include <sys/utsname.h>
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>
37 #include <utils/backtrace.h>
38 #include <threading/thread.h>
39 #include <threading/rwlock.h>
42 * Default user and group
45 #define IPSEC_USER NULL
49 #define IPSEC_GROUP NULL
53 * hook in library for debugging messages
55 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
58 * Logging hook for library logs, using stderr output
60 static void dbg_stderr(debug_t group
, level_t level
, char *fmt
, ...)
67 fprintf(stderr
, "00[%N] ", debug_names
, group
);
68 vfprintf(stderr
, fmt
, args
);
69 fprintf(stderr
, "\n");
74 typedef struct journal_logger_t journal_logger_t
;
77 * Logger implementation using systemd-journal
79 struct journal_logger_t
{
84 custom_logger_t
public;
87 * Configured loglevels
89 level_t levels
[DBG_MAX
];
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
)
101 char buf
[4096], *msg
= buf
;
106 len
= vsnprintf(msg
, sizeof(buf
), fmt
, copy
);
109 if (len
>= sizeof(buf
))
114 len
= vsnprintf(msg
, len
, fmt
, copy
);
119 char unique
[64] = "", name
[256] = "";
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
))
128 snprintf(name
, sizeof(name
), "IKE_SA_NAME=%s",
129 ike_sa
->get_name(ike_sa
));
135 priority
= LOG_NOTICE
;
141 priority
= LOG_DEBUG
;
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
,
152 unique
[0] ? unique
: NULL
,
153 name
[0] ? name
: NULL
,
162 METHOD(logger_t
, get_level
, level_t
,
163 journal_logger_t
*this, debug_t group
)
167 this->lock
->read_lock(this->lock
);
168 level
= this->levels
[group
];
169 this->lock
->unlock(this->lock
);
174 METHOD(custom_logger_t
, set_level
, void,
175 journal_logger_t
*this, debug_t group
, level_t level
)
177 this->lock
->write_lock(this->lock
);
178 this->levels
[group
] = level
;
179 this->lock
->unlock(this->lock
);
182 METHOD(custom_logger_t
, logger_destroy
, void,
183 journal_logger_t
*this)
185 this->lock
->destroy(this->lock
);
189 static custom_logger_t
*journal_logger_create(const char *name
)
191 journal_logger_t
*this;
197 .get_level
= _get_level
,
199 .set_level
= _set_level
,
200 .destroy
= _logger_destroy
,
202 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
204 return &this->public;
208 * Run the daemon and handle unix signals
215 sigaddset(&set
, SIGHUP
);
216 sigaddset(&set
, SIGTERM
);
217 sigprocmask(SIG_BLOCK
, &set
, NULL
);
219 sd_notify(0, "READY=1\n");
225 sig
= sigwaitinfo(&set
, NULL
);
229 { /* ignore signals we didn't wait for */
232 DBG1(DBG_DMN
, "waiting for signal failed: %s", strerror(errno
));
233 return SS_RC_INITIALIZATION_FAILED
;
239 DBG1(DBG_DMN
, "signal of type SIGHUP received. Reloading "
241 if (lib
->settings
->load_files(lib
->settings
, lib
->conf
, FALSE
))
243 charon
->load_loggers(charon
);
244 lib
->plugins
->reload(lib
->plugins
, NULL
);
248 DBG1(DBG_DMN
, "reloading config failed, keeping old");
254 DBG1(DBG_DMN
, "SIGTERM received, shutting down");
255 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
265 static bool lookup_uid_gid()
269 name
= lib
->settings
->get_str(lib
->settings
, "%s.user", IPSEC_USER
,
271 if (name
&& !lib
->caps
->resolve_uid(lib
->caps
, name
))
275 name
= lib
->settings
->get_str(lib
->settings
, "%s.group", IPSEC_GROUP
,
277 if (name
&& !lib
->caps
->resolve_gid(lib
->caps
, name
))
285 * Handle SIGSEGV/SIGILL signals raised by threads
287 static void segv_handler(int signal
)
289 backtrace_t
*backtrace
;
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
);
297 DBG1(DBG_DMN
, "killing ourself, received critical signal");
302 * Add namespace alias
304 static void __attribute__ ((constructor
))register_namespace()
306 /* inherit settings from charon */
307 library_add_namespace("charon");
311 * Register journal logger
313 static void __attribute__ ((constructor
))register_logger()
315 register_custom_logger("journal", journal_logger_create
);
319 * Main function, starts the daemon.
321 int main(int argc
, char *argv
[])
323 struct sigaction action
;
324 struct utsname utsname
;
328 if (uname(&utsname
) != 0)
330 memset(&utsname
, 0, sizeof(utsname
));
333 sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
334 VERSION
, utsname
.sysname
, utsname
.release
, utsname
.machine
);
336 atexit(library_deinit
);
337 if (!library_init(NULL
, "charon-systemd"))
339 sd_notifyf(0, "STATUS=libstrongswan initialization failed");
340 return SS_RC_INITIALIZATION_FAILED
;
342 if (lib
->integrity
&&
343 !lib
->integrity
->check_file(lib
->integrity
, "charon-systemd", argv
[0]))
345 sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
346 return SS_RC_INITIALIZATION_FAILED
;
348 atexit(libcharon_deinit
);
349 if (!libcharon_init())
351 sd_notifyf(0, "STATUS=libcharon initialization failed");
352 return SS_RC_INITIALIZATION_FAILED
;
354 if (!lookup_uid_gid())
356 sd_notifyf(0, "STATUS=unknown uid/gid");
357 return SS_RC_INITIALIZATION_FAILED
;
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",
367 charon
->load_loggers(charon
);
369 if (!charon
->initialize(charon
,
370 lib
->settings
->get_str(lib
->settings
, "%s.load", PLUGINS
, lib
->ns
)))
372 sd_notifyf(0, "STATUS=charon initialization failed");
373 return SS_RC_INITIALIZATION_FAILED
;
375 lib
->plugins
->status(lib
->plugins
, LEVEL_CTRL
);
377 if (!lib
->caps
->drop(lib
->caps
))
379 sd_notifyf(0, "STATUS=dropping capabilities failed");
380 return SS_RC_INITIALIZATION_FAILED
;
383 /* add handler for SEGV and ILL,
384 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
385 action
.sa_handler
= segv_handler
;
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
);
397 pthread_sigmask(SIG_SETMASK
, &action
.sa_mask
, NULL
);
399 charon
->start(charon
);
401 sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
402 VERSION
, utsname
.sysname
, utsname
.release
, utsname
.machine
);