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
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>.
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
22 #include <sys/types.h>
23 #include <sys/utsname.h>
31 #include <utils/backtrace.h>
32 #include <threading/thread.h>
34 #include "cmd/cmd_options.h"
35 #include "cmd/cmd_connection.h"
36 #include "cmd/cmd_creds.h"
41 static level_t default_loglevel
= LEVEL_CTRL
;
44 * Loglevel configuration
46 static level_t levels
[DBG_MAX
];
49 * Connection to initiate
51 static cmd_connection_t
*conn
;
56 static cmd_creds_t
*creds
;
59 * hook in library for debugging messages
61 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
64 * Logging hook for library logs, using stderr output
66 static void dbg_stderr(debug_t group
, level_t level
, char *fmt
, ...)
70 if (level
<= default_loglevel
)
73 fprintf(stderr
, "00[%N] ", debug_names
, group
);
74 vfprintf(stderr
, fmt
, args
);
75 fprintf(stderr
, "\n");
81 * Clean up connection definition atexit()
83 static void cleanup_conn()
89 * Clean up credentials atexit()
91 static void cleanup_creds()
97 * Run the daemon and handle unix signals
103 /* handle SIGINT, SIGHUP and SIGTERM in this handler */
105 sigaddset(&set
, SIGINT
);
106 sigaddset(&set
, SIGHUP
);
107 sigaddset(&set
, SIGTERM
);
108 sigaddset(&set
, SIGUSR1
);
109 sigprocmask(SIG_BLOCK
, &set
, NULL
);
115 sig
= sigwaitinfo(&set
, NULL
);
119 { /* ignore signals we didn't wait for */
122 DBG1(DBG_DMN
, "waiting for signal failed: %s", strerror(errno
));
129 DBG1(DBG_DMN
, "signal of type SIGHUP received. Reloading "
131 if (lib
->settings
->load_files(lib
->settings
, lib
->conf
, FALSE
))
133 charon
->load_loggers(charon
, levels
, TRUE
);
134 lib
->plugins
->reload(lib
->plugins
, NULL
);
138 DBG1(DBG_DMN
, "reloading config failed, keeping old");
144 DBG1(DBG_DMN
, "signal of type SIGINT received. Shutting down");
145 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
150 DBG1(DBG_DMN
, "signal of type SIGTERM received. Shutting down");
151 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
155 { /* an error occurred */
156 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
166 static bool lookup_uid_gid()
169 if (!lib
->caps
->resolve_uid(lib
->caps
, IPSEC_USER
))
175 if (!lib
->caps
->resolve_gid(lib
->caps
, IPSEC_GROUP
))
184 * Handle SIGSEGV/SIGILL signals raised by threads
186 static void segv_handler(int signal
)
188 backtrace_t
*backtrace
;
190 DBG1(DBG_DMN
, "thread %u received %d", thread_current_id(), signal
);
191 backtrace
= backtrace_create(2);
192 backtrace
->log(backtrace
, stderr
, TRUE
);
193 backtrace
->destroy(backtrace
);
195 DBG1(DBG_DMN
, "killing ourself, received critical signal");
200 * Print command line usage and exit
202 static void usage(FILE *out
, char *msg
, char *binary
)
204 static const int padto
= 18;
205 char cmd
[64], *pre
, *post
;
210 fprintf(out
, "%s\n", msg
);
212 fprintf(out
, "Usage: %s\n", binary
);
213 for (i
= 0; i
< CMD_OPT_COUNT
; i
++)
215 switch (cmd_options
[i
].has_arg
)
217 case required_argument
:
221 case optional_argument
:
231 snprintf(cmd
, sizeof(cmd
), " --%s%s%s%s", cmd_options
[i
].name
,
232 pre
, cmd_options
[i
].arg
, post
);
233 pad
= padto
- strlen(cmd
);
236 fprintf(out
, "%s%-*s%s\n", cmd
, pad
, "", cmd_options
[i
].desc
);
239 { /* write description to a separate line */
240 fprintf(out
, "%s\n%-*s%s\n", cmd
, padto
, "", cmd_options
[i
].desc
);
242 for (line
= 0; line
< countof(cmd_options
[i
].lines
); line
++)
244 if (cmd_options
[i
].lines
[line
])
246 fprintf(out
, "%-*s%s\n", padto
, "", cmd_options
[i
].lines
[line
]);
253 * Handle command line options, if simple is TRUE only arguments like --help
254 * and --version are handled.
256 static void handle_arguments(int argc
, char *argv
[], bool simple
)
258 struct option long_opts
[CMD_OPT_COUNT
+ 1] = {};
261 for (i
= 0; i
< CMD_OPT_COUNT
; i
++)
263 long_opts
[i
].name
= cmd_options
[i
].name
;
264 long_opts
[i
].val
= cmd_options
[i
].id
;
265 long_opts
[i
].has_arg
= cmd_options
[i
].has_arg
;
267 /* reset option parser */
271 bool handled
= FALSE
;
273 opt
= getopt_long(argc
, argv
, "", long_opts
, NULL
);
279 usage(stdout
, NULL
, argv
[0]);
281 case CMD_OPT_VERSION
:
282 printf("%s, strongSwan %s\n", "charon-cmd", VERSION
);
285 default_loglevel
= atoi(optarg
);
292 handled
|= conn
->handle(conn
, opt
, optarg
);
293 handled
|= creds
->handle(creds
, opt
, optarg
);
300 /* missing argument, unrecognized option */
301 usage(stderr
, NULL
, argv
[0]);
309 * Main function, starts the daemon.
311 int main(int argc
, char *argv
[])
313 struct sigaction action
;
314 struct utsname utsname
;
317 /* handle simple arguments */
318 handle_arguments(argc
, argv
, TRUE
);
321 atexit(library_deinit
);
322 if (!library_init(NULL
, "charon-cmd"))
324 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
328 if (!lib
->integrity
->check_file(lib
->integrity
, "charon-cmd", argv
[0]))
330 exit(SS_RC_DAEMON_INTEGRITY
);
333 atexit(libhydra_deinit
);
334 if (!libhydra_init())
336 exit(SS_RC_INITIALIZATION_FAILED
);
338 atexit(libcharon_deinit
);
339 if (!libcharon_init())
341 exit(SS_RC_INITIALIZATION_FAILED
);
343 for (group
= 0; group
< DBG_MAX
; group
++)
345 levels
[group
] = default_loglevel
;
347 charon
->load_loggers(charon
, levels
, TRUE
);
349 if (!lookup_uid_gid())
351 exit(SS_RC_INITIALIZATION_FAILED
);
353 lib
->settings
->set_default_str(lib
->settings
, "charon-cmd.port", "0");
354 lib
->settings
->set_default_str(lib
->settings
, "charon-cmd.port_nat_t", "0");
355 if (!charon
->initialize(charon
,
356 lib
->settings
->get_str(lib
->settings
, "charon-cmd.load", PLUGINS
)))
358 exit(SS_RC_INITIALIZATION_FAILED
);
360 if (!lib
->caps
->drop(lib
->caps
))
362 exit(SS_RC_INITIALIZATION_FAILED
);
365 conn
= cmd_connection_create();
366 atexit(cleanup_conn
);
367 creds
= cmd_creds_create();
368 atexit(cleanup_creds
);
370 /* handle all arguments */
371 handle_arguments(argc
, argv
, FALSE
);
373 if (uname(&utsname
) != 0)
375 memset(&utsname
, 0, sizeof(utsname
));
377 DBG1(DBG_DMN
, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
378 VERSION
, utsname
.sysname
, utsname
.release
, utsname
.machine
);
379 lib
->plugins
->status(lib
->plugins
, LEVEL_CTRL
);
381 /* add handler for SEGV and ILL,
382 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
383 action
.sa_handler
= segv_handler
;
385 sigemptyset(&action
.sa_mask
);
386 sigaddset(&action
.sa_mask
, SIGINT
);
387 sigaddset(&action
.sa_mask
, SIGTERM
);
388 sigaddset(&action
.sa_mask
, SIGHUP
);
389 sigaddset(&action
.sa_mask
, SIGUSR1
);
390 sigaction(SIGSEGV
, &action
, NULL
);
391 sigaction(SIGILL
, &action
, NULL
);
392 sigaction(SIGBUS
, &action
, NULL
);
393 action
.sa_handler
= SIG_IGN
;
394 sigaction(SIGPIPE
, &action
, NULL
);
396 pthread_sigmask(SIG_SETMASK
, &action
.sa_mask
, NULL
);
398 /* start daemon with thread-pool */
399 charon
->start(charon
);
400 /* wait for signal */