1773e7c3987cf8cdef61f3e0c1a63632ef9540f7
[strongswan.git] / src / charon-nm / charon-nm.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * 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
16 #include <stdio.h>
17 #include <syslog.h>
18 #include <signal.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <errno.h>
22
23 #include <hydra.h>
24 #include <daemon.h>
25
26 #include <library.h>
27 #include <utils/backtrace.h>
28 #include <threading/thread.h>
29
30 #include <nm/nm_backend.h>
31
32 /**
33 * Default user and group
34 */
35 #ifndef IPSEC_USER
36 #define IPSEC_USER NULL
37 #endif
38
39 #ifndef IPSEC_GROUP
40 #define IPSEC_GROUP NULL
41 #endif
42
43 /**
44 * Hook in library for debugging messages
45 */
46 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
47
48 /**
49 * Simple logging hook for library logs, using syslog output
50 */
51 static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
52 {
53 if (level <= 1)
54 {
55 char buffer[8192], groupstr[4];
56 va_list args;
57
58 va_start(args, fmt);
59 /* write in memory buffer first */
60 vsnprintf(buffer, sizeof(buffer), fmt, args);
61 /* cache group name */
62 snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
63 syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", groupstr, buffer);
64 va_end(args);
65 }
66 }
67
68 /**
69 * Run the daemon and handle unix signals
70 */
71 static void run()
72 {
73 sigset_t set;
74
75 /* handle SIGINT and SIGTERM in this handler */
76 sigemptyset(&set);
77 sigaddset(&set, SIGINT);
78 sigaddset(&set, SIGTERM);
79 sigprocmask(SIG_BLOCK, &set, NULL);
80
81 while (TRUE)
82 {
83 int sig;
84
85 sig = sigwaitinfo(&set, NULL);
86 if (sig == -1)
87 {
88 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
89 return;
90 }
91 switch (sig)
92 {
93 case SIGINT:
94 {
95 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
96 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
97 return;
98 }
99 case SIGTERM:
100 {
101 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
102 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
103 return;
104 }
105 default:
106 {
107 DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
108 break;
109 }
110 }
111 }
112 }
113
114 /**
115 * Handle SIGSEGV/SIGILL signals raised by threads
116 */
117 static void segv_handler(int signal)
118 {
119 backtrace_t *backtrace;
120
121 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
122 backtrace = backtrace_create(2);
123 backtrace->log(backtrace, stderr, TRUE);
124 backtrace->destroy(backtrace);
125
126 DBG1(DBG_DMN, "killing ourself, received critical signal");
127 abort();
128 }
129
130 /**
131 * Lookup UID and GID
132 */
133 static bool lookup_uid_gid()
134 {
135 char *name;
136
137 name = lib->settings->get_str(lib->settings, "charon-nm.user",
138 IPSEC_USER);
139 if (name && !lib->caps->resolve_uid(lib->caps, name))
140 {
141 return FALSE;
142 }
143 name = lib->settings->get_str(lib->settings, "charon-nm.group",
144 IPSEC_GROUP);
145 if (name && !lib->caps->resolve_gid(lib->caps, name))
146 {
147 return FALSE;
148 }
149 return TRUE;
150 }
151
152 /**
153 * Main function, starts NetworkManager backend.
154 */
155 int main(int argc, char *argv[])
156 {
157 struct sigaction action;
158 int status = SS_RC_INITIALIZATION_FAILED;
159
160 /* logging for library during initialization, as we have no bus yet */
161 dbg = dbg_syslog;
162
163 /* LD causes a crash probably due to Glib */
164 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
165
166 /* initialize library */
167 if (!library_init(NULL, "charon-nm"))
168 {
169 library_deinit();
170 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
171 }
172
173 if (lib->integrity &&
174 !lib->integrity->check_file(lib->integrity, "charon-nm", argv[0]))
175 {
176 dbg_syslog(DBG_DMN, 1, "integrity check of charon-nm failed");
177 library_deinit();
178 exit(SS_RC_DAEMON_INTEGRITY);
179 }
180
181 if (!libhydra_init())
182 {
183 dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
184 libhydra_deinit();
185 library_deinit();
186 exit(SS_RC_INITIALIZATION_FAILED);
187 }
188
189 if (!libcharon_init())
190 {
191 dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
192 goto deinit;
193 }
194
195 if (!lookup_uid_gid())
196 {
197 dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting charon-nm");
198 goto deinit;
199 }
200
201 /* make sure we log to the DAEMON facility by default */
202 lib->settings->set_int(lib->settings, "charon-nm.syslog.daemon.default",
203 lib->settings->get_int(lib->settings,
204 "charon-nm.syslog.daemon.default", 1));
205 charon->load_loggers(charon, NULL, FALSE);
206
207 /* use random ports to avoid conflicts with regular charon */
208 lib->settings->set_int(lib->settings, "charon-nm.port", 0);
209 lib->settings->set_int(lib->settings, "charon-nm.port_natt_t", 0);
210
211 DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
212 if (lib->integrity)
213 {
214 DBG1(DBG_DMN, "integrity tests enabled:");
215 DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests");
216 DBG1(DBG_DMN, "lib 'libhydra': passed file and segment integrity tests");
217 DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests");
218 DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test");
219 }
220
221 /* register NM backend to be loaded with plugins */
222 nm_backend_register();
223
224 /* initialize daemon */
225 if (!charon->initialize(charon,
226 lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS)))
227 {
228 DBG1(DBG_DMN, "initialization failed - aborting charon-nm");
229 goto deinit;
230 }
231 lib->plugins->status(lib->plugins, LEVEL_CTRL);
232
233 if (!lib->caps->drop(lib->caps))
234 {
235 DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm");
236 goto deinit;
237 }
238
239 /* add handler for SEGV and ILL,
240 * INT and TERM are handled by sigwaitinfo() in run() */
241 action.sa_handler = segv_handler;
242 action.sa_flags = 0;
243 sigemptyset(&action.sa_mask);
244 sigaddset(&action.sa_mask, SIGINT);
245 sigaddset(&action.sa_mask, SIGTERM);
246 sigaction(SIGSEGV, &action, NULL);
247 sigaction(SIGILL, &action, NULL);
248 sigaction(SIGBUS, &action, NULL);
249 action.sa_handler = SIG_IGN;
250 sigaction(SIGPIPE, &action, NULL);
251
252 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
253
254 /* start daemon (i.e. the threads in the thread-pool) */
255 charon->start(charon);
256
257 /* main thread goes to run loop */
258 run();
259
260 status = 0;
261
262 deinit:
263 libcharon_deinit();
264 libhydra_deinit();
265 library_deinit();
266 return status;
267 }
268