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