charon-nm.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (C) 2012 Tobias Brunner
  3. * HSR Hochschule fuer Technik Rapperswil
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <stdio.h>
  16. #include <syslog.h>
  17. #include <signal.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #include <errno.h>
  21. #include <daemon.h>
  22. #include <library.h>
  23. #include <utils/backtrace.h>
  24. #include <threading/thread.h>
  25. #include <nm/nm_backend.h>
  26. /**
  27. * Default user and group
  28. */
  29. #ifndef IPSEC_USER
  30. #define IPSEC_USER NULL
  31. #endif
  32. #ifndef IPSEC_GROUP
  33. #define IPSEC_GROUP NULL
  34. #endif
  35. /**
  36. * Hook in library for debugging messages
  37. */
  38. extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
  39. /**
  40. * Simple logging hook for library logs, using syslog output
  41. */
  42. static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
  43. {
  44. if (level <= 1)
  45. {
  46. char buffer[8192], groupstr[4];
  47. va_list args;
  48. va_start(args, fmt);
  49. /* write in memory buffer first */
  50. vsnprintf(buffer, sizeof(buffer), fmt, args);
  51. /* cache group name */
  52. snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
  53. syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", groupstr, buffer);
  54. va_end(args);
  55. }
  56. }
  57. /**
  58. * Run the daemon and handle unix signals
  59. */
  60. static void run()
  61. {
  62. sigset_t set;
  63. /* handle SIGINT and SIGTERM in this handler */
  64. sigemptyset(&set);
  65. sigaddset(&set, SIGINT);
  66. sigaddset(&set, SIGTERM);
  67. sigprocmask(SIG_BLOCK, &set, NULL);
  68. while (TRUE)
  69. {
  70. int sig;
  71. sig = sigwaitinfo(&set, NULL);
  72. if (sig == -1)
  73. {
  74. if (errno == EINTR)
  75. { /* ignore signals we didn't wait for */
  76. continue;
  77. }
  78. DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
  79. return;
  80. }
  81. switch (sig)
  82. {
  83. case SIGINT:
  84. {
  85. DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
  86. charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
  87. return;
  88. }
  89. case SIGTERM:
  90. {
  91. DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
  92. charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
  93. return;
  94. }
  95. }
  96. }
  97. }
  98. #ifndef DISABLE_SIGNAL_HANDLER
  99. /**
  100. * Handle SIGSEGV/SIGILL signals raised by threads
  101. */
  102. static void segv_handler(int signal)
  103. {
  104. backtrace_t *backtrace;
  105. DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
  106. backtrace = backtrace_create(2);
  107. backtrace->log(backtrace, stderr, TRUE);
  108. backtrace->destroy(backtrace);
  109. DBG1(DBG_DMN, "killing ourself, received critical signal");
  110. abort();
  111. }
  112. #endif /* DISABLE_SIGNAL_HANDLER */
  113. /**
  114. * Lookup UID and GID
  115. */
  116. static bool lookup_uid_gid()
  117. {
  118. char *name;
  119. name = lib->settings->get_str(lib->settings, "charon-nm.user",
  120. IPSEC_USER);
  121. if (name && !lib->caps->resolve_uid(lib->caps, name))
  122. {
  123. return FALSE;
  124. }
  125. name = lib->settings->get_str(lib->settings, "charon-nm.group",
  126. IPSEC_GROUP);
  127. if (name && !lib->caps->resolve_gid(lib->caps, name))
  128. {
  129. return FALSE;
  130. }
  131. return TRUE;
  132. }
  133. /**
  134. * Main function, starts NetworkManager backend.
  135. */
  136. int main(int argc, char *argv[])
  137. {
  138. struct sigaction action;
  139. int status = SS_RC_INITIALIZATION_FAILED;
  140. /* logging for library during initialization, as we have no bus yet */
  141. dbg = dbg_syslog;
  142. /* LD causes a crash probably due to Glib */
  143. setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
  144. /* initialize library */
  145. if (!library_init(NULL, "charon-nm"))
  146. {
  147. library_deinit();
  148. exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
  149. }
  150. if (lib->integrity &&
  151. !lib->integrity->check_file(lib->integrity, "charon-nm", argv[0]))
  152. {
  153. dbg_syslog(DBG_DMN, 1, "integrity check of charon-nm failed");
  154. library_deinit();
  155. exit(SS_RC_DAEMON_INTEGRITY);
  156. }
  157. if (!libcharon_init())
  158. {
  159. dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
  160. goto deinit;
  161. }
  162. if (!lookup_uid_gid())
  163. {
  164. dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting charon-nm");
  165. goto deinit;
  166. }
  167. /* make sure we log to the DAEMON facility by default */
  168. lib->settings->set_int(lib->settings, "charon-nm.syslog.daemon.default",
  169. lib->settings->get_int(lib->settings,
  170. "charon-nm.syslog.daemon.default", 1));
  171. charon->load_loggers(charon);
  172. /* use random ports to avoid conflicts with regular charon */
  173. lib->settings->set_int(lib->settings, "charon-nm.port", 0);
  174. lib->settings->set_int(lib->settings, "charon-nm.port_nat_t", 0);
  175. DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
  176. if (lib->integrity)
  177. {
  178. DBG1(DBG_DMN, "integrity tests enabled:");
  179. DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests");
  180. DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests");
  181. DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test");
  182. }
  183. /* register NM backend to be loaded with plugins */
  184. nm_backend_register();
  185. /* initialize daemon */
  186. if (!charon->initialize(charon,
  187. lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS)))
  188. {
  189. DBG1(DBG_DMN, "initialization failed - aborting charon-nm");
  190. goto deinit;
  191. }
  192. lib->plugins->status(lib->plugins, LEVEL_CTRL);
  193. if (!lib->caps->drop(lib->caps))
  194. {
  195. DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm");
  196. goto deinit;
  197. }
  198. /* add handler for fatal signals,
  199. * INT and TERM are handled by sigwaitinfo() in run() */
  200. action.sa_flags = 0;
  201. sigemptyset(&action.sa_mask);
  202. sigaddset(&action.sa_mask, SIGINT);
  203. sigaddset(&action.sa_mask, SIGTERM);
  204. /* optionally let the external system handle fatal signals */
  205. #ifndef DISABLE_SIGNAL_HANDLER
  206. action.sa_handler = segv_handler;
  207. sigaction(SIGSEGV, &action, NULL);
  208. sigaction(SIGILL, &action, NULL);
  209. sigaction(SIGBUS, &action, NULL);
  210. #endif /* DISABLE_SIGNAL_HANDLER */
  211. action.sa_handler = SIG_IGN;
  212. sigaction(SIGPIPE, &action, NULL);
  213. pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
  214. /* start daemon (i.e. the threads in the thread-pool) */
  215. charon->start(charon);
  216. /* main thread goes to run loop */
  217. run();
  218. status = 0;
  219. deinit:
  220. libcharon_deinit();
  221. library_deinit();
  222. return status;
  223. }