Return to charon-systemd.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon-systemd |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2006-2018 Tobias Brunner ! 3: * Copyright (C) 2005-2014 Martin Willi ! 4: * Copyright (C) 2006 Daniel Roethlisberger ! 5: * Copyright (C) 2005 Jan Hutter ! 6: * HSR Hochschule fuer Technik Rapperswil ! 7: * Copyright (C) 2014 revosec AG ! 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 <signal.h> ! 21: #include <stdio.h> ! 22: #include <pthread.h> ! 23: #include <sys/stat.h> ! 24: #include <sys/types.h> ! 25: #include <sys/utsname.h> ! 26: #include <unistd.h> ! 27: #include <errno.h> ! 28: ! 29: /* won't make sense from our logging hook */ ! 30: #define SD_JOURNAL_SUPPRESS_LOCATION ! 31: #include <systemd/sd-daemon.h> ! 32: #include <systemd/sd-journal.h> ! 33: ! 34: #include <daemon.h> ! 35: ! 36: #include <library.h> ! 37: #include <utils/backtrace.h> ! 38: #include <threading/thread.h> ! 39: #include <threading/rwlock.h> ! 40: ! 41: /** ! 42: * Default user and group ! 43: */ ! 44: #ifndef IPSEC_USER ! 45: #define IPSEC_USER NULL ! 46: #endif ! 47: ! 48: #ifndef IPSEC_GROUP ! 49: #define IPSEC_GROUP NULL ! 50: #endif ! 51: ! 52: /** ! 53: * hook in library for debugging messages ! 54: */ ! 55: extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); ! 56: ! 57: /** ! 58: * Logging hook for library logs, using stderr output ! 59: */ ! 60: static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) ! 61: { ! 62: va_list args; ! 63: ! 64: if (level <= 1) ! 65: { ! 66: va_start(args, fmt); ! 67: fprintf(stderr, "00[%N] ", debug_names, group); ! 68: vfprintf(stderr, fmt, args); ! 69: fprintf(stderr, "\n"); ! 70: va_end(args); ! 71: } ! 72: } ! 73: ! 74: typedef struct journal_logger_t journal_logger_t; ! 75: ! 76: /** ! 77: * Logger implementation using systemd-journal ! 78: */ ! 79: struct journal_logger_t { ! 80: ! 81: /** ! 82: * Public interface ! 83: */ ! 84: custom_logger_t public; ! 85: ! 86: /** ! 87: * Configured loglevels ! 88: */ ! 89: level_t levels[DBG_MAX]; ! 90: ! 91: /** ! 92: * Lock for levels ! 93: */ ! 94: rwlock_t *lock; ! 95: }; ! 96: ! 97: METHOD(logger_t, vlog, void, ! 98: journal_logger_t *this, debug_t group, level_t level, int thread, ! 99: ike_sa_t *ike_sa, const char *fmt, va_list args) ! 100: { ! 101: char buf[4096], *msg = buf; ! 102: ssize_t len; ! 103: va_list copy; ! 104: ! 105: va_copy(copy, args); ! 106: len = vsnprintf(msg, sizeof(buf), fmt, copy); ! 107: va_end(copy); ! 108: ! 109: if (len >= sizeof(buf)) ! 110: { ! 111: len++; ! 112: msg = malloc(len); ! 113: va_copy(copy, args); ! 114: len = vsnprintf(msg, len, fmt, copy); ! 115: va_end(copy); ! 116: } ! 117: if (len > 0) ! 118: { ! 119: char unique[64] = "", name[256] = ""; ! 120: int priority; ! 121: ! 122: if (ike_sa) ! 123: { ! 124: snprintf(unique, sizeof(unique), "IKE_SA_UNIQUE_ID=%u", ! 125: ike_sa->get_unique_id(ike_sa)); ! 126: if (ike_sa->get_peer_cfg(ike_sa)) ! 127: { ! 128: snprintf(name, sizeof(name), "IKE_SA_NAME=%s", ! 129: ike_sa->get_name(ike_sa)); ! 130: } ! 131: } ! 132: switch (level) ! 133: { ! 134: case LEVEL_AUDIT: ! 135: priority = LOG_NOTICE; ! 136: break; ! 137: case LEVEL_CTRL: ! 138: priority = LOG_INFO; ! 139: break; ! 140: default: ! 141: priority = LOG_DEBUG; ! 142: break; ! 143: } ! 144: sd_journal_send( ! 145: "MESSAGE=%s", msg, ! 146: "MESSAGE_ID=57d2708c-d607-43bd-8c39-66bf%.8x", ! 147: chunk_hash_static(chunk_from_str((char*)fmt)), ! 148: "PRIORITY=%d", priority, ! 149: "GROUP=%N", debug_names, group, ! 150: "LEVEL=%d", level, ! 151: "THREAD=%d", thread, ! 152: unique[0] ? unique : NULL, ! 153: name[0] ? name : NULL, ! 154: NULL); ! 155: } ! 156: if (msg != buf) ! 157: { ! 158: free(msg); ! 159: } ! 160: } ! 161: ! 162: METHOD(logger_t, get_level, level_t, ! 163: journal_logger_t *this, debug_t group) ! 164: { ! 165: level_t level; ! 166: ! 167: this->lock->read_lock(this->lock); ! 168: level = this->levels[group]; ! 169: this->lock->unlock(this->lock); ! 170: ! 171: return level; ! 172: } ! 173: ! 174: METHOD(custom_logger_t, set_level, void, ! 175: journal_logger_t *this, debug_t group, level_t level) ! 176: { ! 177: this->lock->write_lock(this->lock); ! 178: this->levels[group] = level; ! 179: this->lock->unlock(this->lock); ! 180: } ! 181: ! 182: METHOD(custom_logger_t, logger_destroy, void, ! 183: journal_logger_t *this) ! 184: { ! 185: this->lock->destroy(this->lock); ! 186: free(this); ! 187: } ! 188: ! 189: static custom_logger_t *journal_logger_create(const char *name) ! 190: { ! 191: journal_logger_t *this; ! 192: ! 193: INIT(this, ! 194: .public = { ! 195: .logger = { ! 196: .vlog = _vlog, ! 197: .get_level = _get_level, ! 198: }, ! 199: .set_level = _set_level, ! 200: .destroy = _logger_destroy, ! 201: }, ! 202: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ! 203: ); ! 204: return &this->public; ! 205: } ! 206: ! 207: /** ! 208: * Run the daemon and handle unix signals ! 209: */ ! 210: static int run() ! 211: { ! 212: sigset_t set; ! 213: ! 214: sigemptyset(&set); ! 215: sigaddset(&set, SIGHUP); ! 216: sigaddset(&set, SIGTERM); ! 217: sigprocmask(SIG_BLOCK, &set, NULL); ! 218: ! 219: sd_notify(0, "READY=1\n"); ! 220: ! 221: while (TRUE) ! 222: { ! 223: int sig; ! 224: ! 225: sig = sigwaitinfo(&set, NULL); ! 226: if (sig == -1) ! 227: { ! 228: if (errno == EINTR) ! 229: { /* ignore signals we didn't wait for */ ! 230: continue; ! 231: } ! 232: DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno)); ! 233: return SS_RC_INITIALIZATION_FAILED; ! 234: } ! 235: switch (sig) ! 236: { ! 237: case SIGHUP: ! 238: { ! 239: DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " ! 240: "configuration"); ! 241: if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) ! 242: { ! 243: charon->load_loggers(charon); ! 244: lib->plugins->reload(lib->plugins, NULL); ! 245: } ! 246: else ! 247: { ! 248: DBG1(DBG_DMN, "reloading config failed, keeping old"); ! 249: } ! 250: break; ! 251: } ! 252: case SIGTERM: ! 253: { ! 254: DBG1(DBG_DMN, "SIGTERM received, shutting down"); ! 255: charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); ! 256: return 0; ! 257: } ! 258: } ! 259: } ! 260: } ! 261: ! 262: /** ! 263: * lookup UID and GID ! 264: */ ! 265: static bool lookup_uid_gid() ! 266: { ! 267: char *name; ! 268: ! 269: name = lib->settings->get_str(lib->settings, "%s.user", IPSEC_USER, ! 270: lib->ns); ! 271: if (name && !lib->caps->resolve_uid(lib->caps, name)) ! 272: { ! 273: return FALSE; ! 274: } ! 275: name = lib->settings->get_str(lib->settings, "%s.group", IPSEC_GROUP, ! 276: lib->ns); ! 277: if (name && !lib->caps->resolve_gid(lib->caps, name)) ! 278: { ! 279: return FALSE; ! 280: } ! 281: return TRUE; ! 282: } ! 283: ! 284: #ifndef DISABLE_SIGNAL_HANDLER ! 285: /** ! 286: * Handle SIGSEGV/SIGILL signals raised by threads ! 287: */ ! 288: static void segv_handler(int signal) ! 289: { ! 290: backtrace_t *backtrace; ! 291: ! 292: DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); ! 293: backtrace = backtrace_create(2); ! 294: backtrace->log(backtrace, NULL, TRUE); ! 295: backtrace->log(backtrace, stderr, TRUE); ! 296: backtrace->destroy(backtrace); ! 297: ! 298: DBG1(DBG_DMN, "killing ourself, received critical signal"); ! 299: abort(); ! 300: } ! 301: #endif /* DISABLE_SIGNAL_HANDLER */ ! 302: ! 303: /** ! 304: * Add namespace alias ! 305: */ ! 306: static void __attribute__ ((constructor))register_namespace() ! 307: { ! 308: /* inherit settings from charon */ ! 309: library_add_namespace("charon"); ! 310: } ! 311: ! 312: /** ! 313: * Register journal logger ! 314: */ ! 315: static void __attribute__ ((constructor))register_logger() ! 316: { ! 317: register_custom_logger("journal", journal_logger_create); ! 318: } ! 319: ! 320: /** ! 321: * Main function, starts the daemon. ! 322: */ ! 323: int main(int argc, char *argv[]) ! 324: { ! 325: struct sigaction action; ! 326: struct utsname utsname; ! 327: int status = SS_RC_INITIALIZATION_FAILED; ! 328: ! 329: dbg = dbg_stderr; ! 330: ! 331: if (uname(&utsname) != 0) ! 332: { ! 333: memset(&utsname, 0, sizeof(utsname)); ! 334: } ! 335: ! 336: sd_notifyf(0, "STATUS=Starting charon-systemd, strongSwan %s, %s %s, %s", ! 337: VERSION, utsname.sysname, utsname.release, utsname.machine); ! 338: ! 339: atexit(library_deinit); ! 340: if (!library_init(NULL, "charon-systemd")) ! 341: { ! 342: sd_notifyf(0, "STATUS=libstrongswan initialization failed"); ! 343: return SS_RC_INITIALIZATION_FAILED; ! 344: } ! 345: if (lib->integrity && ! 346: !lib->integrity->check_file(lib->integrity, "charon-systemd", argv[0])) ! 347: { ! 348: sd_notifyf(0, "STATUS=integrity check of charon-systemd failed"); ! 349: return SS_RC_INITIALIZATION_FAILED; ! 350: } ! 351: if (!libcharon_init()) ! 352: { ! 353: sd_notifyf(0, "STATUS=libcharon initialization failed"); ! 354: goto error; ! 355: } ! 356: if (!lookup_uid_gid()) ! 357: { ! 358: sd_notifyf(0, "STATUS=unknown uid/gid"); ! 359: goto error; ! 360: } ! 361: /* we registered the journal logger as custom logger, which gets its ! 362: * settings from <ns>.customlog.journal, let it fallback to <ns>.journal */ ! 363: lib->settings->add_fallback(lib->settings, "%s.customlog.journal", ! 364: "%s.journal", lib->ns); ! 365: /* load the journal logger by default */ ! 366: lib->settings->set_default_str(lib->settings, "%s.journal.default", "1", ! 367: lib->ns); ! 368: ! 369: charon->load_loggers(charon); ! 370: ! 371: if (!charon->initialize(charon, ! 372: lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns))) ! 373: { ! 374: sd_notifyf(0, "STATUS=charon initialization failed"); ! 375: goto error; ! 376: } ! 377: lib->plugins->status(lib->plugins, LEVEL_CTRL); ! 378: ! 379: if (!lib->caps->drop(lib->caps)) ! 380: { ! 381: sd_notifyf(0, "STATUS=dropping capabilities failed"); ! 382: goto error; ! 383: } ! 384: ! 385: /* add handler for fatal signals, ! 386: * INT, TERM and HUP are handled by sigwaitinfo() in run() */ ! 387: action.sa_flags = 0; ! 388: sigemptyset(&action.sa_mask); ! 389: sigaddset(&action.sa_mask, SIGINT); ! 390: sigaddset(&action.sa_mask, SIGTERM); ! 391: sigaddset(&action.sa_mask, SIGHUP); ! 392: ! 393: /* optionally let the external system handle fatal signals */ ! 394: #ifndef DISABLE_SIGNAL_HANDLER ! 395: action.sa_handler = segv_handler; ! 396: sigaction(SIGSEGV, &action, NULL); ! 397: sigaction(SIGILL, &action, NULL); ! 398: sigaction(SIGBUS, &action, NULL); ! 399: #endif /* DISABLE_SIGNAL_HANDLER */ ! 400: ! 401: action.sa_handler = SIG_IGN; ! 402: sigaction(SIGPIPE, &action, NULL); ! 403: ! 404: pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); ! 405: ! 406: charon->start(charon); ! 407: ! 408: sd_notifyf(0, "STATUS=charon-systemd running, strongSwan %s, %s %s, %s", ! 409: VERSION, utsname.sysname, utsname.release, utsname.machine); ! 410: ! 411: status = run(); ! 412: ! 413: error: ! 414: libcharon_deinit(); ! 415: return status; ! 416: }