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