Use AUTH_RULE_IDENTITY_LOOSE 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 DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
210 if (lib->integrity)
211 {
212 DBG1(DBG_DMN, "integrity tests enabled:");
213 DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests");
214 DBG1(DBG_DMN, "lib 'libhydra': passed file and segment integrity tests");
215 DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests");
216 DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test");
217 }
218
219 /* register NM backend to be loaded with plugins */
220 nm_backend_register();
221
222 /* initialize daemon */
223 if (!charon->initialize(charon,
224 lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS)))
225 {
226 DBG1(DBG_DMN, "initialization failed - aborting charon-nm");
227 goto deinit;
228 }
229
230 if (!charon->caps->drop(charon->caps))
231 {
232 DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm");
233 goto deinit;
234 }
235
236 /* add handler for SEGV and ILL,
237 * INT and TERM are handled by sigwait() in run() */
238 action.sa_handler = segv_handler;
239 action.sa_flags = 0;
240 sigemptyset(&action.sa_mask);
241 sigaddset(&action.sa_mask, SIGINT);
242 sigaddset(&action.sa_mask, SIGTERM);
243 sigaction(SIGSEGV, &action, NULL);
244 sigaction(SIGILL, &action, NULL);
245 sigaction(SIGBUS, &action, NULL);
246 action.sa_handler = SIG_IGN;
247 sigaction(SIGPIPE, &action, NULL);
248
249 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
250
251 /* start daemon (i.e. the threads in the thread-pool) */
252 charon->start(charon);
253
254 /* main thread goes to run loop */
255 run();
256
257 status = 0;
258
259 deinit:
260 libcharon_deinit();
261 libhydra_deinit();
262 library_deinit();
263 return status;
264 }
265