systemd: Provide a charon-systemd daemon targeting full systemd integration
[strongswan.git] / src / charon-systemd / charon-systemd.c
1 /*
2 * Copyright (C) 2006-2012 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include <signal.h>
20 #include <stdio.h>
21 #include <pthread.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/utsname.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <systemd/sd-daemon.h>
28
29 #include <hydra.h>
30 #include <daemon.h>
31
32 #include <library.h>
33 #include <utils/backtrace.h>
34 #include <threading/thread.h>
35
36 /**
37 * hook in library for debugging messages
38 */
39 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
40
41 /**
42 * Logging hook for library logs, using stderr output
43 */
44 static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
45 {
46 va_list args;
47
48 if (level <= 1)
49 {
50 va_start(args, fmt);
51 fprintf(stderr, "00[%N] ", debug_names, group);
52 vfprintf(stderr, fmt, args);
53 fprintf(stderr, "\n");
54 va_end(args);
55 }
56 }
57
58 /**
59 * Run the daemon and handle unix signals
60 */
61 static int run()
62 {
63 sigset_t set;
64
65 sigemptyset(&set);
66 sigaddset(&set, SIGTERM);
67 sigprocmask(SIG_BLOCK, &set, NULL);
68
69 sd_notify(0, "READY=1\n");
70
71 while (TRUE)
72 {
73 int sig, error;
74
75 error = sigwait(&set, &sig);
76 if (error)
77 {
78 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(error));
79 return SS_RC_INITIALIZATION_FAILED;
80 }
81 switch (sig)
82 {
83 case SIGTERM:
84 {
85 DBG1(DBG_DMN, "SIGTERM received, shutting down");
86 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
87 return 0;
88 }
89 default:
90 {
91 DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
92 break;
93 }
94 }
95 }
96 }
97
98 /**
99 * lookup UID and GID
100 */
101 static bool lookup_uid_gid()
102 {
103 #ifdef IPSEC_USER
104 if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER))
105 {
106 return FALSE;
107 }
108 #endif /* IPSEC_USER */
109 #ifdef IPSEC_GROUP
110 if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP))
111 {
112 return FALSE;
113 }
114 #endif /* IPSEC_GROUP */
115 return TRUE;
116 }
117
118 /**
119 * Handle SIGSEGV/SIGILL signals raised by threads
120 */
121 static void segv_handler(int signal)
122 {
123 backtrace_t *backtrace;
124
125 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
126 backtrace = backtrace_create(2);
127 backtrace->log(backtrace, NULL, TRUE);
128 backtrace->log(backtrace, stderr, TRUE);
129 backtrace->destroy(backtrace);
130
131 DBG1(DBG_DMN, "killing ourself, received critical signal");
132 abort();
133 }
134
135 /**
136 * Main function, starts the daemon.
137 */
138 int main(int argc, char *argv[])
139 {
140 struct sigaction action;
141 struct utsname utsname;
142
143 dbg = dbg_stderr;
144
145 if (uname(&utsname) != 0)
146 {
147 memset(&utsname, 0, sizeof(utsname));
148 }
149
150 sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s",
151 VERSION, utsname.sysname, utsname.release, utsname.machine);
152
153 atexit(library_deinit);
154 if (!library_init(NULL, "charon-systemd"))
155 {
156 sd_notifyf(0, "STATUS=libstrongswan initialization failed");
157 return SS_RC_INITIALIZATION_FAILED;
158 }
159 if (lib->integrity &&
160 !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0]))
161 {
162 sd_notifyf(0, "STATUS=integrity check of charon-systemd failed");
163 return SS_RC_INITIALIZATION_FAILED;
164 }
165 atexit(libhydra_deinit);
166 if (!libhydra_init())
167 {
168 sd_notifyf(0, "STATUS=libhydra initialization failed");
169 return SS_RC_INITIALIZATION_FAILED;
170 }
171 atexit(libcharon_deinit);
172 if (!libcharon_init())
173 {
174 sd_notifyf(0, "STATUS=libcharon initialization failed");
175 return SS_RC_INITIALIZATION_FAILED;
176 }
177 if (!lookup_uid_gid())
178 {
179 sd_notifyf(0, "STATUS=unkown uid/gid");
180 return SS_RC_INITIALIZATION_FAILED;
181 }
182 charon->load_loggers(charon, NULL, FALSE);
183
184 if (!charon->initialize(charon, PLUGINS))
185 {
186 sd_notifyf(0, "STATUS=charon initialization failed");
187 return SS_RC_INITIALIZATION_FAILED;
188 }
189 lib->plugins->status(lib->plugins, LEVEL_CTRL);
190
191 if (!lib->caps->drop(lib->caps))
192 {
193 sd_notifyf(0, "STATUS=dropping capabilities failed");
194 return SS_RC_INITIALIZATION_FAILED;
195 }
196
197 /* add handler for SEGV and ILL,
198 * INT, TERM and HUP are handled by sigwait() in run() */
199 action.sa_handler = segv_handler;
200 action.sa_flags = 0;
201 sigemptyset(&action.sa_mask);
202 sigaddset(&action.sa_mask, SIGINT);
203 sigaddset(&action.sa_mask, SIGTERM);
204 sigaddset(&action.sa_mask, SIGHUP);
205 sigaction(SIGSEGV, &action, NULL);
206 sigaction(SIGILL, &action, NULL);
207 sigaction(SIGBUS, &action, NULL);
208 action.sa_handler = SIG_IGN;
209 sigaction(SIGPIPE, &action, NULL);
210
211 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
212
213 charon->start(charon);
214
215 sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s",
216 VERSION, utsname.sysname, utsname.release, utsname.machine);
217
218 return run();
219 }