]>
Commit | Line | Data |
---|---|---|
349fa528 | 1 | /* |
1b4d97db | 2 | * Copyright (C) 2006-2017 Tobias Brunner |
349fa528 TB |
3 | * Copyright (C) 2005-2009 Martin Willi |
4 | * Copyright (C) 2006 Daniel Roethlisberger | |
5 | * Copyright (C) 2005 Jan Hutter | |
19ef2aec TB |
6 | * |
7 | * Copyright (C) secunet Security Networks AG | |
349fa528 TB |
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 <stdio.h> | |
349fa528 | 21 | #include <signal.h> |
349fa528 TB |
22 | #include <pthread.h> |
23 | #include <sys/stat.h> | |
24 | #include <sys/types.h> | |
b8e17eb3 | 25 | #include <sys/utsname.h> |
349fa528 TB |
26 | #include <unistd.h> |
27 | #include <getopt.h> | |
866514c7 MW |
28 | #include <fcntl.h> |
29 | #include <errno.h> | |
349fa528 TB |
30 | |
31 | #include <daemon.h> | |
32 | ||
33 | #include <library.h> | |
34 | #include <utils/backtrace.h> | |
35 | #include <threading/thread.h> | |
36 | ||
404960e5 | 37 | #ifdef ANDROID |
bdbbab35 | 38 | #include <private/android_filesystem_config.h> /* for AID_VPN */ |
404960e5 TB |
39 | #endif |
40 | ||
349fa528 TB |
41 | /** |
42 | * PID file, in which charon stores its process id | |
43 | */ | |
44 | #define PID_FILE IPSEC_PIDDIR "/charon.pid" | |
45 | ||
68b7448e TB |
46 | /** |
47 | * Default user and group | |
48 | */ | |
49 | #ifndef IPSEC_USER | |
50 | #define IPSEC_USER NULL | |
51 | #endif | |
52 | ||
53 | #ifndef IPSEC_GROUP | |
54 | #define IPSEC_GROUP NULL | |
55 | #endif | |
56 | ||
b02a03a5 TB |
57 | /** |
58 | * Global reference to PID file (required to truncate, if undeletable) | |
59 | */ | |
60 | static FILE *pidfile = NULL; | |
61 | ||
349fa528 TB |
62 | /** |
63 | * hook in library for debugging messages | |
64 | */ | |
9ed6341d | 65 | extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); |
349fa528 TB |
66 | |
67 | /** | |
68 | * Logging hook for library logs, using stderr output | |
69 | */ | |
9ed6341d | 70 | static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) |
349fa528 TB |
71 | { |
72 | va_list args; | |
73 | ||
74 | if (level <= 1) | |
75 | { | |
76 | va_start(args, fmt); | |
9ed6341d | 77 | fprintf(stderr, "00[%N] ", debug_names, group); |
349fa528 TB |
78 | vfprintf(stderr, fmt, args); |
79 | fprintf(stderr, "\n"); | |
80 | va_end(args); | |
81 | } | |
82 | } | |
83 | ||
84 | /** | |
85 | * Run the daemon and handle unix signals | |
86 | */ | |
87 | static void run() | |
88 | { | |
89 | sigset_t set; | |
90 | ||
88b85e02 | 91 | /* handle SIGINT, SIGHUP and SIGTERM in this handler */ |
349fa528 TB |
92 | sigemptyset(&set); |
93 | sigaddset(&set, SIGINT); | |
94 | sigaddset(&set, SIGHUP); | |
95 | sigaddset(&set, SIGTERM); | |
96 | sigprocmask(SIG_BLOCK, &set, NULL); | |
97 | ||
98 | while (TRUE) | |
99 | { | |
100 | int sig; | |
349fa528 | 101 | |
85814809 TB |
102 | sig = sigwaitinfo(&set, NULL); |
103 | if (sig == -1) | |
349fa528 | 104 | { |
88b85e02 TB |
105 | if (errno == EINTR) |
106 | { /* ignore signals we didn't wait for */ | |
107 | continue; | |
108 | } | |
85814809 | 109 | DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno)); |
349fa528 TB |
110 | return; |
111 | } | |
112 | switch (sig) | |
113 | { | |
114 | case SIGHUP: | |
115 | { | |
3b71d3d0 MW |
116 | DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " |
117 | "configuration"); | |
68da3bad | 118 | if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) |
3b71d3d0 | 119 | { |
9665686b | 120 | charon->load_loggers(charon); |
3b71d3d0 MW |
121 | lib->plugins->reload(lib->plugins, NULL); |
122 | } | |
123 | else | |
124 | { | |
125 | DBG1(DBG_DMN, "reloading config failed, keeping old"); | |
126 | } | |
349fa528 TB |
127 | break; |
128 | } | |
129 | case SIGINT: | |
349fa528 TB |
130 | case SIGTERM: |
131 | { | |
040608a4 TB |
132 | DBG1(DBG_DMN, "%s received, shutting down", |
133 | sig == SIGINT ? "SIGINT" : "SIGTERM"); | |
349fa528 TB |
134 | charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); |
135 | return; | |
136 | } | |
349fa528 TB |
137 | } |
138 | } | |
139 | } | |
140 | ||
349fa528 TB |
141 | /** |
142 | * lookup UID and GID | |
143 | */ | |
144 | static bool lookup_uid_gid() | |
145 | { | |
68b7448e TB |
146 | char *name; |
147 | ||
148 | name = lib->settings->get_str(lib->settings, "charon.user", IPSEC_USER); | |
149 | if (name && !lib->caps->resolve_uid(lib->caps, name)) | |
349fa528 | 150 | { |
0619ddfa | 151 | return FALSE; |
349fa528 | 152 | } |
68b7448e TB |
153 | name = lib->settings->get_str(lib->settings, "charon.group", IPSEC_GROUP); |
154 | if (name && !lib->caps->resolve_gid(lib->caps, name)) | |
349fa528 | 155 | { |
0619ddfa | 156 | return FALSE; |
349fa528 | 157 | } |
404960e5 | 158 | #ifdef ANDROID |
a2eb5817 | 159 | lib->caps->set_uid(lib->caps, AID_VPN); |
349fa528 TB |
160 | #endif |
161 | return TRUE; | |
162 | } | |
163 | ||
164 | /** | |
165 | * Handle SIGSEGV/SIGILL signals raised by threads | |
166 | */ | |
fe3ae5be | 167 | #ifndef DISABLE_SIGNAL_HANDLER |
349fa528 TB |
168 | static void segv_handler(int signal) |
169 | { | |
170 | backtrace_t *backtrace; | |
171 | ||
172 | DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); | |
173 | backtrace = backtrace_create(2); | |
1f69412b | 174 | backtrace->log(backtrace, NULL, TRUE); |
091d1780 | 175 | backtrace->log(backtrace, stderr, TRUE); |
349fa528 TB |
176 | backtrace->destroy(backtrace); |
177 | ||
178 | DBG1(DBG_DMN, "killing ourself, received critical signal"); | |
179 | abort(); | |
180 | } | |
fe3ae5be | 181 | #endif /* DISABLE_SIGNAL_HANDLER */ |
349fa528 TB |
182 | |
183 | /** | |
184 | * Check/create PID file, return TRUE if already running | |
185 | */ | |
186 | static bool check_pidfile() | |
187 | { | |
188 | struct stat stb; | |
349fa528 TB |
189 | |
190 | if (stat(PID_FILE, &stb) == 0) | |
191 | { | |
b02a03a5 TB |
192 | pidfile = fopen(PID_FILE, "r"); |
193 | if (pidfile) | |
349fa528 TB |
194 | { |
195 | char buf[64]; | |
196 | pid_t pid = 0; | |
197 | ||
198 | memset(buf, 0, sizeof(buf)); | |
b02a03a5 | 199 | if (fread(buf, 1, sizeof(buf), pidfile)) |
349fa528 | 200 | { |
6d36f8b6 | 201 | buf[sizeof(buf) - 1] = '\0'; |
349fa528 TB |
202 | pid = atoi(buf); |
203 | } | |
b02a03a5 | 204 | fclose(pidfile); |
1b4d97db | 205 | pidfile = NULL; |
9655a3ff | 206 | if (pid && pid != getpid() && kill(pid, 0) == 0) |
1b4d97db TB |
207 | { |
208 | DBG1(DBG_DMN, "charon already running ('"PID_FILE"' exists)"); | |
349fa528 TB |
209 | return TRUE; |
210 | } | |
211 | } | |
212 | DBG1(DBG_DMN, "removing pidfile '"PID_FILE"', process not running"); | |
213 | unlink(PID_FILE); | |
214 | } | |
215 | ||
216 | /* create new pidfile */ | |
b02a03a5 TB |
217 | pidfile = fopen(PID_FILE, "w"); |
218 | if (pidfile) | |
349fa528 | 219 | { |
866514c7 MW |
220 | int fd; |
221 | ||
222 | fd = fileno(pidfile); | |
42353849 TB |
223 | if (fd == -1) |
224 | { | |
225 | DBG1(DBG_DMN, "unable to determine fd for '"PID_FILE"'"); | |
226 | return TRUE; | |
227 | } | |
228 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) | |
866514c7 MW |
229 | { |
230 | DBG1(DBG_LIB, "setting FD_CLOEXEC for '"PID_FILE"' failed: %s", | |
231 | strerror(errno)); | |
232 | } | |
4f1d2f2b MM |
233 | /* Only change owner of the pidfile if we have CAP_CHOWN. Otherwise, |
234 | * attempt to change group of pidfile to group under which charon | |
235 | * runs after dropping caps. This requires the user that charon | |
236 | * starts as to: | |
237 | * a) Have write access to the socket dir. | |
238 | * b) Belong to the group that charon will run under after dropping | |
239 | * caps. */ | |
b9fcc619 MM |
240 | if (lib->caps->check(lib->caps, CAP_CHOWN)) |
241 | { | |
242 | ignore_result(fchown(fd, | |
243 | lib->caps->get_uid(lib->caps), | |
244 | lib->caps->get_gid(lib->caps))); | |
245 | } | |
4f1d2f2b MM |
246 | else |
247 | { | |
248 | ignore_result(fchown(fd, -1, | |
249 | lib->caps->get_gid(lib->caps))); | |
250 | } | |
b02a03a5 TB |
251 | fprintf(pidfile, "%d\n", getpid()); |
252 | fflush(pidfile); | |
1b4d97db TB |
253 | return FALSE; |
254 | } | |
255 | else | |
256 | { | |
257 | DBG1(DBG_DMN, "unable to create pidfile '"PID_FILE"'"); | |
258 | return TRUE; | |
349fa528 | 259 | } |
349fa528 TB |
260 | } |
261 | ||
b02a03a5 TB |
262 | /** |
263 | * Delete/truncate the PID file | |
264 | */ | |
265 | static void unlink_pidfile() | |
266 | { | |
267 | /* because unlinking the PID file may fail, we truncate it to ensure the | |
268 | * daemon can be properly restarted. one probable cause for this is the | |
269 | * combination of not running as root and the effective user lacking | |
270 | * permissions on the parent dir(s) of the PID file */ | |
271 | if (pidfile) | |
272 | { | |
4f9b82bc | 273 | ignore_result(ftruncate(fileno(pidfile), 0)); |
b02a03a5 | 274 | fclose(pidfile); |
1b4d97db | 275 | unlink(PID_FILE); |
b02a03a5 | 276 | } |
b02a03a5 TB |
277 | } |
278 | ||
349fa528 TB |
279 | /** |
280 | * print command line usage and exit | |
281 | */ | |
282 | static void usage(const char *msg) | |
283 | { | |
284 | if (msg != NULL && *msg != '\0') | |
285 | { | |
286 | fprintf(stderr, "%s\n", msg); | |
287 | } | |
288 | fprintf(stderr, "Usage: charon\n" | |
289 | " [--help]\n" | |
290 | " [--version]\n" | |
291 | " [--use-syslog]\n" | |
292 | " [--debug-<type> <level>]\n" | |
56d07af3 | 293 | " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|esp|lib)\n" |
349fa528 TB |
294 | " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n" |
295 | " 2 = controlmore, 3 = raw, 4 = private)\n" | |
296 | "\n" | |
297 | ); | |
349fa528 TB |
298 | } |
299 | ||
300 | /** | |
301 | * Main function, starts the daemon. | |
302 | */ | |
303 | int main(int argc, char *argv[]) | |
304 | { | |
305 | struct sigaction action; | |
52bff307 | 306 | int group, status = SS_RC_INITIALIZATION_FAILED; |
b8e17eb3 | 307 | struct utsname utsname; |
9665686b TB |
308 | level_t levels[DBG_MAX]; |
309 | bool use_syslog = FALSE; | |
349fa528 TB |
310 | |
311 | /* logging for library during initialization, as we have no bus yet */ | |
312 | dbg = dbg_stderr; | |
313 | ||
314 | /* initialize library */ | |
34d3bfcf | 315 | if (!library_init(NULL, "charon")) |
349fa528 TB |
316 | { |
317 | library_deinit(); | |
318 | exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); | |
319 | } | |
320 | ||
321 | if (lib->integrity && | |
322 | !lib->integrity->check_file(lib->integrity, "charon", argv[0])) | |
323 | { | |
9ed6341d | 324 | dbg_stderr(DBG_DMN, 1, "integrity check of charon failed"); |
349fa528 TB |
325 | library_deinit(); |
326 | exit(SS_RC_DAEMON_INTEGRITY); | |
327 | } | |
328 | ||
1c306c0e | 329 | if (!libcharon_init()) |
52bff307 | 330 | { |
9ed6341d | 331 | dbg_stderr(DBG_DMN, 1, "initialization failed - aborting charon"); |
52bff307 TB |
332 | goto deinit; |
333 | } | |
334 | ||
349fa528 TB |
335 | /* use CTRL loglevel for default */ |
336 | for (group = 0; group < DBG_MAX; group++) | |
337 | { | |
338 | levels[group] = LEVEL_CTRL; | |
339 | } | |
340 | ||
341 | /* handle arguments */ | |
342 | for (;;) | |
343 | { | |
344 | struct option long_opts[] = { | |
345 | { "help", no_argument, NULL, 'h' }, | |
346 | { "version", no_argument, NULL, 'v' }, | |
347 | { "use-syslog", no_argument, NULL, 'l' }, | |
348 | /* TODO: handle "debug-all" */ | |
349 | { "debug-dmn", required_argument, &group, DBG_DMN }, | |
350 | { "debug-mgr", required_argument, &group, DBG_MGR }, | |
351 | { "debug-ike", required_argument, &group, DBG_IKE }, | |
352 | { "debug-chd", required_argument, &group, DBG_CHD }, | |
353 | { "debug-job", required_argument, &group, DBG_JOB }, | |
354 | { "debug-cfg", required_argument, &group, DBG_CFG }, | |
355 | { "debug-knl", required_argument, &group, DBG_KNL }, | |
356 | { "debug-net", required_argument, &group, DBG_NET }, | |
54d096a7 | 357 | { "debug-asn", required_argument, &group, DBG_ASN }, |
349fa528 | 358 | { "debug-enc", required_argument, &group, DBG_ENC }, |
ed08f7ce | 359 | { "debug-tnc", required_argument, &group, DBG_TNC }, |
a6cb3741 AS |
360 | { "debug-imc", required_argument, &group, DBG_IMC }, |
361 | { "debug-imv", required_argument, &group, DBG_IMV }, | |
b9d61f78 | 362 | { "debug-pts", required_argument, &group, DBG_PTS }, |
47765000 | 363 | { "debug-tls", required_argument, &group, DBG_TLS }, |
56d07af3 | 364 | { "debug-esp", required_argument, &group, DBG_ESP }, |
349fa528 TB |
365 | { "debug-lib", required_argument, &group, DBG_LIB }, |
366 | { 0,0,0,0 } | |
367 | }; | |
368 | ||
369 | int c = getopt_long(argc, argv, "", long_opts, NULL); | |
370 | switch (c) | |
371 | { | |
372 | case EOF: | |
373 | break; | |
374 | case 'h': | |
375 | usage(NULL); | |
9d843ee6 TB |
376 | status = 0; |
377 | goto deinit; | |
349fa528 TB |
378 | case 'v': |
379 | printf("Linux strongSwan %s\n", VERSION); | |
a1f90c7a TB |
380 | status = 0; |
381 | goto deinit; | |
349fa528 TB |
382 | case 'l': |
383 | use_syslog = TRUE; | |
384 | continue; | |
385 | case 0: | |
386 | /* option is in group */ | |
387 | levels[group] = atoi(optarg); | |
388 | continue; | |
389 | default: | |
390 | usage(""); | |
9d843ee6 TB |
391 | status = 1; |
392 | goto deinit; | |
349fa528 TB |
393 | } |
394 | break; | |
395 | } | |
396 | ||
397 | if (!lookup_uid_gid()) | |
398 | { | |
9ed6341d | 399 | dbg_stderr(DBG_DMN, 1, "invalid uid/gid - aborting charon"); |
52bff307 | 400 | goto deinit; |
349fa528 TB |
401 | } |
402 | ||
9665686b TB |
403 | charon->set_default_loggers(charon, levels, !use_syslog); |
404 | charon->load_loggers(charon); | |
84f89634 | 405 | |
b8e17eb3 MW |
406 | if (uname(&utsname) != 0) |
407 | { | |
408 | memset(&utsname, 0, sizeof(utsname)); | |
409 | } | |
410 | DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)", | |
411 | utsname.sysname, utsname.release, utsname.machine); | |
94b48e07 TB |
412 | if (lib->integrity) |
413 | { | |
414 | DBG1(DBG_DMN, "integrity tests enabled:"); | |
415 | DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); | |
94b48e07 TB |
416 | DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); |
417 | DBG1(DBG_DMN, "daemon 'charon': passed file integrity test"); | |
418 | } | |
419 | ||
349fa528 | 420 | /* initialize daemon */ |
94b48e07 TB |
421 | if (!charon->initialize(charon, |
422 | lib->settings->get_str(lib->settings, "charon.load", PLUGINS))) | |
349fa528 TB |
423 | { |
424 | DBG1(DBG_DMN, "initialization failed - aborting charon"); | |
52bff307 | 425 | goto deinit; |
349fa528 | 426 | } |
607f8e99 | 427 | lib->plugins->status(lib->plugins, LEVEL_CTRL); |
349fa528 TB |
428 | |
429 | if (check_pidfile()) | |
430 | { | |
52bff307 | 431 | goto deinit; |
349fa528 TB |
432 | } |
433 | ||
a2eb5817 | 434 | if (!lib->caps->drop(lib->caps)) |
349fa528 TB |
435 | { |
436 | DBG1(DBG_DMN, "capability dropping failed - aborting charon"); | |
52bff307 | 437 | goto deinit; |
349fa528 TB |
438 | } |
439 | ||
fe3ae5be | 440 | /* add handler for fatal signals, |
85814809 | 441 | * INT, TERM and HUP are handled by sigwaitinfo() in run() */ |
349fa528 TB |
442 | action.sa_flags = 0; |
443 | sigemptyset(&action.sa_mask); | |
444 | sigaddset(&action.sa_mask, SIGINT); | |
445 | sigaddset(&action.sa_mask, SIGTERM); | |
446 | sigaddset(&action.sa_mask, SIGHUP); | |
fe3ae5be SM |
447 | |
448 | /* optionally let the external system handle fatal signals */ | |
449 | #ifndef DISABLE_SIGNAL_HANDLER | |
450 | action.sa_handler = segv_handler; | |
349fa528 TB |
451 | sigaction(SIGSEGV, &action, NULL); |
452 | sigaction(SIGILL, &action, NULL); | |
453 | sigaction(SIGBUS, &action, NULL); | |
fe3ae5be SM |
454 | #endif /* DISABLE_SIGNAL_HANDLER */ |
455 | ||
349fa528 TB |
456 | action.sa_handler = SIG_IGN; |
457 | sigaction(SIGPIPE, &action, NULL); | |
458 | ||
459 | pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); | |
460 | ||
461 | /* start daemon (i.e. the threads in the thread-pool) */ | |
462 | charon->start(charon); | |
463 | ||
464 | /* main thread goes to run loop */ | |
465 | run(); | |
466 | ||
52bff307 | 467 | status = 0; |
349fa528 | 468 | |
52bff307 TB |
469 | deinit: |
470 | libcharon_deinit(); | |
1b4d97db | 471 | unlink_pidfile(); |
52bff307 TB |
472 | library_deinit(); |
473 | return status; | |
349fa528 | 474 | } |