charon-cmd: add a connection object and its initiation to charon-cmd
[strongswan.git] / src / charon-cmd / charon-cmd.c
1 /*
2 * Copyright (C) 2006-2012 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 #define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */
21 #include <signal.h>
22 #undef _POSIX_PTHREAD_SEMANTICS
23 #include <pthread.h>
24 #include <sys/types.h>
25 #include <sys/utsname.h>
26 #include <unistd.h>
27 #include <getopt.h>
28
29 #include <library.h>
30 #include <hydra.h>
31 #include <daemon.h>
32 #include <utils/backtrace.h>
33 #include <threading/thread.h>
34
35 #include "cmd/cmd_options.h"
36 #include "cmd/cmd_connection.h"
37
38 /**
39 * Loglevel configuration
40 */
41 static level_t levels[DBG_MAX];
42
43 /**
44 * Connection to initiate
45 */
46 static cmd_connection_t *conn;
47
48 /**
49 * hook in library for debugging messages
50 */
51 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
52
53 /**
54 * Logging hook for library logs, using stderr output
55 */
56 static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
57 {
58 va_list args;
59
60 if (level <= 1)
61 {
62 va_start(args, fmt);
63 fprintf(stderr, "00[%N] ", debug_names, group);
64 vfprintf(stderr, fmt, args);
65 fprintf(stderr, "\n");
66 va_end(args);
67 }
68 }
69
70 /**
71 * Clean up connection definition atexit()
72 */
73 static void cleanup_conn()
74 {
75 DESTROY_IF(conn);
76 }
77
78 /**
79 * Run the daemon and handle unix signals
80 */
81 static int run()
82 {
83 sigset_t set;
84
85 /* handle SIGINT, SIGHUP and SIGTERM in this handler */
86 sigemptyset(&set);
87 sigaddset(&set, SIGINT);
88 sigaddset(&set, SIGHUP);
89 sigaddset(&set, SIGTERM);
90 sigaddset(&set, SIGUSR1);
91 sigprocmask(SIG_BLOCK, &set, NULL);
92
93 while (TRUE)
94 {
95 int sig;
96 int error;
97
98 error = sigwait(&set, &sig);
99 if (error)
100 {
101 DBG1(DBG_DMN, "error %d while waiting for a signal", error);
102 return 1;
103 }
104 switch (sig)
105 {
106 case SIGHUP:
107 {
108 DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading "
109 "configuration");
110 if (lib->settings->load_files(lib->settings, NULL, FALSE))
111 {
112 charon->load_loggers(charon, levels, TRUE);
113 lib->plugins->reload(lib->plugins, NULL);
114 }
115 else
116 {
117 DBG1(DBG_DMN, "reloading config failed, keeping old");
118 }
119 break;
120 }
121 case SIGINT:
122 {
123 DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
124 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
125 return 0;
126 }
127 case SIGTERM:
128 {
129 DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
130 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
131 return 0;
132 }
133 case SIGUSR1:
134 { /* an error occured */
135 charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
136 return 1;
137 }
138 default:
139 {
140 DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
141 break;
142 }
143 }
144 }
145 }
146
147 /**
148 * lookup UID and GID
149 */
150 static bool lookup_uid_gid()
151 {
152 #ifdef IPSEC_USER
153 if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER))
154 {
155 return FALSE;
156 }
157 #endif
158 #ifdef IPSEC_GROUP
159 if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP))
160 {
161 return FALSE;
162 }
163 #endif
164 return TRUE;
165 }
166
167 /**
168 * Handle SIGSEGV/SIGILL signals raised by threads
169 */
170 static void segv_handler(int signal)
171 {
172 backtrace_t *backtrace;
173
174 DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
175 backtrace = backtrace_create(2);
176 backtrace->log(backtrace, stderr, TRUE);
177 backtrace->destroy(backtrace);
178
179 DBG1(DBG_DMN, "killing ourself, received critical signal");
180 abort();
181 }
182
183 /**
184 * Print command line usage and exit
185 */
186 static void usage(FILE *out, char *msg, char *binary)
187 {
188 int i, pre, post, padto = 0, spacing = 2;
189
190 for (i = 0; i < CMD_OPT_COUNT; i++)
191 {
192 padto = max(padto, strlen(cmd_options[i].name) +
193 strlen(cmd_options[i].arg));
194 }
195 padto += spacing;
196
197 if (msg)
198 {
199 fprintf(out, "%s\n", msg);
200 }
201 fprintf(out, "Usage: %s\n", binary);
202 for (i = 0; i < CMD_OPT_COUNT; i++)
203 {
204 switch (cmd_options[i].has_arg)
205 {
206 case required_argument:
207 pre = '<';
208 post = '>';
209 break;
210 case optional_argument:
211 pre = '[';
212 post = ']';
213 break;
214 case no_argument:
215 default:
216 pre = post = ' ';
217 break;
218 }
219 fprintf(out, " --%s %c%s%c %-*s%s\n",
220 cmd_options[i].name,
221 pre, cmd_options[i].arg, post,
222 padto - strlen(cmd_options[i].name) - strlen(cmd_options[i].arg), "",
223 cmd_options[i].desc);
224 }
225 }
226
227 /**
228 * Handle command line options
229 */
230 static void handle_arguments(int argc, char *argv[])
231 {
232 while (TRUE)
233 {
234 struct option long_opts[CMD_OPT_COUNT + 1] = {};
235 int i, opt;
236
237 for (i = 0; i < CMD_OPT_COUNT; i++)
238 {
239 long_opts[i].name = cmd_options[i].name;
240 long_opts[i].val = cmd_options[i].id;
241 long_opts[i].has_arg = cmd_options[i].has_arg;
242 }
243
244 opt = getopt_long(argc, argv, "", long_opts, NULL);
245 switch (opt)
246 {
247 case EOF:
248 break;
249 case CMD_OPT_HELP:
250 usage(stdout, NULL, argv[0]);
251 exit(0);
252 case CMD_OPT_VERSION:
253 printf("%s, strongSwan %s\n", "charon-cmd", VERSION);
254 exit(0);
255 default:
256 if (conn->handle(conn, opt, optarg))
257 {
258 continue;
259 }
260 usage(stderr, NULL, argv[0]);
261 exit(1);
262 }
263 break;
264 }
265 }
266
267 /**
268 * Main function, starts the daemon.
269 */
270 int main(int argc, char *argv[])
271 {
272 struct sigaction action;
273 struct utsname utsname;
274 int group;
275
276 dbg = dbg_stderr;
277 atexit(library_deinit);
278 if (!library_init(NULL))
279 {
280 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
281 }
282 if (lib->integrity)
283 {
284 if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0]))
285 {
286 exit(SS_RC_DAEMON_INTEGRITY);
287 }
288 }
289 atexit(libhydra_deinit);
290 if (!libhydra_init("charon-cmd"))
291 {
292 exit(SS_RC_INITIALIZATION_FAILED);
293 }
294 atexit(libcharon_deinit);
295 if (!libcharon_init("charon-cmd"))
296 {
297 exit(SS_RC_INITIALIZATION_FAILED);
298 }
299 for (group = 0; group < DBG_MAX; group++)
300 {
301 levels[group] = LEVEL_CTRL;
302 }
303 conn = cmd_connection_create();
304 atexit(cleanup_conn);
305
306 handle_arguments(argc, argv);
307
308 if (!lookup_uid_gid())
309 {
310 exit(SS_RC_INITIALIZATION_FAILED);
311 }
312 charon->load_loggers(charon, levels, TRUE);
313
314 if (uname(&utsname) != 0)
315 {
316 memset(&utsname, 0, sizeof(utsname));
317 }
318 DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
319 VERSION, utsname.sysname, utsname.release, utsname.machine);
320
321 if (!charon->initialize(charon,
322 lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS)))
323 {
324 exit(SS_RC_INITIALIZATION_FAILED);
325 }
326 if (!charon->caps->drop(charon->caps))
327 {
328 exit(SS_RC_INITIALIZATION_FAILED);
329 }
330
331 /* add handler for SEGV and ILL,
332 * INT, TERM and HUP are handled by sigwait() in run() */
333 action.sa_handler = segv_handler;
334 action.sa_flags = 0;
335 sigemptyset(&action.sa_mask);
336 sigaddset(&action.sa_mask, SIGINT);
337 sigaddset(&action.sa_mask, SIGTERM);
338 sigaddset(&action.sa_mask, SIGHUP);
339 sigaction(SIGSEGV, &action, NULL);
340 sigaction(SIGILL, &action, NULL);
341 sigaction(SIGBUS, &action, NULL);
342 action.sa_handler = SIG_IGN;
343 sigaction(SIGPIPE, &action, NULL);
344
345 pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
346
347 /* start daemon with thread-pool */
348 charon->start(charon);
349 /* wait for signal */
350 return run();
351 }