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