]>
Commit | Line | Data |
---|---|---|
1fed10be | 1 | /* |
4d38a698 | 2 | * Copyright (C) 2006-2013 Tobias Brunner |
1fed10be MW |
3 | * Copyright (C) 2005-2013 Martin Willi |
4 | * Copyright (C) 2006 Daniel Roethlisberger | |
5 | * Copyright (C) 2005 Jan Hutter | |
1b671669 | 6 | * HSR Hochschule fuer Technik Rapperswil |
1fed10be MW |
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> | |
1fed10be | 20 | #include <signal.h> |
1fed10be MW |
21 | #include <pthread.h> |
22 | #include <sys/types.h> | |
23 | #include <sys/utsname.h> | |
24 | #include <unistd.h> | |
25 | #include <getopt.h> | |
85814809 | 26 | #include <errno.h> |
1fed10be MW |
27 | |
28 | #include <library.h> | |
1fed10be MW |
29 | #include <daemon.h> |
30 | #include <utils/backtrace.h> | |
31 | #include <threading/thread.h> | |
32 | ||
be44723d | 33 | #include "cmd/cmd_options.h" |
78d7a0f7 | 34 | #include "cmd/cmd_connection.h" |
2baa7bbe | 35 | #include "cmd/cmd_creds.h" |
be44723d | 36 | |
295d595b TB |
37 | /** |
38 | * Default loglevel | |
39 | */ | |
40 | static level_t default_loglevel = LEVEL_CTRL; | |
41 | ||
78d7a0f7 MW |
42 | /** |
43 | * Connection to initiate | |
44 | */ | |
45 | static cmd_connection_t *conn; | |
46 | ||
2baa7bbe MW |
47 | /** |
48 | * Credential backend | |
49 | */ | |
50 | static cmd_creds_t *creds; | |
51 | ||
1fed10be MW |
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 | ||
295d595b | 64 | if (level <= default_loglevel) |
1fed10be MW |
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 | ||
78d7a0f7 MW |
74 | /** |
75 | * Clean up connection definition atexit() | |
76 | */ | |
77 | static void cleanup_conn() | |
78 | { | |
79 | DESTROY_IF(conn); | |
80 | } | |
81 | ||
2baa7bbe MW |
82 | /** |
83 | * Clean up credentials atexit() | |
84 | */ | |
85 | static void cleanup_creds() | |
86 | { | |
87 | DESTROY_IF(creds); | |
88 | } | |
89 | ||
1fed10be MW |
90 | /** |
91 | * Run the daemon and handle unix signals | |
92 | */ | |
78d7a0f7 | 93 | static int run() |
1fed10be MW |
94 | { |
95 | sigset_t set; | |
96 | ||
78d7a0f7 | 97 | /* handle SIGINT, SIGHUP and SIGTERM in this handler */ |
1fed10be MW |
98 | sigemptyset(&set); |
99 | sigaddset(&set, SIGINT); | |
100 | sigaddset(&set, SIGHUP); | |
101 | sigaddset(&set, SIGTERM); | |
78d7a0f7 | 102 | sigaddset(&set, SIGUSR1); |
1fed10be MW |
103 | sigprocmask(SIG_BLOCK, &set, NULL); |
104 | ||
105 | while (TRUE) | |
106 | { | |
107 | int sig; | |
1fed10be | 108 | |
85814809 TB |
109 | sig = sigwaitinfo(&set, NULL); |
110 | if (sig == -1) | |
1fed10be | 111 | { |
88b85e02 TB |
112 | if (errno == EINTR) |
113 | { /* ignore signals we didn't wait for */ | |
114 | continue; | |
115 | } | |
85814809 | 116 | DBG1(DBG_DMN, "waiting for signal failed: %s", strerror(errno)); |
78d7a0f7 | 117 | return 1; |
1fed10be MW |
118 | } |
119 | switch (sig) | |
120 | { | |
121 | case SIGHUP: | |
122 | { | |
123 | DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " | |
124 | "configuration"); | |
68da3bad | 125 | if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) |
1fed10be | 126 | { |
9665686b | 127 | charon->load_loggers(charon); |
1fed10be MW |
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); | |
78d7a0f7 | 140 | return 0; |
1fed10be MW |
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); | |
78d7a0f7 MW |
146 | return 0; |
147 | } | |
148 | case SIGUSR1: | |
0ceb2888 | 149 | { /* an error occurred */ |
78d7a0f7 MW |
150 | charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); |
151 | return 1; | |
1fed10be | 152 | } |
1fed10be MW |
153 | } |
154 | } | |
155 | } | |
156 | ||
157 | /** | |
158 | * lookup UID and GID | |
159 | */ | |
160 | static bool lookup_uid_gid() | |
161 | { | |
162 | #ifdef IPSEC_USER | |
a2eb5817 | 163 | if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) |
1fed10be MW |
164 | { |
165 | return FALSE; | |
166 | } | |
167 | #endif | |
168 | #ifdef IPSEC_GROUP | |
a2eb5817 | 169 | if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) |
1fed10be MW |
170 | { |
171 | return FALSE; | |
172 | } | |
173 | #endif | |
174 | return TRUE; | |
175 | } | |
176 | ||
fe3ae5be | 177 | #ifndef DISABLE_SIGNAL_HANDLER |
1fed10be MW |
178 | /** |
179 | * Handle SIGSEGV/SIGILL signals raised by threads | |
180 | */ | |
181 | static void segv_handler(int signal) | |
182 | { | |
183 | backtrace_t *backtrace; | |
184 | ||
185 | DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); | |
186 | backtrace = backtrace_create(2); | |
187 | backtrace->log(backtrace, stderr, TRUE); | |
188 | backtrace->destroy(backtrace); | |
189 | ||
190 | DBG1(DBG_DMN, "killing ourself, received critical signal"); | |
191 | abort(); | |
192 | } | |
fe3ae5be | 193 | #endif /* DISABLE_SIGNAL_HANDLER */ |
1fed10be | 194 | |
1fed10be MW |
195 | /** |
196 | * Print command line usage and exit | |
197 | */ | |
198 | static void usage(FILE *out, char *msg, char *binary) | |
199 | { | |
5991f095 TB |
200 | static const int padto = 18; |
201 | char cmd[64], *pre, *post; | |
202 | int i, line, pad; | |
1fed10be MW |
203 | |
204 | if (msg) | |
205 | { | |
206 | fprintf(out, "%s\n", msg); | |
207 | } | |
208 | fprintf(out, "Usage: %s\n", binary); | |
be44723d | 209 | for (i = 0; i < CMD_OPT_COUNT; i++) |
1fed10be | 210 | { |
be44723d | 211 | switch (cmd_options[i].has_arg) |
1fed10be MW |
212 | { |
213 | case required_argument: | |
4d38a698 TB |
214 | pre = " <"; |
215 | post = ">"; | |
1fed10be MW |
216 | break; |
217 | case optional_argument: | |
4d38a698 TB |
218 | pre = "[="; |
219 | post = "]"; | |
1fed10be MW |
220 | break; |
221 | case no_argument: | |
222 | default: | |
4d38a698 TB |
223 | pre = " "; |
224 | post = " "; | |
1fed10be MW |
225 | break; |
226 | } | |
5991f095 TB |
227 | snprintf(cmd, sizeof(cmd), " --%s%s%s%s", cmd_options[i].name, |
228 | pre, cmd_options[i].arg, post); | |
229 | pad = padto - strlen(cmd); | |
230 | if (pad >= 1) | |
231 | { | |
232 | fprintf(out, "%s%-*s%s\n", cmd, pad, "", cmd_options[i].desc); | |
233 | } | |
234 | else | |
235 | { /* write description to a separate line */ | |
236 | fprintf(out, "%s\n%-*s%s\n", cmd, padto, "", cmd_options[i].desc); | |
237 | } | |
d6b0c28b MW |
238 | for (line = 0; line < countof(cmd_options[i].lines); line++) |
239 | { | |
240 | if (cmd_options[i].lines[line]) | |
241 | { | |
5991f095 | 242 | fprintf(out, "%-*s%s\n", padto, "", cmd_options[i].lines[line]); |
d6b0c28b MW |
243 | } |
244 | } | |
1fed10be MW |
245 | } |
246 | } | |
247 | ||
248 | /** | |
4049ec42 TB |
249 | * Handle command line options, if simple is TRUE only arguments like --help |
250 | * and --version are handled. | |
1fed10be | 251 | */ |
4049ec42 | 252 | static void handle_arguments(int argc, char *argv[], bool simple) |
1fed10be | 253 | { |
9dfd9275 MW |
254 | struct option long_opts[CMD_OPT_COUNT + 1] = {}; |
255 | int i, opt; | |
256 | ||
257 | for (i = 0; i < CMD_OPT_COUNT; i++) | |
258 | { | |
259 | long_opts[i].name = cmd_options[i].name; | |
260 | long_opts[i].val = cmd_options[i].id; | |
261 | long_opts[i].has_arg = cmd_options[i].has_arg; | |
262 | } | |
4049ec42 TB |
263 | /* reset option parser */ |
264 | optind = 1; | |
1fed10be MW |
265 | while (TRUE) |
266 | { | |
7bcd96e4 MW |
267 | bool handled = FALSE; |
268 | ||
78d7a0f7 MW |
269 | opt = getopt_long(argc, argv, "", long_opts, NULL); |
270 | switch (opt) | |
1fed10be MW |
271 | { |
272 | case EOF: | |
273 | break; | |
be44723d | 274 | case CMD_OPT_HELP: |
1fed10be MW |
275 | usage(stdout, NULL, argv[0]); |
276 | exit(0); | |
be44723d | 277 | case CMD_OPT_VERSION: |
1fed10be MW |
278 | printf("%s, strongSwan %s\n", "charon-cmd", VERSION); |
279 | exit(0); | |
295d595b TB |
280 | case CMD_OPT_DEBUG: |
281 | default_loglevel = atoi(optarg); | |
282 | continue; | |
1fed10be | 283 | default: |
4049ec42 TB |
284 | if (simple) |
285 | { | |
286 | continue; | |
287 | } | |
7bcd96e4 MW |
288 | handled |= conn->handle(conn, opt, optarg); |
289 | handled |= creds->handle(creds, opt, optarg); | |
290 | if (handled) | |
78d7a0f7 MW |
291 | { |
292 | continue; | |
293 | } | |
efb4cb0b TB |
294 | /* fall-through */ |
295 | case '?': | |
296 | /* missing argument, unrecognized option */ | |
1fed10be MW |
297 | usage(stderr, NULL, argv[0]); |
298 | exit(1); | |
299 | } | |
300 | break; | |
301 | } | |
302 | } | |
303 | ||
304 | /** | |
305 | * Main function, starts the daemon. | |
306 | */ | |
307 | int main(int argc, char *argv[]) | |
308 | { | |
309 | struct sigaction action; | |
310 | struct utsname utsname; | |
9665686b | 311 | level_t levels[DBG_MAX]; |
1fed10be MW |
312 | int group; |
313 | ||
4049ec42 TB |
314 | /* handle simple arguments */ |
315 | handle_arguments(argc, argv, TRUE); | |
316 | ||
1fed10be MW |
317 | dbg = dbg_stderr; |
318 | atexit(library_deinit); | |
34d3bfcf | 319 | if (!library_init(NULL, "charon-cmd")) |
1fed10be MW |
320 | { |
321 | exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); | |
322 | } | |
323 | if (lib->integrity) | |
324 | { | |
325 | if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0])) | |
326 | { | |
327 | exit(SS_RC_DAEMON_INTEGRITY); | |
328 | } | |
329 | } | |
1fed10be | 330 | atexit(libcharon_deinit); |
1c306c0e | 331 | if (!libcharon_init()) |
1fed10be MW |
332 | { |
333 | exit(SS_RC_INITIALIZATION_FAILED); | |
334 | } | |
335 | for (group = 0; group < DBG_MAX; group++) | |
336 | { | |
295d595b | 337 | levels[group] = default_loglevel; |
1fed10be | 338 | } |
9665686b TB |
339 | charon->set_default_loggers(charon, levels, TRUE); |
340 | charon->load_loggers(charon); | |
1fed10be MW |
341 | |
342 | if (!lookup_uid_gid()) | |
343 | { | |
344 | exit(SS_RC_INITIALIZATION_FAILED); | |
345 | } | |
7a86bccd MW |
346 | lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); |
347 | lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); | |
1fed10be MW |
348 | if (!charon->initialize(charon, |
349 | lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS))) | |
350 | { | |
351 | exit(SS_RC_INITIALIZATION_FAILED); | |
352 | } | |
157150ca TB |
353 | /* register this again after loading plugins to avoid issues with libraries |
354 | * that register atexit() handlers */ | |
355 | atexit(libcharon_deinit); | |
a2eb5817 | 356 | if (!lib->caps->drop(lib->caps)) |
1fed10be MW |
357 | { |
358 | exit(SS_RC_INITIALIZATION_FAILED); | |
359 | } | |
360 | ||
2baa7bbe MW |
361 | conn = cmd_connection_create(); |
362 | atexit(cleanup_conn); | |
363 | creds = cmd_creds_create(); | |
364 | atexit(cleanup_creds); | |
365 | ||
2baa7bbe MW |
366 | if (uname(&utsname) != 0) |
367 | { | |
368 | memset(&utsname, 0, sizeof(utsname)); | |
369 | } | |
370 | DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)", | |
371 | VERSION, utsname.sysname, utsname.release, utsname.machine); | |
607f8e99 | 372 | lib->plugins->status(lib->plugins, LEVEL_CTRL); |
2baa7bbe | 373 | |
b982473a TB |
374 | /* handle all arguments */ |
375 | handle_arguments(argc, argv, FALSE); | |
376 | ||
fe3ae5be SM |
377 | /* add handler for fatal signals, |
378 | * INT, TERM, HUP and USR1 are handled by sigwaitinfo() in run() */ | |
1fed10be MW |
379 | action.sa_flags = 0; |
380 | sigemptyset(&action.sa_mask); | |
381 | sigaddset(&action.sa_mask, SIGINT); | |
382 | sigaddset(&action.sa_mask, SIGTERM); | |
383 | sigaddset(&action.sa_mask, SIGHUP); | |
1df14301 | 384 | sigaddset(&action.sa_mask, SIGUSR1); |
fe3ae5be SM |
385 | |
386 | /* optionally let the external system handle fatal signals */ | |
387 | #ifndef DISABLE_SIGNAL_HANDLER | |
388 | action.sa_handler = segv_handler; | |
1fed10be MW |
389 | sigaction(SIGSEGV, &action, NULL); |
390 | sigaction(SIGILL, &action, NULL); | |
391 | sigaction(SIGBUS, &action, NULL); | |
fe3ae5be SM |
392 | #endif /* DISABLE_SIGNAL_HANDLER */ |
393 | ||
1fed10be MW |
394 | action.sa_handler = SIG_IGN; |
395 | sigaction(SIGPIPE, &action, NULL); | |
396 | ||
397 | pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); | |
398 | ||
399 | /* start daemon with thread-pool */ | |
400 | charon->start(charon); | |
401 | /* wait for signal */ | |
78d7a0f7 | 402 | return run(); |
1fed10be | 403 | } |