Merge branch 'charon-systemd-reload-loggers'
[strongswan.git] / src / charon-cmd / charon-cmd.c
1 /*
2 * Copyright (C) 2006-2013 Tobias Brunner
3 * Copyright (C) 2005-2013 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include <stdio.h>
20 #include <signal.h>
21 #include <pthread.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24 #include <unistd.h>
25 #include <getopt.h>
26 #include <errno.h>
27
28 #include <library.h>
29 #include <daemon.h>
30 #include <utils/backtrace.h>
31 #include <threading/thread.h>
32
33 #include "cmd/cmd_options.h"
34 #include "cmd/cmd_connection.h"
35 #include "cmd/cmd_creds.h"
36
37 /**
38 * Default loglevel
39 */
40 static level_t default_loglevel = LEVEL_CTRL;
41
42 /**
43 * Connection to initiate
44 */
45 static cmd_connection_t *conn;
46
47 /**
48 * Credential backend
49 */
50 static cmd_creds_t *creds;
51
52 /**
53 * hook in library for debugging messages
54 */
55 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
56
57 /**
58 * Logging hook for library logs, using stderr output
59 */
60 static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
61 {
62 va_list args;
63
64 if (level <= default_loglevel)
65 {
66 va_start(args, fmt);
67 fprintf(stderr, "00[%N] ", debug_names, group);
68 vfprintf(stderr, fmt, args);
69 fprintf(stderr, "\n");
70 va_end(args);
71 }
72 }
73
74 /**
75 * Clean up connection definition atexit()
76 */
77 static void cleanup_conn()
78 {
79 DESTROY_IF(conn);
80 }
81
82 /**
83 * Clean up credentials atexit()
84 */
85 static void cleanup_creds()
86 {
87 DESTROY_IF(creds);
88 }
89
90 /**
91 * Run the daemon and handle unix signals
92 */
93 static int run()
94 {
95 sigset_t set;
96
97 /* handle SIGINT, SIGHUP and SIGTERM in this handler */
98 sigemptyset(&set);
99 sigaddset(&set, SIGINT);
100 sigaddset(&set, SIGHUP);
101 sigaddset(&set, SIGTERM);
102 sigaddset(&set, SIGUSR1);
103 sigprocmask(SIG_BLOCK, &set, NULL);
104
105 while (TRUE)
106 {
107 int sig;
108
109 sig = sigwaitinfo(&set, NULL);
110 if (sig == -1)
111 {
112 if (errno == EINTR)
113 { /* ignore signals we didn't wait for */
114 continue;
115 }
116 DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno));
117 return 1;
118 }
119 switch (sig)
120 {
121 case SIGHUP:
122 {
123 DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading "
124 "configuration");
125 if (lib->settings->load_files(lib->settings, lib->conf, FALSE))
126 {
127 charon->load_loggers(charon);
128 lib->plugins->reload(lib->plugins, NULL);
129 }
130 else
131 {
132 DBG1(DBG_DMN, "reloading config failed, keeping old");
133 }
134 break;
135 }
136 case SIGINT:
137 {
138 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
139 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
140 return 0;
141 }
142 case SIGTERM:
143 {
144 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
145 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
146 return 0;
147 }
148 case SIGUSR1:
149 { /* an error occurred */
150 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
151 return 1;
152 }
153 }
154 }
155 }
156
157 /**
158 * lookup UID and GID
159 */
160 static bool lookup_uid_gid()
161 {
162 #ifdef IPSEC_USER
163 if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER))
164 {
165 return FALSE;
166 }
167 #endif
168 #ifdef IPSEC_GROUP
169 if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP))
170 {
171 return FALSE;
172 }
173 #endif
174 return TRUE;
175 }
176
177 /**
178 * Handle SIGSEGV/SIGILL signals raised by threads
179 */
180 static void segv_handler(int signal)
181 {
182 backtrace_t *backtrace;
183
184 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
185 backtrace = backtrace_create(2);
186 backtrace->log(backtrace, stderr, TRUE);
187 backtrace->destroy(backtrace);
188
189 DBG1(DBG_DMN, "killing ourself, received critical signal");
190 abort();
191 }
192
193 /**
194 * Print command line usage and exit
195 */
196 static void usage(FILE *out, char *msg, char *binary)
197 {
198 static const int padto = 18;
199 char cmd[64], *pre, *post;
200 int i, line, pad;
201
202 if (msg)
203 {
204 fprintf(out, "%s\n", msg);
205 }
206 fprintf(out, "Usage: %s\n", binary);
207 for (i = 0; i < CMD_OPT_COUNT; i++)
208 {
209 switch (cmd_options[i].has_arg)
210 {
211 case required_argument:
212 pre = " <";
213 post = ">";
214 break;
215 case optional_argument:
216 pre = "[=";
217 post = "]";
218 break;
219 case no_argument:
220 default:
221 pre = " ";
222 post = " ";
223 break;
224 }
225 snprintf(cmd, sizeof(cmd), " --%s%s%s%s", cmd_options[i].name,
226 pre, cmd_options[i].arg, post);
227 pad = padto - strlen(cmd);
228 if (pad >= 1)
229 {
230 fprintf(out, "%s%-*s%s\n", cmd, pad, "", cmd_options[i].desc);
231 }
232 else
233 { /* write description to a separate line */
234 fprintf(out, "%s\n%-*s%s\n", cmd, padto, "", cmd_options[i].desc);
235 }
236 for (line = 0; line < countof(cmd_options[i].lines); line++)
237 {
238 if (cmd_options[i].lines[line])
239 {
240 fprintf(out, "%-*s%s\n", padto, "", cmd_options[i].lines[line]);
241 }
242 }
243 }
244 }
245
246 /**
247 * Handle command line options, if simple is TRUE only arguments like --help
248 * and --version are handled.
249 */
250 static void handle_arguments(int argc, char *argv[], bool simple)
251 {
252 struct option long_opts[CMD_OPT_COUNT + 1] = {};
253 int i, opt;
254
255 for (i = 0; i < CMD_OPT_COUNT; i++)
256 {
257 long_opts[i].name = cmd_options[i].name;
258 long_opts[i].val = cmd_options[i].id;
259 long_opts[i].has_arg = cmd_options[i].has_arg;
260 }
261 /* reset option parser */
262 optind = 1;
263 while (TRUE)
264 {
265 bool handled = FALSE;
266
267 opt = getopt_long(argc, argv, "", long_opts, NULL);
268 switch (opt)
269 {
270 case EOF:
271 break;
272 case CMD_OPT_HELP:
273 usage(stdout, NULL, argv[0]);
274 exit(0);
275 case CMD_OPT_VERSION:
276 printf("%s, strongSwan %s\n", "charon-cmd", VERSION);
277 exit(0);
278 case CMD_OPT_DEBUG:
279 default_loglevel = atoi(optarg);
280 continue;
281 default:
282 if (simple)
283 {
284 continue;
285 }
286 handled |= conn->handle(conn, opt, optarg);
287 handled |= creds->handle(creds, opt, optarg);
288 if (handled)
289 {
290 continue;
291 }
292 /* fall-through */
293 case '?':
294 /* missing argument, unrecognized option */
295 usage(stderr, NULL, argv[0]);
296 exit(1);
297 }
298 break;
299 }
300 }
301
302 /**
303 * Main function, starts the daemon.
304 */
305 int main(int argc, char *argv[])
306 {
307 struct sigaction action;
308 struct utsname utsname;
309 level_t levels[DBG_MAX];
310 int group;
311
312 /* handle simple arguments */
313 handle_arguments(argc, argv, TRUE);
314
315 dbg = dbg_stderr;
316 atexit(library_deinit);
317 if (!library_init(NULL, "charon-cmd"))
318 {
319 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
320 }
321 if (lib->integrity)
322 {
323 if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0]))
324 {
325 exit(SS_RC_DAEMON_INTEGRITY);
326 }
327 }
328 atexit(libcharon_deinit);
329 if (!libcharon_init())
330 {
331 exit(SS_RC_INITIALIZATION_FAILED);
332 }
333 for (group = 0; group < DBG_MAX; group++)
334 {
335 levels[group] = default_loglevel;
336 }
337 charon->set_default_loggers(charon, levels, TRUE);
338 charon->load_loggers(charon);
339
340 if (!lookup_uid_gid())
341 {
342 exit(SS_RC_INITIALIZATION_FAILED);
343 }
344 lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
345 lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
346 if (!charon->initialize(charon,
347 lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS)))
348 {
349 exit(SS_RC_INITIALIZATION_FAILED);
350 }
351 if (!lib->caps->drop(lib->caps))
352 {
353 exit(SS_RC_INITIALIZATION_FAILED);
354 }
355
356 conn = cmd_connection_create();
357 atexit(cleanup_conn);
358 creds = cmd_creds_create();
359 atexit(cleanup_creds);
360
361 /* handle all arguments */
362 handle_arguments(argc, argv, FALSE);
363
364 if (uname(&utsname) != 0)
365 {
366 memset(&utsname, 0, sizeof(utsname));
367 }
368 DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
369 VERSION, utsname.sysname, utsname.release, utsname.machine);
370 lib->plugins->status(lib->plugins, LEVEL_CTRL);
371
372 /* add handler for SEGV and ILL,
373 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
374 action.sa_handler = segv_handler;
375 action.sa_flags = 0;
376 sigemptyset(&action.sa_mask);
377 sigaddset(&action.sa_mask, SIGINT);
378 sigaddset(&action.sa_mask, SIGTERM);
379 sigaddset(&action.sa_mask, SIGHUP);
380 sigaddset(&action.sa_mask, SIGUSR1);
381 sigaction(SIGSEGV, &action, NULL);
382 sigaction(SIGILL, &action, NULL);
383 sigaction(SIGBUS, &action, NULL);
384 action.sa_handler = SIG_IGN;
385 sigaction(SIGPIPE, &action, NULL);
386
387 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
388
389 /* start daemon with thread-pool */
390 charon->start(charon);
391 /* wait for signal */
392 return run();
393 }