682b0eef11611e24411f747f91dc122cc9680ab5
[strongswan.git] / src / libcharon / daemon.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 <stdio.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <syslog.h>
23 #include <time.h>
24
25 #include "daemon.h"
26
27 #include <library.h>
28 #include <bus/listeners/sys_logger.h>
29 #include <bus/listeners/file_logger.h>
30 #include <config/proposal.h>
31 #include <plugins/plugin_feature.h>
32 #include <kernel/kernel_handler.h>
33 #include <processing/jobs/start_action_job.h>
34 #include <threading/mutex.h>
35
36 #ifndef LOG_AUTHPRIV /* not defined on OpenSolaris */
37 #define LOG_AUTHPRIV LOG_AUTH
38 #endif
39
40 typedef struct private_daemon_t private_daemon_t;
41
42 /**
43 * Private additions to daemon_t, contains threads and internal functions.
44 */
45 struct private_daemon_t {
46 /**
47 * Public members of daemon_t.
48 */
49 daemon_t public;
50
51 /**
52 * Handler for kernel events
53 */
54 kernel_handler_t *kernel_handler;
55
56 /**
57 * A list of installed loggers (as logger_entry_t*)
58 */
59 linked_list_t *loggers;
60
61 /**
62 * Identifier used for syslog (in the openlog call)
63 */
64 char *syslog_identifier;
65
66 /**
67 * Mutex for configured loggers
68 */
69 mutex_t *mutex;
70
71 /**
72 * Integrity check failed?
73 */
74 bool integrity_failed;
75
76 /**
77 * Number of times we have been initialized
78 */
79 refcount_t ref;
80 };
81
82 /**
83 * One and only instance of the daemon.
84 */
85 daemon_t *charon;
86
87 /**
88 * hook in library for debugging messages
89 */
90 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
91
92 /**
93 * we store the previous debug function so we can reset it
94 */
95 static void (*dbg_old) (debug_t group, level_t level, char *fmt, ...);
96
97 /**
98 * Logging hook for library logs, spreads debug message over bus
99 */
100 static void dbg_bus(debug_t group, level_t level, char *fmt, ...)
101 {
102 va_list args;
103
104 va_start(args, fmt);
105 charon->bus->vlog(charon->bus, group, level, fmt, args);
106 va_end(args);
107 }
108
109 /**
110 * Some metadata about configured loggers
111 */
112 typedef struct {
113 /**
114 * Target of the logger (syslog facility or filename)
115 */
116 char *target;
117
118 /**
119 * TRUE if this is a file logger
120 */
121 bool file;
122
123 /**
124 * The actual logger
125 */
126 union {
127 sys_logger_t *sys;
128 file_logger_t *file;
129 } logger;
130
131 } logger_entry_t;
132
133 /**
134 * Destroy a logger entry
135 */
136 static void logger_entry_destroy(logger_entry_t *this)
137 {
138 if (this->file)
139 {
140 DESTROY_IF(this->logger.file);
141 }
142 else
143 {
144 DESTROY_IF(this->logger.sys);
145 }
146 free(this->target);
147 free(this);
148 }
149
150 /**
151 * Unregister and destroy a logger entry
152 */
153 static void logger_entry_unregister_destroy(logger_entry_t *this)
154 {
155 if (this->file)
156 {
157 charon->bus->remove_logger(charon->bus, &this->logger.file->logger);
158 }
159 else
160 {
161 charon->bus->remove_logger(charon->bus, &this->logger.sys->logger);
162 }
163 logger_entry_destroy(this);
164 }
165
166 /**
167 * Match a logger entry by target and whether it is a file or syslog logger
168 */
169 static bool logger_entry_match(logger_entry_t *this, char *target, bool *file)
170 {
171 return this->file == *file && streq(this->target, target);
172 }
173
174 /**
175 * Handle configured syslog identifier
176 *
177 * mutex must be locked when calling this function
178 */
179 static void handle_syslog_identifier(private_daemon_t *this)
180 {
181 char *identifier;
182
183 identifier = lib->settings->get_str(lib->settings, "%s.syslog.identifier",
184 NULL, lib->ns);
185 if (identifier)
186 { /* set identifier, which is prepended to each log line */
187 if (!this->syslog_identifier ||
188 !streq(identifier, this->syslog_identifier))
189 {
190 closelog();
191 this->syslog_identifier = identifier;
192 openlog(this->syslog_identifier, 0, 0);
193 }
194 }
195 else if (this->syslog_identifier)
196 {
197 closelog();
198 this->syslog_identifier = NULL;
199 }
200 }
201
202 /**
203 * Convert the given string into a syslog facility, returns -1 if the facility
204 * is not supported
205 */
206 static int get_syslog_facility(char *facility)
207 {
208 if (streq(facility, "daemon"))
209 {
210 return LOG_DAEMON;
211 }
212 else if (streq(facility, "auth"))
213 {
214 return LOG_AUTHPRIV;
215 }
216 return -1;
217 }
218
219 /**
220 * Returns an existing or newly created logger entry (if found, it is removed
221 * from the given linked list of existing loggers)
222 */
223 static logger_entry_t *get_logger_entry(char *target, bool is_file_logger,
224 linked_list_t *existing)
225 {
226 logger_entry_t *entry;
227
228 if (existing->find_first(existing, (void*)logger_entry_match,
229 (void**)&entry, target, &is_file_logger) != SUCCESS)
230 {
231 INIT(entry,
232 .target = strdup(target),
233 .file = is_file_logger,
234 );
235 if (is_file_logger)
236 {
237 entry->logger.file = file_logger_create(target);
238 }
239 else
240 {
241 entry->logger.sys = sys_logger_create(get_syslog_facility(target));
242 }
243 }
244 else
245 {
246 existing->remove(existing, entry, NULL);
247 }
248 return entry;
249 }
250
251 /**
252 * Create or reuse a syslog logger
253 */
254 static sys_logger_t *add_sys_logger(private_daemon_t *this, char *facility,
255 linked_list_t *current_loggers)
256 {
257 logger_entry_t *entry;
258
259 entry = get_logger_entry(facility, FALSE, current_loggers);
260 this->loggers->insert_last(this->loggers, entry);
261 return entry->logger.sys;
262 }
263
264 /**
265 * Create or reuse a file logger
266 */
267 static file_logger_t *add_file_logger(private_daemon_t *this, char *filename,
268 linked_list_t *current_loggers)
269 {
270 logger_entry_t *entry;
271
272 entry = get_logger_entry(filename, TRUE, current_loggers);
273 this->loggers->insert_last(this->loggers, entry);
274 return entry->logger.file;
275 }
276
277 /**
278 * Load the given syslog logger configured in strongswan.conf
279 */
280 static void load_sys_logger(private_daemon_t *this, char *facility,
281 linked_list_t *current_loggers)
282 {
283 sys_logger_t *sys_logger;
284 debug_t group;
285 level_t def;
286
287 if (get_syslog_facility(facility) == -1)
288 {
289 return;
290 }
291
292 sys_logger = add_sys_logger(this, facility, current_loggers);
293 sys_logger->set_options(sys_logger,
294 lib->settings->get_bool(lib->settings, "%s.syslog.%s.ike_name",
295 FALSE, lib->ns, facility));
296
297 def = lib->settings->get_int(lib->settings, "%s.syslog.%s.default", 1,
298 lib->ns, facility);
299 for (group = 0; group < DBG_MAX; group++)
300 {
301 sys_logger->set_level(sys_logger, group,
302 lib->settings->get_int(lib->settings, "%s.syslog.%s.%N", def,
303 lib->ns, facility, debug_lower_names, group));
304 }
305 charon->bus->add_logger(charon->bus, &sys_logger->logger);
306 }
307
308 /**
309 * Load the given file logger configured in strongswan.conf
310 */
311 static void load_file_logger(private_daemon_t *this, char *filename,
312 linked_list_t *current_loggers)
313 {
314 file_logger_t *file_logger;
315 debug_t group;
316 level_t def;
317 bool ike_name, flush_line, append;
318 char *time_format;
319
320 time_format = lib->settings->get_str(lib->settings,
321 "%s.filelog.%s.time_format", NULL, lib->ns, filename);
322 ike_name = lib->settings->get_bool(lib->settings,
323 "%s.filelog.%s.ike_name", FALSE, lib->ns, filename);
324 flush_line = lib->settings->get_bool(lib->settings,
325 "%s.filelog.%s.flush_line", FALSE, lib->ns, filename);
326 append = lib->settings->get_bool(lib->settings,
327 "%s.filelog.%s.append", TRUE, lib->ns, filename);
328
329 file_logger = add_file_logger(this, filename, current_loggers);
330 file_logger->set_options(file_logger, time_format, ike_name);
331 file_logger->open(file_logger, flush_line, append);
332
333 def = lib->settings->get_int(lib->settings, "%s.filelog.%s.default", 1,
334 lib->ns, filename);
335 for (group = 0; group < DBG_MAX; group++)
336 {
337 file_logger->set_level(file_logger, group,
338 lib->settings->get_int(lib->settings, "%s.filelog.%s.%N", def,
339 lib->ns, filename, debug_lower_names, group));
340 }
341 charon->bus->add_logger(charon->bus, &file_logger->logger);
342 }
343
344 METHOD(daemon_t, load_loggers, void,
345 private_daemon_t *this, level_t levels[DBG_MAX], bool to_stderr)
346 {
347 enumerator_t *enumerator;
348 linked_list_t *current_loggers;
349 char *target;
350
351 this->mutex->lock(this->mutex);
352 handle_syslog_identifier(this);
353 current_loggers = this->loggers;
354 this->loggers = linked_list_create();
355 enumerator = lib->settings->create_section_enumerator(lib->settings,
356 "%s.syslog", lib->ns);
357 while (enumerator->enumerate(enumerator, &target))
358 {
359 load_sys_logger(this, target, current_loggers);
360 }
361 enumerator->destroy(enumerator);
362
363 enumerator = lib->settings->create_section_enumerator(lib->settings,
364 "%s.filelog", lib->ns);
365 while (enumerator->enumerate(enumerator, &target))
366 {
367 load_file_logger(this, target, current_loggers);
368 }
369 enumerator->destroy(enumerator);
370
371 if (!this->loggers->get_count(this->loggers) && levels)
372 { /* setup legacy style default loggers configured via command-line */
373 file_logger_t *file_logger;
374 sys_logger_t *sys_logger;
375 debug_t group;
376
377 sys_logger = add_sys_logger(this, "daemon", current_loggers);
378 file_logger = add_file_logger(this, "stdout", current_loggers);
379 file_logger->open(file_logger, FALSE, FALSE);
380
381 for (group = 0; group < DBG_MAX; group++)
382 {
383 sys_logger->set_level(sys_logger, group, levels[group]);
384 if (to_stderr)
385 {
386 file_logger->set_level(file_logger, group, levels[group]);
387 }
388 }
389 charon->bus->add_logger(charon->bus, &sys_logger->logger);
390 charon->bus->add_logger(charon->bus, &file_logger->logger);
391
392 sys_logger = add_sys_logger(this, "auth", current_loggers);
393 sys_logger->set_level(sys_logger, DBG_ANY, LEVEL_AUDIT);
394 charon->bus->add_logger(charon->bus, &sys_logger->logger);
395 }
396 /* unregister and destroy any unused remaining loggers */
397 current_loggers->destroy_function(current_loggers,
398 (void*)logger_entry_unregister_destroy);
399 this->mutex->unlock(this->mutex);
400 }
401
402 METHOD(daemon_t, set_level, void,
403 private_daemon_t *this, debug_t group, level_t level)
404 {
405 enumerator_t *enumerator;
406 logger_entry_t *entry;
407
408 /* we set the loglevel on ALL sys- and file-loggers */
409 this->mutex->lock(this->mutex);
410 enumerator = this->loggers->create_enumerator(this->loggers);
411 while (enumerator->enumerate(enumerator, &entry))
412 {
413 if (entry->file)
414 {
415 entry->logger.file->set_level(entry->logger.file, group, level);
416 charon->bus->add_logger(charon->bus, &entry->logger.file->logger);
417 }
418 else
419 {
420 entry->logger.sys->set_level(entry->logger.sys, group, level);
421 charon->bus->add_logger(charon->bus, &entry->logger.sys->logger);
422 }
423 }
424 enumerator->destroy(enumerator);
425 this->mutex->unlock(this->mutex);
426 }
427
428 /**
429 * Clean up all daemon resources
430 */
431 static void destroy(private_daemon_t *this)
432 {
433 /* terminate all idle threads */
434 lib->processor->set_threads(lib->processor, 0);
435 /* make sure nobody waits for a DNS query */
436 lib->hosts->flush(lib->hosts);
437 /* close all IKE_SAs */
438 if (this->public.ike_sa_manager)
439 {
440 this->public.ike_sa_manager->flush(this->public.ike_sa_manager);
441 }
442 if (this->public.traps)
443 {
444 this->public.traps->flush(this->public.traps);
445 }
446 if (this->public.sender)
447 {
448 this->public.sender->flush(this->public.sender);
449 }
450
451 /* cancel all threads and wait for their termination */
452 lib->processor->cancel(lib->processor);
453
454 #ifdef ME
455 DESTROY_IF(this->public.connect_manager);
456 DESTROY_IF(this->public.mediation_manager);
457 #endif /* ME */
458 /* make sure the cache is clear before unloading plugins */
459 lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
460 lib->plugins->unload(lib->plugins);
461 DESTROY_IF(this->kernel_handler);
462 DESTROY_IF(this->public.traps);
463 DESTROY_IF(this->public.shunts);
464 DESTROY_IF(this->public.ike_sa_manager);
465 DESTROY_IF(this->public.controller);
466 DESTROY_IF(this->public.eap);
467 DESTROY_IF(this->public.xauth);
468 DESTROY_IF(this->public.backends);
469 DESTROY_IF(this->public.socket);
470
471 /* rehook library logging, shutdown logging */
472 dbg = dbg_old;
473 DESTROY_IF(this->public.bus);
474 this->loggers->destroy_function(this->loggers, (void*)logger_entry_destroy);
475 this->mutex->destroy(this->mutex);
476 free((void*)this->public.name);
477 free(this);
478 }
479
480 METHOD(daemon_t, start, void,
481 private_daemon_t *this)
482 {
483 /* start the engine, go multithreaded */
484 lib->processor->set_threads(lib->processor,
485 lib->settings->get_int(lib->settings, "%s.threads",
486 DEFAULT_THREADS, lib->ns));
487 }
488
489
490 /**
491 * Initialize/deinitialize sender and receiver
492 */
493 static bool sender_receiver_cb(void *plugin, plugin_feature_t *feature,
494 bool reg, private_daemon_t *this)
495 {
496 if (reg)
497 {
498 this->public.receiver = receiver_create();
499 if (!this->public.receiver)
500 {
501 return FALSE;
502 }
503 this->public.sender = sender_create();
504 }
505 else
506 {
507 DESTROY_IF(this->public.receiver);
508 DESTROY_IF(this->public.sender);
509 }
510 return TRUE;
511 }
512
513 METHOD(daemon_t, initialize, bool,
514 private_daemon_t *this, char *plugins)
515 {
516 plugin_feature_t features[] = {
517 PLUGIN_PROVIDE(CUSTOM, "libcharon"),
518 PLUGIN_DEPENDS(NONCE_GEN),
519 PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"),
520 PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"),
521 PLUGIN_DEPENDS(CUSTOM, "kernel-net"),
522 PLUGIN_CALLBACK((plugin_feature_callback_t)sender_receiver_cb, this),
523 PLUGIN_PROVIDE(CUSTOM, "libcharon-receiver"),
524 PLUGIN_DEPENDS(HASHER, HASH_SHA1),
525 PLUGIN_DEPENDS(RNG, RNG_STRONG),
526 PLUGIN_DEPENDS(CUSTOM, "socket"),
527 };
528 lib->plugins->add_static_features(lib->plugins, lib->ns, features,
529 countof(features), TRUE);
530
531 /* load plugins, further infrastructure may need it */
532 if (!lib->plugins->load(lib->plugins, plugins))
533 {
534 return FALSE;
535 }
536
537 this->public.ike_sa_manager = ike_sa_manager_create();
538 if (this->public.ike_sa_manager == NULL)
539 {
540 return FALSE;
541 }
542
543 /* Queue start_action job */
544 lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create());
545
546 #ifdef ME
547 this->public.connect_manager = connect_manager_create();
548 if (this->public.connect_manager == NULL)
549 {
550 return FALSE;
551 }
552 this->public.mediation_manager = mediation_manager_create();
553 #endif /* ME */
554
555 return TRUE;
556 }
557
558 /**
559 * Create the daemon.
560 */
561 private_daemon_t *daemon_create(const char *name)
562 {
563 private_daemon_t *this;
564
565 INIT(this,
566 .public = {
567 .initialize = _initialize,
568 .start = _start,
569 .load_loggers = _load_loggers,
570 .set_level = _set_level,
571 .bus = bus_create(),
572 .name = strdup(name ?: "libcharon"),
573 },
574 .loggers = linked_list_create(),
575 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
576 .ref = 1,
577 );
578 charon = &this->public;
579 this->public.controller = controller_create();
580 this->public.eap = eap_manager_create();
581 this->public.xauth = xauth_manager_create();
582 this->public.backends = backend_manager_create();
583 this->public.socket = socket_manager_create();
584 this->public.traps = trap_manager_create();
585 this->public.shunts = shunt_manager_create();
586 this->kernel_handler = kernel_handler_create();
587
588 return this;
589 }
590
591 /**
592 * Described in header.
593 */
594 void libcharon_deinit()
595 {
596 private_daemon_t *this = (private_daemon_t*)charon;
597
598 if (!this || !ref_put(&this->ref))
599 { /* have more users */
600 return;
601 }
602
603 destroy(this);
604 charon = NULL;
605 }
606
607 /**
608 * Described in header.
609 */
610 bool libcharon_init(const char *name)
611 {
612 private_daemon_t *this;
613
614 if (charon)
615 { /* already initialized, increase refcount */
616 this = (private_daemon_t*)charon;
617 ref_get(&this->ref);
618 return !this->integrity_failed;
619 }
620
621 this = daemon_create(name);
622
623 /* for uncritical pseudo random numbers */
624 srandom(time(NULL) + getpid());
625
626 /* set up hook to log dbg message in library via charons message bus */
627 dbg_old = dbg;
628 dbg = dbg_bus;
629
630 lib->printf_hook->add_handler(lib->printf_hook, 'P',
631 proposal_printf_hook,
632 PRINTF_HOOK_ARGTYPE_POINTER,
633 PRINTF_HOOK_ARGTYPE_END);
634
635 if (lib->integrity &&
636 !lib->integrity->check(lib->integrity, "libcharon", libcharon_init))
637 {
638 dbg(DBG_DMN, 1, "integrity check of libcharon failed");
639 this->integrity_failed = TRUE;
640 }
641 return !this->integrity_failed;
642 }