Reverting eba28948a584b9d02474cf5d256b04b8d2adbe6a which was only necessary when...
[strongswan.git] / src / charon / daemon.c
1 /*
2 * Copyright (C) 2006-2009 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 <stdio.h>
20 #ifdef HAVE_PRCTL
21 #include <sys/prctl.h>
22 #endif
23 #define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */
24 #include <signal.h>
25 #undef _POSIX_PTHREAD_SEMANTICS
26 #include <pthread.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <time.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <errno.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #ifdef CAPABILITIES
37 #include <sys/capability.h>
38 #endif /* CAPABILITIES */
39
40 #include "daemon.h"
41
42 #include <library.h>
43 #include <utils/backtrace.h>
44 #include <threading/thread.h>
45 #include <selectors/traffic_selector.h>
46 #include <config/proposal.h>
47
48 #ifndef LOG_AUTHPRIV /* not defined on OpenSolaris */
49 #define LOG_AUTHPRIV LOG_AUTH
50 #endif
51
52 typedef struct private_daemon_t private_daemon_t;
53
54 /**
55 * Private additions to daemon_t, contains threads and internal functions.
56 */
57 struct private_daemon_t {
58 /**
59 * Public members of daemon_t.
60 */
61 daemon_t public;
62
63 /**
64 * Signal set used for signal handling.
65 */
66 sigset_t signal_set;
67
68 #ifdef CAPABILITIES
69 /**
70 * capabilities to keep
71 */
72 cap_t caps;
73 #endif /* CAPABILITIES */
74 };
75
76 /**
77 * One and only instance of the daemon.
78 */
79 daemon_t *charon;
80
81 /**
82 * hook in library for debugging messages
83 */
84 extern void (*dbg) (int level, char *fmt, ...);
85
86 /**
87 * Logging hook for library logs, spreads debug message over bus
88 */
89 static void dbg_bus(int level, char *fmt, ...)
90 {
91 va_list args;
92
93 va_start(args, fmt);
94 charon->bus->vlog(charon->bus, DBG_LIB, level, fmt, args);
95 va_end(args);
96 }
97
98 /**
99 * Logging hook for library logs, using stderr output
100 */
101 static void dbg_stderr(int level, char *fmt, ...)
102 {
103 va_list args;
104
105 if (level <= 1)
106 {
107 va_start(args, fmt);
108 fprintf(stderr, "00[LIB] ");
109 vfprintf(stderr, fmt, args);
110 fprintf(stderr, "\n");
111 va_end(args);
112 }
113 }
114
115 /**
116 * Run the daemon and handle unix signals
117 */
118 static void run(private_daemon_t *this)
119 {
120 sigset_t set;
121
122 /* handle SIGINT, SIGHUP ans SIGTERM in this handler */
123 sigemptyset(&set);
124 sigaddset(&set, SIGINT);
125 sigaddset(&set, SIGHUP);
126 sigaddset(&set, SIGTERM);
127 sigprocmask(SIG_BLOCK, &set, NULL);
128
129 while (TRUE)
130 {
131 int sig;
132 int error;
133
134 error = sigwait(&set, &sig);
135 if (error)
136 {
137 DBG1(DBG_DMN, "error %d while waiting for a signal", error);
138 return;
139 }
140 switch (sig)
141 {
142 case SIGHUP:
143 {
144 DBG1(DBG_DMN, "signal of type SIGHUP received. Ignored");
145 break;
146 }
147 case SIGINT:
148 {
149 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
150 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
151 return;
152 }
153 case SIGTERM:
154 {
155 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
156 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
157 return;
158 }
159 default:
160 {
161 DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
162 break;
163 }
164 }
165 }
166 }
167
168 /**
169 * Clean up all daemon resources
170 */
171 static void destroy(private_daemon_t *this)
172 {
173 /* terminate all idle threads */
174 if (this->public.processor)
175 {
176 this->public.processor->set_threads(this->public.processor, 0);
177 }
178 /* close all IKE_SAs */
179 if (this->public.ike_sa_manager)
180 {
181 this->public.ike_sa_manager->flush(this->public.ike_sa_manager);
182 }
183 DESTROY_IF(this->public.receiver);
184 /* unload plugins to release threads */
185 lib->plugins->unload(lib->plugins);
186 #ifdef CAPABILITIES
187 cap_free(this->caps);
188 #endif /* CAPABILITIES */
189 DESTROY_IF(this->public.traps);
190 DESTROY_IF(this->public.ike_sa_manager);
191 DESTROY_IF(this->public.kernel_interface);
192 DESTROY_IF(this->public.scheduler);
193 DESTROY_IF(this->public.controller);
194 DESTROY_IF(this->public.eap);
195 DESTROY_IF(this->public.sim);
196 #ifdef ME
197 DESTROY_IF(this->public.connect_manager);
198 DESTROY_IF(this->public.mediation_manager);
199 #endif /* ME */
200 DESTROY_IF(this->public.backends);
201 DESTROY_IF(this->public.credentials);
202 DESTROY_IF(this->public.sender);
203 DESTROY_IF(this->public.socket);
204 /* wait until all threads are gone */
205 DESTROY_IF(this->public.processor);
206
207 /* rehook library logging, shutdown logging */
208 dbg = dbg_stderr;
209 DESTROY_IF(this->public.bus);
210 this->public.file_loggers->destroy_offset(this->public.file_loggers,
211 offsetof(file_logger_t, destroy));
212 this->public.sys_loggers->destroy_offset(this->public.sys_loggers,
213 offsetof(sys_logger_t, destroy));
214 free(this);
215 }
216
217 /**
218 * drop daemon capabilities
219 */
220 static bool drop_capabilities(private_daemon_t *this)
221 {
222 #ifdef HAVE_PRCTL
223 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
224 #endif
225
226 if (setgid(charon->gid) != 0)
227 {
228 DBG1(DBG_DMN, "change to unprivileged group failed");
229 return FALSE;
230 }
231 if (setuid(charon->uid) != 0)
232 {
233 DBG1(DBG_DMN, "change to unprivileged user failed");
234 return FALSE;
235 }
236
237 #ifdef CAPABILITIES
238 if (cap_set_proc(this->caps) != 0)
239 {
240 DBG1(DBG_DMN, "unable to drop daemon capabilities");
241 return FALSE;
242 }
243 #endif /* CAPABILITIES */
244 return TRUE;
245 }
246
247 /**
248 * Implementation of daemon_t.keep_cap
249 */
250 static void keep_cap(private_daemon_t *this, u_int cap)
251 {
252 #ifdef CAPABILITIES
253 cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
254 cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET);
255 cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET);
256 #endif /* CAPABILITIES */
257 }
258
259 /**
260 * lookup UID and GID
261 */
262 static bool lookup_uid_gid(private_daemon_t *this)
263 {
264 #ifdef IPSEC_USER
265 {
266 char buf[1024];
267 struct passwd passwd, *pwp;
268
269 if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
270 pwp == NULL)
271 {
272 DBG1(DBG_DMN, "resolving user '"IPSEC_USER"' failed");
273 return FALSE;
274 }
275 charon->uid = pwp->pw_uid;
276 }
277 #endif
278 #ifdef IPSEC_GROUP
279 {
280 char buf[1024];
281 struct group group, *grp;
282
283 if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
284 grp == NULL)
285 {
286 DBG1(DBG_DMN, "resolving group '"IPSEC_GROUP"' failed");
287 return FALSE;
288 }
289 charon->gid = grp->gr_gid;
290 }
291 #endif
292 return TRUE;
293 }
294
295 /**
296 * Log loaded plugins
297 */
298 static void print_plugins()
299 {
300 char buf[512], *plugin;
301 int len = 0;
302 enumerator_t *enumerator;
303
304 buf[0] = '\0';
305 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
306 while (len < sizeof(buf) && enumerator->enumerate(enumerator, &plugin))
307 {
308 len += snprintf(&buf[len], sizeof(buf)-len, "%s ", plugin);
309 }
310 enumerator->destroy(enumerator);
311 DBG1(DBG_DMN, "loaded plugins: %s", buf);
312 }
313
314 /**
315 * Initialize logging
316 */
317 static void initialize_loggers(private_daemon_t *this, bool use_stderr,
318 level_t levels[])
319 {
320 sys_logger_t *sys_logger;
321 file_logger_t *file_logger;
322 enumerator_t *enumerator;
323 char *facility, *filename;
324 int loggers_defined = 0;
325 debug_t group;
326 level_t def;
327 bool append;
328 FILE *file;
329
330 /* setup sysloggers */
331 enumerator = lib->settings->create_section_enumerator(lib->settings,
332 "charon.syslog");
333 while (enumerator->enumerate(enumerator, &facility))
334 {
335 loggers_defined++;
336 if (streq(facility, "daemon"))
337 {
338 sys_logger = sys_logger_create(LOG_DAEMON);
339 }
340 else if (streq(facility, "auth"))
341 {
342 sys_logger = sys_logger_create(LOG_AUTHPRIV);
343 }
344 else
345 {
346 continue;
347 }
348 def = lib->settings->get_int(lib->settings,
349 "charon.syslog.%s.default", 1, facility);
350 for (group = 0; group < DBG_MAX; group++)
351 {
352 sys_logger->set_level(sys_logger, group,
353 lib->settings->get_int(lib->settings,
354 "charon.syslog.%s.%N", def,
355 facility, debug_lower_names, group));
356 }
357 this->public.sys_loggers->insert_last(this->public.sys_loggers,
358 sys_logger);
359 this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
360 }
361 enumerator->destroy(enumerator);
362
363 /* and file loggers */
364 enumerator = lib->settings->create_section_enumerator(lib->settings,
365 "charon.filelog");
366 while (enumerator->enumerate(enumerator, &filename))
367 {
368 loggers_defined++;
369 if (streq(filename, "stderr"))
370 {
371 file = stderr;
372 }
373 else if (streq(filename, "stdout"))
374 {
375 file = stdout;
376 }
377 else
378 {
379 append = lib->settings->get_bool(lib->settings,
380 "charon.filelog.%s.append", TRUE, filename);
381 file = fopen(filename, append ? "a" : "w");
382 if (file == NULL)
383 {
384 DBG1(DBG_DMN, "opening file %s for logging failed: %s",
385 filename, strerror(errno));
386 continue;
387 }
388 }
389 file_logger = file_logger_create(file);
390 def = lib->settings->get_int(lib->settings,
391 "charon.filelog.%s.default", 1, filename);
392 for (group = 0; group < DBG_MAX; group++)
393 {
394 file_logger->set_level(file_logger, group,
395 lib->settings->get_int(lib->settings,
396 "charon.filelog.%s.%N", def,
397 filename, debug_lower_names, group));
398 }
399 this->public.file_loggers->insert_last(this->public.file_loggers,
400 file_logger);
401 this->public.bus->add_listener(this->public.bus, &file_logger->listener);
402
403 }
404 enumerator->destroy(enumerator);
405
406 /* set up legacy style default loggers provided via command-line */
407 if (!loggers_defined)
408 {
409 /* set up default stdout file_logger */
410 file_logger = file_logger_create(stdout);
411 this->public.bus->add_listener(this->public.bus, &file_logger->listener);
412 this->public.file_loggers->insert_last(this->public.file_loggers,
413 file_logger);
414 /* set up default daemon sys_logger */
415 sys_logger = sys_logger_create(LOG_DAEMON);
416 this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
417 this->public.sys_loggers->insert_last(this->public.sys_loggers,
418 sys_logger);
419 for (group = 0; group < DBG_MAX; group++)
420 {
421 sys_logger->set_level(sys_logger, group, levels[group]);
422 if (use_stderr)
423 {
424 file_logger->set_level(file_logger, group, levels[group]);
425 }
426 }
427
428 /* set up default auth sys_logger */
429 sys_logger = sys_logger_create(LOG_AUTHPRIV);
430 this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
431 this->public.sys_loggers->insert_last(this->public.sys_loggers,
432 sys_logger);
433 sys_logger->set_level(sys_logger, DBG_ANY, LEVEL_AUDIT);
434 }
435 }
436
437 /**
438 * Initialize the daemon
439 */
440 static bool initialize(private_daemon_t *this, bool syslog, level_t levels[])
441 {
442 /* for uncritical pseudo random numbers */
443 srandom(time(NULL) + getpid());
444
445 /* setup bus and it's listeners first to enable log output */
446 this->public.bus = bus_create();
447 /* set up hook to log dbg message in library via charons message bus */
448 dbg = dbg_bus;
449
450 initialize_loggers(this, !syslog, levels);
451
452 DBG1(DBG_DMN, "Starting IKEv2 charon daemon (strongSwan "VERSION")");
453
454 if (lib->integrity)
455 {
456 DBG1(DBG_DMN, "integrity tests enabled:");
457 DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests");
458 DBG1(DBG_DMN, "daemon 'charon': passed file integrity test");
459 }
460
461 /* load secrets, ca certificates and crls */
462 this->public.processor = processor_create();
463 this->public.scheduler = scheduler_create();
464 this->public.credentials = credential_manager_create();
465 this->public.controller = controller_create();
466 this->public.eap = eap_manager_create();
467 this->public.sim = sim_manager_create();
468 this->public.backends = backend_manager_create();
469 this->public.kernel_interface = kernel_interface_create();
470 this->public.socket = socket_manager_create();
471 this->public.traps = trap_manager_create();
472
473 /* load plugins, further infrastructure may need it */
474 if (!lib->plugins->load(lib->plugins, NULL,
475 lib->settings->get_str(lib->settings, "charon.load", PLUGINS)))
476 {
477 return FALSE;
478 }
479
480 print_plugins();
481
482 this->public.ike_sa_manager = ike_sa_manager_create();
483 if (this->public.ike_sa_manager == NULL)
484 {
485 return FALSE;
486 }
487 this->public.sender = sender_create();
488 this->public.receiver = receiver_create();
489 if (this->public.receiver == NULL)
490 {
491 return FALSE;
492 }
493
494 #ifdef ME
495 this->public.connect_manager = connect_manager_create();
496 if (this->public.connect_manager == NULL)
497 {
498 return FALSE;
499 }
500 this->public.mediation_manager = mediation_manager_create();
501 #endif /* ME */
502
503 return TRUE;
504 }
505
506 /**
507 * Handle SIGSEGV/SIGILL signals raised by threads
508 */
509 static void segv_handler(int signal)
510 {
511 backtrace_t *backtrace;
512
513 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
514 backtrace = backtrace_create(2);
515 backtrace->log(backtrace, stderr);
516 backtrace->destroy(backtrace);
517
518 DBG1(DBG_DMN, "killing ourself, received critical signal");
519 abort();
520 }
521
522 /**
523 * Create the daemon.
524 */
525 private_daemon_t *daemon_create(void)
526 {
527 struct sigaction action;
528 private_daemon_t *this = malloc_thing(private_daemon_t);
529
530 /* assign methods */
531 this->public.keep_cap = (void(*)(daemon_t*, u_int cap))keep_cap;
532
533 /* NULL members for clean destruction */
534 this->public.socket = NULL;
535 this->public.ike_sa_manager = NULL;
536 this->public.traps = NULL;
537 this->public.credentials = NULL;
538 this->public.backends = NULL;
539 this->public.sender= NULL;
540 this->public.receiver = NULL;
541 this->public.scheduler = NULL;
542 this->public.kernel_interface = NULL;
543 this->public.processor = NULL;
544 this->public.controller = NULL;
545 this->public.eap = NULL;
546 this->public.sim = NULL;
547 this->public.bus = NULL;
548 this->public.file_loggers = linked_list_create();
549 this->public.sys_loggers = linked_list_create();
550 #ifdef ME
551 this->public.connect_manager = NULL;
552 this->public.mediation_manager = NULL;
553 #endif /* ME */
554 this->public.uid = 0;
555 this->public.gid = 0;
556
557 #ifdef CAPABILITIES
558 this->caps = cap_init();
559 keep_cap(this, CAP_NET_ADMIN);
560 if (lib->leak_detective)
561 {
562 keep_cap(this, CAP_SYS_NICE);
563 }
564 #endif /* CAPABILITIES */
565
566 /* add handler for SEGV and ILL,
567 * INT, TERM and HUP are handled by sigwait() in run() */
568 action.sa_handler = segv_handler;
569 action.sa_flags = 0;
570 sigemptyset(&action.sa_mask);
571 sigaddset(&action.sa_mask, SIGINT);
572 sigaddset(&action.sa_mask, SIGTERM);
573 sigaddset(&action.sa_mask, SIGHUP);
574 sigaction(SIGSEGV, &action, NULL);
575 sigaction(SIGILL, &action, NULL);
576 sigaction(SIGBUS, &action, NULL);
577 action.sa_handler = SIG_IGN;
578 sigaction(SIGPIPE, &action, NULL);
579
580 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
581
582 return this;
583 }
584
585 /**
586 * Check/create PID file, return TRUE if already running
587 */
588 static bool check_pidfile()
589 {
590 struct stat stb;
591 FILE *file;
592
593 if (stat(PID_FILE, &stb) == 0)
594 {
595 file = fopen(PID_FILE, "r");
596 if (file)
597 {
598 char buf[64];
599 pid_t pid = 0;
600
601 memset(buf, 0, sizeof(buf));
602 if (fread(buf, 1, sizeof(buf), file))
603 {
604 pid = atoi(buf);
605 }
606 fclose(file);
607 if (pid && kill(pid, 0) == 0)
608 { /* such a process is running */
609 return TRUE;
610 }
611 }
612 DBG1(DBG_DMN, "removing pidfile '"PID_FILE"', process not running");
613 unlink(PID_FILE);
614 }
615
616 /* create new pidfile */
617 file = fopen(PID_FILE, "w");
618 if (file)
619 {
620 fprintf(file, "%d\n", getpid());
621 ignore_result(fchown(fileno(file), charon->uid, charon->gid));
622 fclose(file);
623 }
624 return FALSE;
625 }
626
627 /**
628 * print command line usage and exit
629 */
630 static void usage(const char *msg)
631 {
632 if (msg != NULL && *msg != '\0')
633 {
634 fprintf(stderr, "%s\n", msg);
635 }
636 fprintf(stderr, "Usage: charon\n"
637 " [--help]\n"
638 " [--version]\n"
639 " [--use-syslog]\n"
640 " [--debug-<type> <level>]\n"
641 " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib)\n"
642 " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n"
643 " 2 = controlmore, 3 = raw, 4 = private)\n"
644 "\n"
645 );
646 exit(msg == NULL? 0 : 1);
647 }
648
649 /**
650 * Main function, manages the daemon.
651 */
652 int main(int argc, char *argv[])
653 {
654 bool use_syslog = FALSE;
655 private_daemon_t *private_charon;
656 level_t levels[DBG_MAX];
657 int group;
658
659 /* logging for library during initialization, as we have no bus yet */
660 dbg = dbg_stderr;
661
662 /* initialize library */
663 if (!library_init(NULL))
664 {
665 library_deinit();
666 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
667 }
668
669 if (lib->integrity &&
670 !lib->integrity->check_file(lib->integrity, "charon", argv[0]))
671 {
672 dbg_stderr(1, "integrity check of charon failed");
673 library_deinit();
674 exit(SS_RC_DAEMON_INTEGRITY);
675 }
676
677 lib->printf_hook->add_handler(lib->printf_hook, 'R',
678 traffic_selector_printf_hook,
679 PRINTF_HOOK_ARGTYPE_POINTER,
680 PRINTF_HOOK_ARGTYPE_END);
681 lib->printf_hook->add_handler(lib->printf_hook, 'P',
682 proposal_printf_hook,
683 PRINTF_HOOK_ARGTYPE_POINTER,
684 PRINTF_HOOK_ARGTYPE_END);
685 private_charon = daemon_create();
686 charon = (daemon_t*)private_charon;
687
688 /* use CTRL loglevel for default */
689 for (group = 0; group < DBG_MAX; group++)
690 {
691 levels[group] = LEVEL_CTRL;
692 }
693
694 /* handle arguments */
695 for (;;)
696 {
697 struct option long_opts[] = {
698 { "help", no_argument, NULL, 'h' },
699 { "version", no_argument, NULL, 'v' },
700 { "use-syslog", no_argument, NULL, 'l' },
701 /* TODO: handle "debug-all" */
702 { "debug-dmn", required_argument, &group, DBG_DMN },
703 { "debug-mgr", required_argument, &group, DBG_MGR },
704 { "debug-ike", required_argument, &group, DBG_IKE },
705 { "debug-chd", required_argument, &group, DBG_CHD },
706 { "debug-job", required_argument, &group, DBG_JOB },
707 { "debug-cfg", required_argument, &group, DBG_CFG },
708 { "debug-knl", required_argument, &group, DBG_KNL },
709 { "debug-net", required_argument, &group, DBG_NET },
710 { "debug-enc", required_argument, &group, DBG_ENC },
711 { "debug-lib", required_argument, &group, DBG_LIB },
712 { 0,0,0,0 }
713 };
714
715 int c = getopt_long(argc, argv, "", long_opts, NULL);
716 switch (c)
717 {
718 case EOF:
719 break;
720 case 'h':
721 usage(NULL);
722 break;
723 case 'v':
724 printf("Linux strongSwan %s\n", VERSION);
725 exit(0);
726 case 'l':
727 use_syslog = TRUE;
728 continue;
729 case 0:
730 /* option is in group */
731 levels[group] = atoi(optarg);
732 continue;
733 default:
734 usage("");
735 break;
736 }
737 break;
738 }
739
740 if (!lookup_uid_gid(private_charon))
741 {
742 DBG1(DBG_DMN, "invalid uid/gid - aborting charon");
743 destroy(private_charon);
744 library_deinit();
745 exit(SS_RC_INITIALIZATION_FAILED);
746 }
747
748 /* initialize daemon */
749 if (!initialize(private_charon, use_syslog, levels))
750 {
751 DBG1(DBG_DMN, "initialization failed - aborting charon");
752 destroy(private_charon);
753 library_deinit();
754 exit(SS_RC_INITIALIZATION_FAILED);
755 }
756
757 if (check_pidfile())
758 {
759 DBG1(DBG_DMN, "charon already running (\""PID_FILE"\" exists)");
760 destroy(private_charon);
761 library_deinit();
762 exit(-1);
763 }
764
765 if (!drop_capabilities(private_charon))
766 {
767 DBG1(DBG_DMN, "capability dropping failed - aborting charon");
768 destroy(private_charon);
769 library_deinit();
770 exit(SS_RC_INITIALIZATION_FAILED);
771 }
772
773 /* start the engine, go multithreaded */
774 charon->processor->set_threads(charon->processor,
775 lib->settings->get_int(lib->settings, "charon.threads",
776 DEFAULT_THREADS));
777
778 /* run daemon */
779 run(private_charon);
780
781 /* normal termination, cleanup and exit */
782 destroy(private_charon);
783 unlink(PID_FILE);
784
785 library_deinit();
786
787 return 0;
788 }
789