2 * Copyright (C) 2006-2015 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
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>.
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
20 * Copyright (C) 2016 secunet Security Networks AG
21 * Copyright (C) 2016 Thomas Egerer
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43 #include <sys/types.h>
55 #include <bus/listeners/sys_logger.h>
56 #include <bus/listeners/file_logger.h>
57 #include <config/proposal.h>
58 #include <plugins/plugin_feature.h>
59 #include <kernel/kernel_handler.h>
60 #include <processing/jobs/start_action_job.h>
61 #include <threading/mutex.h>
63 #ifndef LOG_AUTHPRIV /* not defined on OpenSolaris */
64 #define LOG_AUTHPRIV LOG_AUTH
67 typedef struct private_daemon_t private_daemon_t
;
70 * Private additions to daemon_t, contains threads and internal functions.
72 struct private_daemon_t
{
74 * Public members of daemon_t.
79 * Handler for kernel events
81 kernel_handler_t
*kernel_handler
;
84 * A list of installed loggers (as logger_entry_t*)
86 linked_list_t
*loggers
;
89 * Identifier used for syslog (in the openlog call)
91 char *syslog_identifier
;
94 * Mutex for configured loggers
99 * Integrity check failed?
101 bool integrity_failed
;
104 * Number of times we have been initialized
110 * One and only instance of the daemon.
115 * hook in library for debugging messages
117 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
120 * we store the previous debug function so we can reset it
122 static void (*dbg_old
) (debug_t group
, level_t level
, char *fmt
, ...);
125 * Logging hook for library logs, spreads debug message over bus
127 static void dbg_bus(debug_t group
, level_t level
, char *fmt
, ...)
132 charon
->bus
->vlog(charon
->bus
, group
, level
, fmt
, args
);
137 * Data for registered custom loggers
141 * Name of the custom logger (also used for loglevel configuration)
146 * Constructor to be called for custom logger creation
148 custom_logger_constructor_t constructor
;
150 } custom_logger_entry_t
;
152 #define MAX_CUSTOM_LOGGERS 10
155 * Static array for logger registration using __attribute__((constructor))
157 static custom_logger_entry_t custom_loggers
[MAX_CUSTOM_LOGGERS
];
158 static int custom_logger_count
;
161 * Described in header
163 void register_custom_logger(char *name
,
164 custom_logger_constructor_t constructor
)
166 if (custom_logger_count
< MAX_CUSTOM_LOGGERS
- 1)
168 custom_loggers
[custom_logger_count
].name
= name
;
169 custom_loggers
[custom_logger_count
].constructor
= constructor
;
170 custom_logger_count
++;
174 fprintf(stderr
, "failed to register custom logger, please increase "
175 "MAX_CUSTOM_LOGGERS");
180 * Types of supported loggers
184 * Syslog logger instance
189 * File logger instance
194 * Custom logger instance
201 * Some metadata about configured loggers
205 * Target of the logger (syslog facility or filename)
220 custom_logger_t
*custom
;
226 * Destroy a logger entry
228 static void logger_entry_destroy(logger_entry_t
*this)
233 DESTROY_IF(this->logger
.file
);
236 DESTROY_IF(this->logger
.sys
);
239 DESTROY_IF(this->logger
.custom
);
247 * Unregister and destroy a logger entry
249 static void logger_entry_unregister_destroy(logger_entry_t
*this)
254 charon
->bus
->remove_logger(charon
->bus
, &this->logger
.file
->logger
);
257 charon
->bus
->remove_logger(charon
->bus
, &this->logger
.sys
->logger
);
260 charon
->bus
->remove_logger(charon
->bus
,
261 &this->logger
.custom
->logger
);
264 logger_entry_destroy(this);
268 * Match a logger entry by target and whether it is a file or syslog logger
270 static bool logger_entry_match(logger_entry_t
*this, char *target
,
273 return this->type
== *type
&& streq(this->target
, target
);
277 * Handle configured syslog identifier
279 * mutex must be locked when calling this function
281 static void handle_syslog_identifier(private_daemon_t
*this)
286 identifier
= lib
->settings
->get_str(lib
->settings
, "%s.syslog.identifier",
289 { /* set identifier, which is prepended to each log line */
290 if (!this->syslog_identifier
||
291 !streq(identifier
, this->syslog_identifier
))
294 this->syslog_identifier
= identifier
;
295 openlog(this->syslog_identifier
, 0, 0);
298 else if (this->syslog_identifier
)
301 this->syslog_identifier
= NULL
;
303 #endif /* HAVE_SYSLOG */
307 * Convert the given string into a syslog facility, returns -1 if the facility
310 static int get_syslog_facility(char *facility
)
313 if (streq(facility
, "daemon"))
317 else if (streq(facility
, "auth"))
321 #endif /* HAVE_SYSLOG */
326 * Returns an existing or newly created logger entry (if found, it is removed
327 * from the given linked list of existing loggers)
329 static logger_entry_t
*get_logger_entry(char *target
, logger_type_t type
,
330 linked_list_t
*existing
,
331 custom_logger_constructor_t constructor
)
333 logger_entry_t
*entry
;
335 if (existing
->find_first(existing
, (void*)logger_entry_match
,
336 (void**)&entry
, target
, &type
) != SUCCESS
)
339 .target
= strdup(target
),
345 entry
->logger
.file
= file_logger_create(target
);
349 entry
->logger
.sys
= sys_logger_create(
350 get_syslog_facility(target
));
355 #endif /* HAVE_SYSLOG */
359 entry
->logger
.custom
= constructor(target
);
361 if (!entry
->logger
.custom
)
371 existing
->remove(existing
, entry
, NULL
);
377 * Create or reuse a syslog logger
379 static sys_logger_t
*add_sys_logger(private_daemon_t
*this, char *facility
,
380 linked_list_t
*current_loggers
)
382 logger_entry_t
*entry
;
384 entry
= get_logger_entry(facility
, SYS_LOGGER
, current_loggers
, NULL
);
387 this->loggers
->insert_last(this->loggers
, entry
);
389 return entry ? entry
->logger
.sys
: NULL
;
393 * Create or reuse a file logger
395 static file_logger_t
*add_file_logger(private_daemon_t
*this, char *filename
,
396 linked_list_t
*current_loggers
)
398 logger_entry_t
*entry
;
400 entry
= get_logger_entry(filename
, FILE_LOGGER
, current_loggers
, NULL
);
403 this->loggers
->insert_last(this->loggers
, entry
);
405 return entry ? entry
->logger
.file
: NULL
;
409 * Create or reuse a custom logger
411 static custom_logger_t
*add_custom_logger(private_daemon_t
*this,
412 custom_logger_entry_t
*custom
,
413 linked_list_t
*current_loggers
)
415 logger_entry_t
*entry
;
417 entry
= get_logger_entry(custom
->name
, CUSTOM_LOGGER
, current_loggers
,
418 custom
->constructor
);
421 this->loggers
->insert_last(this->loggers
, entry
);
423 return entry ? entry
->logger
.custom
: NULL
;
427 * Load the given syslog logger configured in strongswan.conf
429 static void load_sys_logger(private_daemon_t
*this, char *facility
,
430 linked_list_t
*current_loggers
)
432 sys_logger_t
*sys_logger
;
436 if (get_syslog_facility(facility
) == -1)
441 sys_logger
= add_sys_logger(this, facility
, current_loggers
);
447 sys_logger
->set_options(sys_logger
,
448 lib
->settings
->get_bool(lib
->settings
, "%s.syslog.%s.ike_name",
449 FALSE
, lib
->ns
, facility
));
451 def
= lib
->settings
->get_int(lib
->settings
, "%s.syslog.%s.default", 1,
453 for (group
= 0; group
< DBG_MAX
; group
++)
455 sys_logger
->set_level(sys_logger
, group
,
456 lib
->settings
->get_int(lib
->settings
, "%s.syslog.%s.%N", def
,
457 lib
->ns
, facility
, debug_lower_names
, group
));
459 charon
->bus
->add_logger(charon
->bus
, &sys_logger
->logger
);
463 * Load the given file logger configured in strongswan.conf
465 static void load_file_logger(private_daemon_t
*this, char *filename
,
466 linked_list_t
*current_loggers
)
468 file_logger_t
*file_logger
;
471 bool add_ms
, ike_name
, flush_line
, append
;
474 time_format
= lib
->settings
->get_str(lib
->settings
,
475 "%s.filelog.%s.time_format", NULL
, lib
->ns
, filename
);
476 add_ms
= lib
->settings
->get_bool(lib
->settings
,
477 "%s.filelog.%s.time_add_ms", FALSE
, lib
->ns
, filename
);
478 ike_name
= lib
->settings
->get_bool(lib
->settings
,
479 "%s.filelog.%s.ike_name", FALSE
, lib
->ns
, filename
);
480 flush_line
= lib
->settings
->get_bool(lib
->settings
,
481 "%s.filelog.%s.flush_line", FALSE
, lib
->ns
, filename
);
482 append
= lib
->settings
->get_bool(lib
->settings
,
483 "%s.filelog.%s.append", TRUE
, lib
->ns
, filename
);
485 file_logger
= add_file_logger(this, filename
, current_loggers
);
491 file_logger
->set_options(file_logger
, time_format
, add_ms
, ike_name
);
492 file_logger
->open(file_logger
, flush_line
, append
);
494 def
= lib
->settings
->get_int(lib
->settings
, "%s.filelog.%s.default", 1,
496 for (group
= 0; group
< DBG_MAX
; group
++)
498 file_logger
->set_level(file_logger
, group
,
499 lib
->settings
->get_int(lib
->settings
, "%s.filelog.%s.%N", def
,
500 lib
->ns
, filename
, debug_lower_names
, group
));
502 charon
->bus
->add_logger(charon
->bus
, &file_logger
->logger
);
506 * Load the given custom logger configured in strongswan.conf
508 static void load_custom_logger(private_daemon_t
*this,
509 custom_logger_entry_t
*entry
,
510 linked_list_t
*current_loggers
)
512 custom_logger_t
*custom_logger
;
516 custom_logger
= add_custom_logger(this, entry
, current_loggers
);
522 def
= lib
->settings
->get_int(lib
->settings
, "%s.customlog.%s.default", 1,
523 lib
->ns
, entry
->name
);
524 for (group
= 0; group
< DBG_MAX
; group
++)
526 custom_logger
->set_level(custom_logger
, group
,
527 lib
->settings
->get_int(lib
->settings
, "%s.customlog.%s.%N", def
,
528 lib
->ns
, entry
->name
, debug_lower_names
, group
));
530 charon
->bus
->add_logger(charon
->bus
, &custom_logger
->logger
);
533 METHOD(daemon_t
, load_loggers
, void,
534 private_daemon_t
*this, level_t levels
[DBG_MAX
], bool to_stderr
)
536 enumerator_t
*enumerator
;
537 linked_list_t
*current_loggers
;
541 this->mutex
->lock(this->mutex
);
542 handle_syslog_identifier(this);
543 current_loggers
= this->loggers
;
544 this->loggers
= linked_list_create();
545 enumerator
= lib
->settings
->create_section_enumerator(lib
->settings
,
546 "%s.syslog", lib
->ns
);
547 while (enumerator
->enumerate(enumerator
, &target
))
549 load_sys_logger(this, target
, current_loggers
);
551 enumerator
->destroy(enumerator
);
553 enumerator
= lib
->settings
->create_section_enumerator(lib
->settings
,
554 "%s.filelog", lib
->ns
);
555 while (enumerator
->enumerate(enumerator
, &target
))
557 load_file_logger(this, target
, current_loggers
);
559 enumerator
->destroy(enumerator
);
561 for (i
= 0; i
< custom_logger_count
; ++i
)
563 load_custom_logger(this, &custom_loggers
[i
], current_loggers
);
566 if (!this->loggers
->get_count(this->loggers
) && levels
)
567 { /* setup legacy style default loggers configured via command-line */
568 file_logger_t
*file_logger
;
569 sys_logger_t
*sys_logger
;
572 sys_logger
= add_sys_logger(this, "daemon", current_loggers
);
573 file_logger
= add_file_logger(this, "stdout", current_loggers
);
574 file_logger
->open(file_logger
, FALSE
, FALSE
);
576 for (group
= 0; group
< DBG_MAX
; group
++)
580 sys_logger
->set_level(sys_logger
, group
, levels
[group
]);
584 file_logger
->set_level(file_logger
, group
, levels
[group
]);
589 charon
->bus
->add_logger(charon
->bus
, &sys_logger
->logger
);
591 charon
->bus
->add_logger(charon
->bus
, &file_logger
->logger
);
593 sys_logger
= add_sys_logger(this, "auth", current_loggers
);
596 sys_logger
->set_level(sys_logger
, DBG_ANY
, LEVEL_AUDIT
);
597 charon
->bus
->add_logger(charon
->bus
, &sys_logger
->logger
);
600 /* unregister and destroy any unused remaining loggers */
601 current_loggers
->destroy_function(current_loggers
,
602 (void*)logger_entry_unregister_destroy
);
603 this->mutex
->unlock(this->mutex
);
606 METHOD(daemon_t
, set_level
, void,
607 private_daemon_t
*this, debug_t group
, level_t level
)
609 enumerator_t
*enumerator
;
610 logger_entry_t
*entry
;
612 /* we set the loglevel on ALL sys- and file-loggers */
613 this->mutex
->lock(this->mutex
);
614 enumerator
= this->loggers
->create_enumerator(this->loggers
);
615 while (enumerator
->enumerate(enumerator
, &entry
))
620 entry
->logger
.file
->set_level(entry
->logger
.file
, group
, level
);
621 charon
->bus
->add_logger(charon
->bus
,
622 &entry
->logger
.file
->logger
);
625 entry
->logger
.sys
->set_level(entry
->logger
.sys
, group
, level
);
626 charon
->bus
->add_logger(charon
->bus
,
627 &entry
->logger
.sys
->logger
);
630 entry
->logger
.custom
->set_level(entry
->logger
.custom
, group
,
632 charon
->bus
->add_logger(charon
->bus
,
633 &entry
->logger
.sys
->logger
);
637 enumerator
->destroy(enumerator
);
638 this->mutex
->unlock(this->mutex
);
642 * Clean up all daemon resources
644 static void destroy(private_daemon_t
*this)
646 /* terminate all idle threads */
647 lib
->processor
->set_threads(lib
->processor
, 0);
648 /* make sure nobody waits for a DNS query */
649 lib
->hosts
->flush(lib
->hosts
);
650 /* close all IKE_SAs */
651 if (this->public.ike_sa_manager
)
653 this->public.ike_sa_manager
->flush(this->public.ike_sa_manager
);
655 if (this->public.traps
)
657 this->public.traps
->flush(this->public.traps
);
659 if (this->public.shunts
)
661 this->public.shunts
->flush(this->public.shunts
);
663 if (this->public.sender
)
665 this->public.sender
->flush(this->public.sender
);
668 /* cancel all threads and wait for their termination */
669 lib
->processor
->cancel(lib
->processor
);
672 DESTROY_IF(this->public.connect_manager
);
673 DESTROY_IF(this->public.mediation_manager
);
675 /* make sure the cache and scheduler are clear before unloading plugins */
676 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_ANY
);
677 lib
->scheduler
->flush(lib
->scheduler
);
678 lib
->plugins
->unload(lib
->plugins
);
679 DESTROY_IF(this->public.attributes
);
680 DESTROY_IF(this->kernel_handler
);
681 DESTROY_IF(this->public.traps
);
682 DESTROY_IF(this->public.shunts
);
683 DESTROY_IF(this->public.controller
);
684 DESTROY_IF(this->public.eap
);
685 DESTROY_IF(this->public.xauth
);
686 DESTROY_IF(this->public.backends
);
687 DESTROY_IF(this->public.socket
);
689 /* rehook library logging, shutdown logging */
691 DESTROY_IF(this->public.bus
);
692 this->loggers
->destroy_function(this->loggers
, (void*)logger_entry_destroy
);
693 this->mutex
->destroy(this->mutex
);
698 * Run a set of configured scripts
700 static void run_scripts(private_daemon_t
*this, char *verb
)
702 enumerator_t
*enumerator
;
703 char *key
, *value
, *pos
, buf
[1024];
706 enumerator
= lib
->settings
->create_key_value_enumerator(lib
->settings
,
707 "%s.%s-scripts", lib
->ns
, verb
);
708 while (enumerator
->enumerate(enumerator
, &key
, &value
))
710 DBG1(DBG_DMN
, "executing %s script '%s' (%s):", verb
, key
, value
);
711 cmd
= popen(value
, "r");
714 DBG1(DBG_DMN
, "executing %s script '%s' (%s) failed: %s",
715 verb
, key
, value
, strerror(errno
));
720 if (!fgets(buf
, sizeof(buf
), cmd
))
724 DBG1(DBG_DMN
, "reading from %s script '%s' (%s) failed",
731 pos
= buf
+ strlen(buf
);
732 if (pos
> buf
&& pos
[-1] == '\n')
736 DBG1(DBG_DMN
, "%s: %s", key
, buf
);
741 enumerator
->destroy(enumerator
);
744 METHOD(daemon_t
, start
, void,
745 private_daemon_t
*this)
747 /* start the engine, go multithreaded */
748 lib
->processor
->set_threads(lib
->processor
,
749 lib
->settings
->get_int(lib
->settings
, "%s.threads",
750 DEFAULT_THREADS
, lib
->ns
));
752 run_scripts(this, "start");
756 * Initialize/deinitialize sender and receiver
758 static bool sender_receiver_cb(void *plugin
, plugin_feature_t
*feature
,
759 bool reg
, private_daemon_t
*this)
763 this->public.receiver
= receiver_create();
764 if (!this->public.receiver
)
768 this->public.sender
= sender_create();
772 DESTROY_IF(this->public.receiver
);
773 DESTROY_IF(this->public.sender
);
779 * Initialize/deinitialize IKE_SA/CHILD_SA managers
781 static bool sa_managers_cb(void *plugin
, plugin_feature_t
*feature
,
782 bool reg
, private_daemon_t
*this)
786 this->public.ike_sa_manager
= ike_sa_manager_create();
787 if (!this->public.ike_sa_manager
)
791 this->public.child_sa_manager
= child_sa_manager_create();
795 DESTROY_IF(this->public.ike_sa_manager
);
796 DESTROY_IF(this->public.child_sa_manager
);
801 METHOD(daemon_t
, initialize
, bool,
802 private_daemon_t
*this, char *plugins
)
804 plugin_feature_t features
[] = {
805 PLUGIN_PROVIDE(CUSTOM
, "libcharon"),
806 PLUGIN_DEPENDS(NONCE_GEN
),
807 PLUGIN_DEPENDS(CUSTOM
, "libcharon-sa-managers"),
808 PLUGIN_DEPENDS(CUSTOM
, "libcharon-receiver"),
809 PLUGIN_DEPENDS(CUSTOM
, "kernel-ipsec"),
810 PLUGIN_DEPENDS(CUSTOM
, "kernel-net"),
811 PLUGIN_CALLBACK((plugin_feature_callback_t
)sender_receiver_cb
, this),
812 PLUGIN_PROVIDE(CUSTOM
, "libcharon-receiver"),
813 PLUGIN_DEPENDS(HASHER
, HASH_SHA1
),
814 PLUGIN_DEPENDS(RNG
, RNG_STRONG
),
815 PLUGIN_DEPENDS(CUSTOM
, "socket"),
816 PLUGIN_CALLBACK((plugin_feature_callback_t
)sa_managers_cb
, this),
817 PLUGIN_PROVIDE(CUSTOM
, "libcharon-sa-managers"),
818 PLUGIN_DEPENDS(HASHER
, HASH_SHA1
),
819 PLUGIN_DEPENDS(RNG
, RNG_WEAK
),
821 lib
->plugins
->add_static_features(lib
->plugins
, lib
->ns
, features
,
822 countof(features
), TRUE
, NULL
, NULL
);
824 /* load plugins, further infrastructure may need it */
825 if (!lib
->plugins
->load(lib
->plugins
, plugins
))
830 /* Queue start_action job */
831 lib
->processor
->queue_job(lib
->processor
, (job_t
*)start_action_job_create());
834 this->public.connect_manager
= connect_manager_create();
835 if (this->public.connect_manager
== NULL
)
839 this->public.mediation_manager
= mediation_manager_create();
848 private_daemon_t
*daemon_create()
850 private_daemon_t
*this;
854 .initialize
= _initialize
,
856 .load_loggers
= _load_loggers
,
857 .set_level
= _set_level
,
860 .loggers
= linked_list_create(),
861 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
864 charon
= &this->public;
865 this->public.attributes
= attribute_manager_create();
866 this->public.controller
= controller_create();
867 this->public.eap
= eap_manager_create();
868 this->public.xauth
= xauth_manager_create();
869 this->public.backends
= backend_manager_create();
870 this->public.socket
= socket_manager_create();
871 this->public.traps
= trap_manager_create();
872 this->public.shunts
= shunt_manager_create();
873 this->kernel_handler
= kernel_handler_create();
879 * Described in header.
881 void libcharon_deinit()
883 private_daemon_t
*this = (private_daemon_t
*)charon
;
885 if (!this || !ref_put(&this->ref
))
886 { /* have more users */
890 run_scripts(this, "stop");
897 * Described in header.
899 bool libcharon_init()
901 private_daemon_t
*this;
904 { /* already initialized, increase refcount */
905 this = (private_daemon_t
*)charon
;
907 return !this->integrity_failed
;
910 this = daemon_create();
912 /* for uncritical pseudo random numbers */
913 srandom(time(NULL
) + getpid());
915 /* set up hook to log dbg message in library via charons message bus */
919 lib
->printf_hook
->add_handler(lib
->printf_hook
, 'P',
920 proposal_printf_hook
,
921 PRINTF_HOOK_ARGTYPE_POINTER
,
922 PRINTF_HOOK_ARGTYPE_END
);
924 if (lib
->integrity
&&
925 !lib
->integrity
->check(lib
->integrity
, "libcharon", libcharon_init
))
927 dbg(DBG_DMN
, 1, "integrity check of libcharon failed");
928 this->integrity_failed
= TRUE
;
930 return !this->integrity_failed
;