Branch data Line data Source code
1 : : /**
2 : : * \file server/fwknopd.c
3 : : *
4 : : * \brief An implementation of an fwknop server.
5 : : *
6 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
7 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
8 : : * list of contributors, see the file 'CREDITS'.
9 : : *
10 : : * License (GNU General Public License):
11 : : *
12 : : * This program is free software; you can redistribute it and/or
13 : : * modify it under the terms of the GNU General Public License
14 : : * as published by the Free Software Foundation; either version 2
15 : : * of the License, or (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program; if not, write to the Free Software
24 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 : : * USA
26 : : *
27 : : *****************************************************************************
28 : : */
29 : : #include "fwknopd.h"
30 : : #include "access.h"
31 : : #include "config_init.h"
32 : : #include "log_msg.h"
33 : : #include "utils.h"
34 : : #include "fw_util.h"
35 : : #include "sig_handler.h"
36 : : #include "replay_cache.h"
37 : : #include "tcp_server.h"
38 : : #include "udp_server.h"
39 : :
40 : : #if USE_LIBNETFILTER_QUEUE
41 : : #include "nfq_capture.h"
42 : : #endif
43 : : #if USE_LIBPCAP
44 : : #include "pcap_capture.h"
45 : : #endif
46 : :
47 : : /* Prototypes
48 : : */
49 : : static int check_dir_path(const char * const path,
50 : : const char * const path_name, const unsigned char use_basename);
51 : : static int make_dir_path(const char * const path);
52 : : static void daemonize_process(fko_srv_options_t * const opts);
53 : : static int stop_fwknopd(fko_srv_options_t * const opts);
54 : : static int status_fwknopd(fko_srv_options_t * const opts);
55 : : static int restart_fwknopd(fko_srv_options_t * const opts);
56 : : static int write_pid_file(fko_srv_options_t *opts);
57 : : static int handle_signals(fko_srv_options_t *opts);
58 : : static void setup_pid(fko_srv_options_t *opts);
59 : : static void init_digest_cache(fko_srv_options_t *opts);
60 : : static void set_locale(fko_srv_options_t *opts);
61 : : static pid_t get_running_pid(const fko_srv_options_t *opts);
62 : : #if AFL_FUZZING
63 : : static void afl_enc_pkt_from_file(fko_srv_options_t *opts);
64 : : static void afl_pkt_from_stdin(fko_srv_options_t *opts);
65 : : #endif
66 : :
67 : : #if HAVE_LIBFIU
68 : : static void enable_fault_injections(fko_srv_options_t * const opts);
69 : : #endif
70 : :
71 : : #if AFL_FUZZING
72 : : #define AFL_MAX_PKT_SIZE 1024
73 : : #define AFL_DUMP_CTX_SIZE 4096
74 : : #endif
75 : :
76 : : int
77 : 7115 : main(int argc, char **argv)
78 : : {
79 : : fko_srv_options_t opts;
80 : 7115 : int depth = 0;
81 : :
82 : : while(1)
83 : : {
84 : : /* Handle command line
85 : : */
86 : 7117 : config_init(&opts, argc, argv);
87 : :
88 : : #if HAVE_LIBFIU
89 : : /* Set any fault injection points early
90 : : */
91 : 6027 : enable_fault_injections(&opts);
92 : : #endif
93 : :
94 : : /* Process any options that do their thing and exit.
95 : : */
96 : :
97 : : /* Kill the currently running fwknopd process?
98 : : */
99 [ + + ]: 6027 : if(opts.kill == 1)
100 : 454 : clean_exit(&opts, NO_FW_CLEANUP, stop_fwknopd(&opts));
101 : :
102 : : /* Status of the currently running fwknopd process?
103 : : */
104 [ + + ]: 5573 : if(opts.status == 1)
105 : 892 : clean_exit(&opts, NO_FW_CLEANUP, status_fwknopd(&opts));
106 : :
107 : : /* Restart the currently running fwknopd process?
108 : : */
109 [ + + ]: 4681 : if(opts.restart == 1)
110 : 1 : clean_exit(&opts, NO_FW_CLEANUP, restart_fwknopd(&opts));
111 : :
112 : : /* Initialize logging.
113 : : */
114 : 4680 : init_logging(&opts);
115 : :
116 : : /* Update the verbosity level for the log module */
117 : 4675 : log_set_verbosity(LOG_DEFAULT_VERBOSITY + opts.verbose);
118 : :
119 : : #if HAVE_LOCALE_H
120 : : /* Set the locale if specified.
121 : : */
122 : 4675 : set_locale(&opts);
123 : : #endif
124 : :
125 : : /* Make sure we have a valid run dir and path leading to digest file
126 : : * in case it configured to be somewhere other than the run dir.
127 : : */
128 [ + - ]: 4675 : if(!opts.afl_fuzzing
129 [ + + ]: 4675 : && ! check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0))
130 : 2 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
131 : : /* Initialize our signal handlers. You can check the return value for
132 : : * the number of signals that were *not* set. Those that were not set
133 : : * will be listed in the log/stderr output.
134 : : */
135 [ + + ]: 4673 : if(set_sig_handlers() > 0) {
136 : 1 : log_msg(LOG_ERR, "Errors encountered when setting signal handlers.");
137 : 1 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
138 : : }
139 : :
140 : : /* Initialize the firewall rules handler based on the fwknopd.conf
141 : : * file, but (for iptables firewalls) don't flush any rules or create
142 : : * any chains yet. This allows us to dump the current firewall rules
143 : : * via fw_rules_dump() in --fw-list mode before changing around any rules
144 : : * of an existing fwknopd process.
145 : : */
146 [ + + ]: 4672 : if(fw_config_init(&opts) != 1)
147 : 3 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
148 : :
149 [ + + ][ - + ]: 4669 : if(opts.fw_list == 1 || opts.fw_list_all == 1)
150 : : {
151 : 2981 : fw_dump_rules(&opts);
152 : 2981 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
153 : : }
154 : :
155 [ + + ]: 1688 : if(opts.fw_flush == 1)
156 : : {
157 : 19 : fprintf(stdout, "Deleting any existing firewall rules...\n");
158 : 19 : opts.enable_fw = 1;
159 : 19 : clean_exit(&opts, FW_CLEANUP, EXIT_SUCCESS);
160 : : }
161 : :
162 [ + + ]: 1669 : if (opts.config[CONF_ACCESS_FOLDER] != NULL) //If we have an access folder, process it
163 : : {
164 [ - + ]: 2 : if (parse_access_folder(&opts, opts.config[CONF_ACCESS_FOLDER], &depth) != EXIT_SUCCESS)
165 : : {
166 : 0 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
167 : : }
168 : : }
169 : : /* Process the access.conf file, but only if no access.conf folder was specified.
170 : : */
171 [ + + ]: 1667 : else if (parse_access_file(&opts, opts.config[CONF_ACCESS_FILE], &depth) != EXIT_SUCCESS)
172 : : {
173 : 43 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
174 : : }
175 : :
176 : : /* We must have at least one valid access stanza at this point
177 : : */
178 [ + + ]: 1585 : if(! valid_access_stanzas(opts.acc_stanzas))
179 : : {
180 : 1 : log_msg(LOG_ERR, "Fatal, could not find any valid access.conf stanzas");
181 : 1 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
182 : : }
183 : :
184 : : /* Show config (including access.conf vars) and exit dump config was
185 : : * wanted.
186 : : */
187 [ + + ]: 1584 : if(opts.dump_config == 1)
188 : : {
189 : 28 : dump_config(&opts);
190 : 28 : dump_access_list(&opts);
191 : 28 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
192 : : }
193 : :
194 : : /* Now is the right time to bail if we're just parsing the configs
195 : : */
196 [ + + ]: 1556 : if(opts.exit_after_parse_config)
197 : : {
198 : 1048 : log_msg(LOG_INFO, "Configs parsed, exiting.");
199 : 1048 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
200 : : }
201 : :
202 : : /* Acquire pid, become a daemon or run in the foreground, write pid
203 : : * to pid file.
204 : : */
205 [ + + ]: 508 : if(! opts.exit_parse_digest_cache)
206 : 506 : setup_pid(&opts);
207 : :
208 [ + + ][ + + ]: 508 : if(opts.verbose > 1 && opts.foreground)
209 : : {
210 : 495 : dump_config(&opts);
211 : 495 : dump_access_list(&opts);
212 : : }
213 : :
214 : : /* Initialize the digest cache for replay attack detection (either
215 : : * with dbm support or with the default simple cache file strategy)
216 : : * if so configured.
217 : : */
218 : 508 : init_digest_cache(&opts);
219 : :
220 [ + + ]: 508 : if(opts.exit_parse_digest_cache)
221 : : {
222 : 2 : log_msg(LOG_INFO, "Digest cache parsed, exiting.");
223 : 2 : clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
224 : : }
225 : :
226 : : #if AFL_FUZZING
227 : : /* SPA data from STDIN. */
228 : : if(opts.afl_fuzzing)
229 : : {
230 : : if(opts.config[CONF_AFL_PKT_FILE] != 0x0)
231 : : {
232 : : afl_enc_pkt_from_file(&opts);
233 : : }
234 : : else
235 : : {
236 : : afl_pkt_from_stdin(&opts);
237 : : }
238 : : }
239 : : #endif
240 : :
241 : : /* Prepare the firewall - i.e. flush any old rules and (for iptables)
242 : : * create fwknop chains.
243 : : */
244 [ + + ][ + + ]: 506 : if(!opts.test && opts.enable_fw && (fw_initialize(&opts) != 1))
[ + + ]
245 : 3 : clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
246 : :
247 : : #if USE_LIBNETFILTER_QUEUE
248 : : /* If we are to acquire SPA data via a libnetfilter_queue, start it up here.
249 : : */
250 : : if(opts.enable_nfq_capture ||
251 : : strncasecmp(opts.config[CONF_ENABLE_NFQ_CAPTURE], "Y", 1) == 0)
252 : : {
253 : : nfq_capture(&opts);
254 : : }
255 : : else
256 : : #endif
257 : : /* If we are to acquire SPA data via a UDP socket, start it up here.
258 : : */
259 [ + + ][ + + ]: 503 : if(opts.enable_udp_server ||
260 : 492 : strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0)
261 : : {
262 [ - + ]: 13 : if(run_udp_server(&opts) < 0)
263 : : {
264 : 0 : log_msg(LOG_ERR, "Fatal run_udp_server() error");
265 : 0 : clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
266 : : }
267 : : else
268 : : {
269 : : break;
270 : : }
271 : : }
272 : :
273 : : /* If the TCP server option was set, fire it up here. Note that in
274 : : * this mode, fwknopd still acquires SPA packets via libpcap. If you
275 : : * want to use UDP only without the libpcap dependency, then fwknop
276 : : * needs to be compiled with --enable-udp-server. Note that the UDP
277 : : * server can be run even when fwknopd links against libpcap as well,
278 : : * but there is no reason to link against it if SPA packets are
279 : : * always going to be acquired via a UDP socket.
280 : : */
281 [ + + ]: 490 : if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0)
282 : : {
283 [ - + ]: 2 : if(run_tcp_server(&opts) < 0)
284 : : {
285 : 0 : log_msg(LOG_ERR, "Fatal run_tcp_server() error");
286 : 0 : clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
287 : : }
288 : : }
289 : :
290 : : #if USE_LIBPCAP
291 : : /* Intiate pcap capture mode...
292 : : */
293 [ + - ]: 490 : if(!opts.enable_udp_server
294 [ + - ]: 490 : && strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "N", 1) == 0)
295 : : {
296 : 490 : pcap_capture(&opts);
297 : : }
298 : : else
299 : : {
300 : 0 : log_msg(LOG_ERR, "No available capture mode specified. Aborting.");
301 : 0 : clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
302 : : }
303 : : #endif
304 : :
305 : : /* Deal with any signals that we've received and break out
306 : : * of the loop for any terminating signals
307 : : */
308 [ + + ]: 464 : if(handle_signals(&opts) == 1)
309 : : break;
310 : : }
311 : :
312 : 475 : log_msg(LOG_INFO, "Shutting Down fwknopd.");
313 : :
314 : : /* Kill the TCP server (if we have one running).
315 : : */
316 [ - + ]: 475 : if(opts.tcp_server_pid > 0)
317 : : {
318 : 0 : log_msg(LOG_INFO, "Killing the TCP server (pid=%i)",
319 : : opts.tcp_server_pid);
320 : :
321 : 0 : kill(opts.tcp_server_pid, SIGTERM);
322 : :
323 : : /* --DSS XXX: This seems to be necessary if the tcp server
324 : : * was restarted by this program. We need to
325 : : * investigate and fix this. For now, this works
326 : : * (it is kludgy, but does no harm afaik).
327 : : */
328 : 0 : kill(opts.tcp_server_pid, SIGKILL);
329 : : }
330 : :
331 : 475 : clean_exit(&opts, FW_CLEANUP, EXIT_SUCCESS);
332 : :
333 : 0 : return(EXIT_SUCCESS); /* This never gets called */
334 : : }
335 : :
336 : 4675 : static void set_locale(fko_srv_options_t *opts)
337 : : {
338 : : char *locale;
339 : :
340 [ + + ]: 4675 : if(opts->config[CONF_LOCALE] != NULL
341 [ + - ]: 2 : && strncasecmp(opts->config[CONF_LOCALE], "NONE", 4) != 0)
342 : : {
343 : 2 : locale = setlocale(LC_ALL, opts->config[CONF_LOCALE]);
344 : :
345 [ + + ]: 2 : if(locale == NULL)
346 : : {
347 : 1 : log_msg(LOG_ERR,
348 : : "WARNING: Unable to set locale to '%s'.",
349 : : opts->config[CONF_LOCALE]
350 : : );
351 : : }
352 : : else
353 : : {
354 : 1 : log_msg(LOG_INFO,
355 : : "Locale set to '%s'.", opts->config[CONF_LOCALE]
356 : : );
357 : : }
358 : : }
359 : 4675 : return;
360 : : }
361 : :
362 : : #if AFL_FUZZING
363 : : static void afl_enc_pkt_from_file(fko_srv_options_t *opts)
364 : : {
365 : : FILE *fp = NULL;
366 : : fko_ctx_t decrypt_ctx = NULL;
367 : : unsigned char enc_spa_pkt[AFL_MAX_PKT_SIZE] = {0}, rc;
368 : : int res = 0, es = EXIT_SUCCESS, enc_msg_len;
369 : : char dump_buf[AFL_DUMP_CTX_SIZE];
370 : :
371 : : fp = fopen(opts->config[CONF_AFL_PKT_FILE], "rb");
372 : : if(fp != NULL)
373 : : {
374 : : enc_msg_len = 0;
375 : : while(fread(&rc, 1, 1, fp))
376 : : {
377 : : enc_spa_pkt[enc_msg_len] = rc;
378 : : enc_msg_len++;
379 : : if(enc_msg_len == AFL_MAX_PKT_SIZE-1)
380 : : break;
381 : : }
382 : : fclose(fp);
383 : :
384 : : fko_new(&decrypt_ctx);
385 : :
386 : : res = fko_afl_set_spa_data(decrypt_ctx, (const char *)enc_spa_pkt,
387 : : enc_msg_len);
388 : : if(res == FKO_SUCCESS)
389 : : res = fko_decrypt_spa_data(decrypt_ctx, "fwknoptest",
390 : : strlen("fwknoptest"));
391 : : if(res == FKO_SUCCESS)
392 : : res = dump_ctx_to_buffer(decrypt_ctx, dump_buf, sizeof(dump_buf));
393 : : if(res == FKO_SUCCESS)
394 : : log_msg(LOG_INFO, "%s", dump_buf);
395 : : else
396 : : log_msg(LOG_ERR, "Error (%d): %s", res, fko_errstr(res));
397 : :
398 : : fko_destroy(decrypt_ctx);
399 : :
400 : : if(res == FKO_SUCCESS)
401 : : {
402 : : log_msg(LOG_INFO, "SPA packet decode: %s", fko_errstr(res));
403 : : es = EXIT_SUCCESS;
404 : : }
405 : : else
406 : : {
407 : : log_msg(LOG_ERR, "Could not decode SPA packet: %s", fko_errstr(res));
408 : : es = EXIT_FAILURE;
409 : : }
410 : : }
411 : : else
412 : : log_msg(LOG_ERR, "Could not acquire SPA packet from file: %s.",
413 : : opts->config[CONF_AFL_PKT_FILE]);
414 : :
415 : : clean_exit(opts, NO_FW_CLEANUP, es);
416 : : }
417 : :
418 : : static void afl_pkt_from_stdin(fko_srv_options_t *opts)
419 : : {
420 : : FILE *fp = NULL;
421 : : fko_ctx_t decode_ctx = NULL;
422 : : unsigned char spa_pkt[AFL_MAX_PKT_SIZE] = {0};
423 : : int res = 0, es = EXIT_SUCCESS;
424 : : char dump_buf[AFL_DUMP_CTX_SIZE];
425 : :
426 : : fp = fdopen(STDIN_FILENO, "r");
427 : : if(fp != NULL)
428 : : {
429 : : if(fgets((char *)spa_pkt, AFL_MAX_PKT_SIZE, fp) == NULL)
430 : : {
431 : : fclose(fp);
432 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
433 : : }
434 : :
435 : : fclose(fp);
436 : :
437 : : fko_new(&decode_ctx);
438 : :
439 : : res = fko_set_encoded_data(decode_ctx, (char *) spa_pkt,
440 : : strlen((char *)spa_pkt), 0, FKO_DIGEST_SHA256);
441 : :
442 : : if(res == FKO_SUCCESS)
443 : : res = fko_set_spa_data(decode_ctx, (const char *) spa_pkt);
444 : : if(res == FKO_SUCCESS)
445 : : res = fko_decode_spa_data(decode_ctx);
446 : : if(res == FKO_SUCCESS)
447 : : res = dump_ctx_to_buffer(decode_ctx, dump_buf, sizeof(dump_buf));
448 : : if(res == FKO_SUCCESS)
449 : : log_msg(LOG_INFO, "%s", dump_buf);
450 : :
451 : : fko_destroy(decode_ctx);
452 : :
453 : : if(res == FKO_SUCCESS)
454 : : {
455 : : log_msg(LOG_INFO, "SPA packet decode: %s", fko_errstr(res));
456 : : es = EXIT_SUCCESS;
457 : : }
458 : : else
459 : : {
460 : : log_msg(LOG_ERR, "Could not decode SPA packet: %s", fko_errstr(res));
461 : : es = EXIT_FAILURE;
462 : : }
463 : : }
464 : : else
465 : : log_msg(LOG_ERR, "Could not acquire SPA packet from stdin.");
466 : :
467 : : clean_exit(opts, NO_FW_CLEANUP, es);
468 : : }
469 : : #endif
470 : :
471 : 508 : static void init_digest_cache(fko_srv_options_t *opts)
472 : : {
473 : : int rp_cache_count;
474 : :
475 : : #if AFL_FUZZING
476 : : if(opts->afl_fuzzing)
477 : : return;
478 : : #endif
479 : :
480 [ + - ]: 508 : if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
481 : : {
482 : 508 : rp_cache_count = replay_cache_init(opts);
483 : :
484 [ + + ]: 508 : if(rp_cache_count < 0)
485 : : {
486 : 2 : log_msg(LOG_WARNING,
487 : : "Error opening digest cache file. Incoming digests will not be remembered."
488 : : );
489 : : /* Destination points to heap memory, and is guaranteed to be
490 : : * at least two bytes large via validate_options(),
491 : : * DEF_ENABLE_DIGEST_PERSISTENCE, and set_config_entry()
492 : : */
493 : 2 : strlcpy(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "N", 2);
494 : : }
495 : :
496 [ + + ]: 508 : if(opts->verbose)
497 : 500 : log_msg(LOG_ERR,
498 : : "Using Digest Cache: '%s' (entry count = %i)",
499 : : #if USE_FILE_CACHE
500 : : opts->config[CONF_DIGEST_FILE], rp_cache_count
501 : : #else
502 : : opts->config[CONF_DIGEST_DB_FILE], rp_cache_count
503 : : #endif
504 : : );
505 : : }
506 : 508 : return;
507 : : }
508 : :
509 : 506 : static void setup_pid(fko_srv_options_t *opts)
510 : : {
511 : : pid_t old_pid;
512 : :
513 : : #if AFL_FUZZING
514 : : if(opts->afl_fuzzing)
515 : : return;
516 : : #endif
517 : :
518 : : /* If we are a new process (just being started), proceed with normal
519 : : * start-up. Otherwise, we are here as a result of a signal sent to an
520 : : * existing process and we want to restart.
521 : : */
522 [ + + ]: 506 : if(get_running_pid(opts) != getpid())
523 : : {
524 : : /* If foreground mode is not set, then fork off and become a daemon.
525 : : * Otherwise, attempt to get the pid file lock and go on.
526 : : */
527 [ + + ]: 505 : if(opts->foreground == 0)
528 : : {
529 : 5 : daemonize_process(opts);
530 : : }
531 : : else
532 : : {
533 : 500 : old_pid = write_pid_file(opts);
534 [ - + ]: 500 : if(old_pid > 0)
535 : : {
536 : 0 : fprintf(stderr,
537 : : "[*] An instance of fwknopd is already running: (PID=%i).\n", old_pid
538 : : );
539 : :
540 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
541 : : }
542 [ - + ]: 500 : else if(old_pid < 0)
543 : : {
544 : 0 : fprintf(stderr, "[*] PID file error. The lock may not be effective.\n");
545 : : }
546 : : }
547 : :
548 : 505 : log_msg(LOG_INFO, "Starting %s", MY_NAME);
549 : : }
550 : : else
551 : : {
552 : 1 : log_msg(LOG_INFO, "Re-starting %s", MY_NAME);
553 : : }
554 : :
555 : 506 : return;
556 : : }
557 : :
558 : 1 : static int restart_fwknopd(fko_srv_options_t * const opts)
559 : : {
560 : 1 : int res = 0;
561 : : pid_t old_pid;
562 : :
563 : 1 : old_pid = get_running_pid(opts);
564 : :
565 [ + - ]: 1 : if(old_pid > 0)
566 : : {
567 : 1 : res = kill(old_pid, SIGHUP);
568 [ - + ]: 1 : if(res == 0)
569 : : {
570 : 0 : fprintf(stdout, "Sent restart signal to fwknopd (pid=%i)\n", old_pid);
571 : 0 : return EXIT_SUCCESS;
572 : : }
573 : : else
574 : : {
575 : 1 : perror("Unable to send signal to fwknop: ");
576 : 1 : return EXIT_FAILURE;
577 : : }
578 : : }
579 : :
580 : 0 : fprintf(stdout, "No running fwknopd detected.\n");
581 : 0 : return EXIT_FAILURE;
582 : : }
583 : :
584 : 892 : static int status_fwknopd(fko_srv_options_t * const opts)
585 : : {
586 : : pid_t old_pid;
587 : :
588 : 892 : old_pid = write_pid_file(opts);
589 : :
590 [ + + ]: 892 : if(old_pid > 0)
591 : : {
592 : 442 : fprintf(stdout, "Detected fwknopd is running (pid=%i).\n", old_pid);
593 : 442 : return EXIT_SUCCESS;
594 : : }
595 : :
596 : 450 : fprintf(stdout, "No running fwknopd detected.\n");
597 : 450 : return EXIT_FAILURE;
598 : : }
599 : :
600 : 464 : static int handle_signals(fko_srv_options_t *opts)
601 : : {
602 : 464 : int last_sig = 0, rv = 1;
603 : :
604 [ + + ]: 464 : if(got_signal) {
605 : 441 : last_sig = got_signal;
606 : 441 : got_signal = 0;
607 : :
608 [ + + ]: 441 : if(got_sighup)
609 : : {
610 : 2 : log_msg(LOG_WARNING, "Got SIGHUP. Re-reading configs.");
611 : 2 : free_configs(opts);
612 [ - + ]: 2 : if(opts->tcp_server_pid > 0)
613 : 0 : kill(opts->tcp_server_pid, SIGTERM);
614 : 2 : usleep(1000000);
615 : 2 : got_sighup = 0;
616 : 2 : rv = 0; /* this means fwknopd will not exit */
617 : : }
618 [ + + ]: 439 : else if(got_sigint)
619 : : {
620 : 2 : log_msg(LOG_WARNING, "Got SIGINT. Exiting...");
621 : 2 : got_sigint = 0;
622 : : }
623 [ + - ]: 437 : else if(got_sigterm)
624 : : {
625 : 437 : log_msg(LOG_WARNING, "Got SIGTERM. Exiting...");
626 : 437 : got_sigterm = 0;
627 : : }
628 : : else
629 : : {
630 : 0 : log_msg(LOG_WARNING,
631 : : "Got signal %i. No defined action but to exit.", last_sig);
632 : : }
633 : : }
634 [ + - ]: 23 : else if (opts->packet_ctr_limit > 0
635 [ + - ]: 23 : && opts->packet_ctr >= opts->packet_ctr_limit)
636 : : {
637 : 23 : log_msg(LOG_INFO,
638 : : "Packet count limit (%d) reached. Exiting...",
639 : : opts->packet_ctr_limit);
640 : : }
641 : : else /* got_signal was not set (should be if we are here) */
642 : : {
643 : 0 : log_msg(LOG_WARNING,
644 : : "Capture ended without signal. Exiting...");
645 : : }
646 : 464 : return rv;
647 : : }
648 : :
649 : 454 : static int stop_fwknopd(fko_srv_options_t * const opts)
650 : : {
651 : 454 : int res = 0, is_err = 0, sleep_num = 0;
652 : : pid_t old_pid;
653 : :
654 : 454 : old_pid = get_running_pid(opts);
655 : :
656 [ + - ]: 454 : if(old_pid > 0)
657 : : {
658 : 454 : res = kill(old_pid, SIGTERM);
659 : 454 : is_err = kill(old_pid, 0);
660 : :
661 [ + - ]: 454 : if(res == 0 && is_err != 0)
662 : : {
663 : 0 : fprintf(stdout, "Killed fwknopd (pid=%i)\n", old_pid);
664 : 0 : return EXIT_SUCCESS;
665 : : }
666 : : else
667 : : {
668 : : /* give a bit of time for process shutdown and check again
669 : : */
670 [ + + ]: 1049 : for (sleep_num = 0; sleep_num < 4; sleep_num++) {
671 : 1028 : is_err = kill(old_pid, 0);
672 [ + + ]: 1028 : if(is_err != 0)
673 : : {
674 : 433 : fprintf(stdout, "Killed fwknopd (pid=%i) via SIGTERM\n",
675 : : old_pid);
676 : 433 : return EXIT_SUCCESS;
677 : : }
678 : 595 : sleep(1);
679 : : }
680 [ - + ]: 21 : if(is_err != 0)
681 : : {
682 : 0 : fprintf(stdout, "Killed fwknopd (pid=%i) via SIGTERM\n",
683 : : old_pid);
684 : 0 : return EXIT_SUCCESS;
685 : : }
686 : : else
687 : : {
688 : 21 : res = kill(old_pid, SIGKILL);
689 : 21 : is_err = kill(old_pid, 0);
690 [ - + ]: 21 : if(res == 0 && is_err != 0)
691 : : {
692 : 0 : fprintf(stdout,
693 : : "Killed fwknopd (pid=%i) via SIGKILL\n",
694 : : old_pid);
695 : 0 : return EXIT_SUCCESS;
696 : : }
697 : : else
698 : : {
699 : 21 : sleep(1);
700 : 21 : is_err = kill(old_pid, 0);
701 [ + - ]: 21 : if(is_err != 0)
702 : : {
703 : 21 : fprintf(stdout,
704 : : "Killed fwknopd (pid=%i) via SIGKILL\n",
705 : : old_pid);
706 : 21 : return EXIT_SUCCESS;
707 : : }
708 : : else
709 : : {
710 : 0 : perror("Unable to kill fwknop: ");
711 : 0 : return EXIT_FAILURE;
712 : : }
713 : : }
714 : : }
715 : : }
716 : : }
717 : :
718 : 0 : fprintf(stderr, "No running fwknopd detected.\n");
719 : 0 : return EXIT_FAILURE;
720 : : }
721 : :
722 : : /* Ensure the specified directory exists. If not, create it or die.
723 : : */
724 : : static int
725 : 4675 : check_dir_path(const char * const filepath, const char * const fp_desc, const unsigned char use_basename)
726 : : {
727 : : struct stat st;
728 : 4675 : int res = 0;
729 : : char tmp_path[MAX_PATH_LEN];
730 : : char *ndx;
731 : :
732 : : /*
733 : : * FIXME: We shouldn't use a hard-coded dir-separator here.
734 : : */
735 : : /* But first make sure we are using an absolute path.
736 : : */
737 [ + + ]: 4675 : if(*filepath != PATH_SEP)
738 : : {
739 : 1 : log_msg(LOG_ERR,
740 : : "Path '%s' is not absolute.", filepath
741 : : );
742 : 1 : return 0;
743 : : }
744 : :
745 : : /* If this is a file path that we want to use only the basename, strip
746 : : * the trailing filename here.
747 : : */
748 [ - + ][ # # ]: 4674 : if(use_basename && ((ndx = strrchr(filepath, PATH_SEP)) != NULL))
749 : 0 : strlcpy(tmp_path, filepath, (ndx-filepath)+1);
750 : : else
751 : 4674 : strlcpy(tmp_path, filepath, sizeof(tmp_path));
752 : :
753 : : /* At this point, we should make the path is more than just the
754 : : * PATH_SEP. If it is not, silently return.
755 : : */
756 [ + - ]: 4674 : if(strlen(tmp_path) < 2)
757 : : return 1;
758 : :
759 : : /* Make sure we have a valid directory.
760 : : */
761 : 4674 : res = stat(tmp_path, &st);
762 [ + + ]: 4674 : if(res != 0)
763 : : {
764 [ + - ]: 1 : if(errno == ENOENT)
765 : : {
766 : 1 : log_msg(LOG_WARNING,
767 : : "%s directory: %s does not exist. Attempting to create it.",
768 : : fp_desc, tmp_path
769 : : );
770 : :
771 : : /* Directory does not exist, so attempt to create it.
772 : : */
773 : 1 : res = make_dir_path(tmp_path);
774 [ - + ]: 1 : if(res != 0)
775 : : {
776 : 0 : log_msg(LOG_ERR,
777 : : "Unable to create %s directory: %s (error: %i)",
778 : : fp_desc, tmp_path, errno
779 : : );
780 : 0 : return 0;
781 : : }
782 : :
783 : 1 : log_msg(LOG_ERR,
784 : : "Successfully created %s directory: %s", fp_desc, tmp_path
785 : : );
786 : : }
787 : : else
788 : : {
789 : 0 : log_msg(LOG_ERR,
790 : : "Stat of %s returned error %i", tmp_path, errno
791 : : );
792 : 0 : return 0;
793 : : }
794 : : }
795 : : else
796 : : {
797 : : /* It is a file, but is it a directory?
798 : : */
799 [ + + ]: 4673 : if(! S_ISDIR(st.st_mode))
800 : : {
801 : 1 : log_msg(LOG_ERR,
802 : : "Specified %s directory: %s is NOT a directory", fp_desc, tmp_path
803 : : );
804 : 1 : return 0;
805 : : }
806 : : }
807 : : return 1;
808 : : }
809 : :
810 : : static int
811 : 1 : make_dir_path(const char * const run_dir)
812 : : {
813 : : struct stat st;
814 : 1 : int res = 0;
815 : : char tmp_path[MAX_PATH_LEN];
816 : : char *ndx;
817 : :
818 : 1 : strlcpy(tmp_path, run_dir, sizeof(tmp_path));
819 : :
820 : : /* Strip any trailing dir sep char.
821 : : */
822 : 1 : chop_char(tmp_path, PATH_SEP);
823 : :
824 [ + + ]: 52 : for(ndx = tmp_path+1; *ndx; ndx++)
825 : : {
826 [ + + ]: 51 : if(*ndx == '/')
827 : : {
828 : 7 : *ndx = '\0';
829 : :
830 : : /* Stat this part of the path to see if it is a valid directory.
831 : : * If it does not exist, attempt to create it. If it does, and
832 : : * it is a directory, go on. Otherwise, any other error cause it
833 : : * to bail.
834 : : */
835 [ + + ]: 7 : if(stat(tmp_path, &st) != 0)
836 : : {
837 [ + - ]: 2 : if(errno == ENOENT)
838 : : {
839 : 2 : res = mkdir(tmp_path, S_IRWXU);
840 [ - + ]: 2 : if(res != 0)
841 : 0 : return res;
842 : :
843 : : /* run stat() against the component since we just
844 : : * created it
845 : : */
846 [ - + ]: 2 : if(stat(tmp_path, &st) != 0)
847 : : {
848 : 0 : log_msg(LOG_ERR,
849 : : "Could not create component: %s of %s", tmp_path, run_dir
850 : : );
851 : 0 : return(ENOTDIR);
852 : : }
853 : : }
854 : : }
855 : :
856 [ - + ]: 7 : if(! S_ISDIR(st.st_mode))
857 : : {
858 : 0 : log_msg(LOG_ERR,
859 : : "Component: %s of %s is NOT a directory", tmp_path, run_dir
860 : : );
861 : 0 : return(ENOTDIR);
862 : : }
863 : :
864 : 7 : *ndx = '/';
865 : : }
866 : : }
867 : :
868 : 1 : res = mkdir(tmp_path, S_IRWXU);
869 : :
870 : 1 : return(res);
871 : : }
872 : :
873 : : /* Become a daemon: fork(), start a new session, chdir "/",
874 : : * and close unneeded standard filehandles.
875 : : */
876 : : static void
877 : 5 : daemonize_process(fko_srv_options_t * const opts)
878 : : {
879 : : pid_t pid, old_pid;
880 : :
881 : : /* Reset the our umask
882 : : */
883 : 5 : umask(0);
884 : :
885 [ - + ]: 5 : if ((pid = fork()) < 0)
886 : : {
887 : 0 : perror("Unable to fork: ");
888 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
889 : : }
890 [ + + ]: 10 : else if (pid != 0) /* parent */
891 : : {
892 : 5 : clean_exit(opts, NO_FW_CLEANUP, EXIT_SUCCESS);
893 : : }
894 : :
895 : : /* Child process from here on out */
896 : :
897 : : /* Start a new session
898 : : */
899 : 5 : setsid();
900 : :
901 : : /* Create the PID file (or be blocked by an existing one).
902 : : */
903 : 5 : old_pid = write_pid_file(opts);
904 [ - + ]: 5 : if(old_pid > 0)
905 : : {
906 : 0 : fprintf(stderr,
907 : : "[*] An instance of fwknopd is already running: (PID=%i).\n", old_pid
908 : : );
909 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
910 : : }
911 [ - + ]: 5 : else if(old_pid < 0)
912 : : {
913 : 0 : fprintf(stderr,
914 : : "[*] PID file error. The lock may not be effective.\n");
915 : : }
916 : :
917 : : /* Chdir to the root of the filesystem
918 : : */
919 [ - + ]: 5 : if ((chdir("/")) < 0) {
920 : 0 : perror("Could not chdir() to /: ");
921 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
922 : : }
923 : :
924 : : /* Close un-needed file handles
925 : : */
926 : 5 : close(STDIN_FILENO);
927 : 5 : close(STDOUT_FILENO);
928 : 5 : close(STDERR_FILENO);
929 : :
930 : 5 : return;
931 : : }
932 : :
933 : : static int
934 : 1397 : write_pid_file(fko_srv_options_t *opts)
935 : : {
936 : : pid_t old_pid, my_pid;
937 : : int op_fd, lck_res, num_bytes;
938 : 1397 : char buf[PID_BUFLEN] = {0};
939 : :
940 : : /* Reset errno (just in case)
941 : : */
942 : 1397 : errno = 0;
943 : :
944 : : /* Open the PID file
945 : : */
946 : 1397 : op_fd = open(
947 : 1397 : opts->config[CONF_FWKNOP_PID_FILE], O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR
948 : : );
949 : :
950 [ - + ]: 1397 : if(op_fd == -1)
951 : : {
952 : 0 : perror("Error trying to open PID file: ");
953 : 0 : return -1;
954 : : }
955 : :
956 [ - + ]: 1397 : if(fcntl(op_fd, F_SETFD, FD_CLOEXEC) == -1)
957 : : {
958 : 0 : close(op_fd);
959 : 0 : perror("Unexpected error from fcntl: ");
960 : 0 : return -1;
961 : : }
962 : :
963 : : /* Attempt to lock the PID file. If we get an EWOULDBLOCK
964 : : * error, another instance already has the lock. So we grab
965 : : * the pid from the existing lock file, complain and bail.
966 : : */
967 : 1397 : lck_res = lockf(op_fd, F_TLOCK, 0);
968 [ + + ]: 1397 : if(lck_res == -1)
969 : : {
970 : 442 : close(op_fd);
971 : :
972 [ - + ]: 442 : if(errno != EAGAIN)
973 : : {
974 : 0 : perror("Unexpected error from lockf: ");
975 : 0 : return -1;
976 : : }
977 : :
978 : : /* Look for an existing lock holder. If we get a pid return it.
979 : : */
980 : 442 : old_pid = get_running_pid(opts);
981 [ - + ]: 442 : if(old_pid)
982 : : return old_pid;
983 : :
984 : : /* Otherwise, consider it an error.
985 : : */
986 : 0 : perror("Unable read existing PID file: ");
987 : 0 : return -1;
988 : : }
989 : :
990 : : /* Write our PID to the file
991 : : */
992 : 955 : my_pid = getpid();
993 : : snprintf(buf, PID_BUFLEN, "%i\n", my_pid);
994 : :
995 : 955 : log_msg(LOG_DEBUG, "[+] Writing my PID (%i) to the lock file: %s",
996 : : my_pid, opts->config[CONF_FWKNOP_PID_FILE]);
997 : :
998 : 955 : num_bytes = write(op_fd, buf, strlen(buf));
999 : :
1000 [ + - ][ + + ]: 955 : if(errno || num_bytes != strlen(buf))
1001 : 1 : perror("Lock may not be valid. PID file write error: ");
1002 : :
1003 : : /* Sync/flush regardless...
1004 : : */
1005 : 955 : fsync(op_fd);
1006 : :
1007 : : /* Put the lock file discriptor in out options struct so any
1008 : : * child processes we my spawn can close and release it.
1009 : : */
1010 : 955 : opts->lock_fd = op_fd;
1011 : :
1012 : 955 : return 0;
1013 : : }
1014 : :
1015 : : static pid_t
1016 : 1403 : get_running_pid(const fko_srv_options_t *opts)
1017 : : {
1018 : 1403 : int op_fd, is_err, bytes_read = 0;
1019 : 1403 : char buf[PID_BUFLEN] = {0};
1020 : 1403 : pid_t rpid = 0;
1021 : :
1022 : :
1023 [ - + ]: 1403 : if(verify_file_perms_ownership(opts->config[CONF_FWKNOP_PID_FILE]) != 1)
1024 : : {
1025 : 0 : fprintf(stderr, "verify_file_perms_ownership() error\n");
1026 : 0 : return(rpid);
1027 : : }
1028 : :
1029 : 2806 : op_fd = open(opts->config[CONF_FWKNOP_PID_FILE], O_RDONLY);
1030 : :
1031 [ - + ]: 1403 : if(op_fd == -1)
1032 : : {
1033 [ # # ][ # # ]: 0 : if((opts->foreground != 0) && (opts->verbose != 0))
1034 : 0 : perror("Error trying to open PID file: ");
1035 : : return(rpid);
1036 : : }
1037 : :
1038 : 1403 : bytes_read = read(op_fd, buf, PID_BUFLEN);
1039 [ + - ]: 1403 : if (bytes_read > 0)
1040 : : {
1041 : 1403 : buf[PID_BUFLEN-1] = '\0';
1042 : : /* max pid value is configurable on Linux
1043 : : */
1044 : 1403 : rpid = (pid_t) strtol_wrapper(buf, 0, (2 << 30),
1045 : : NO_EXIT_UPON_ERR, &is_err);
1046 [ - + ]: 1403 : if(is_err != FKO_SUCCESS)
1047 : 0 : rpid = 0;
1048 : : }
1049 [ # # ]: 0 : else if (bytes_read < 0)
1050 : 0 : perror("Error trying to read() PID file: ");
1051 : :
1052 : 1403 : close(op_fd);
1053 : :
1054 : 1403 : return(rpid);
1055 : : }
1056 : :
1057 : : #if HAVE_LIBFIU
1058 : : static void
1059 : 6027 : enable_fault_injections(fko_srv_options_t * const opts)
1060 : : {
1061 [ + + ]: 6027 : if(opts->config[CONF_FAULT_INJECTION_TAG] != NULL)
1062 : : {
1063 [ + - ]: 36 : if(opts->verbose)
1064 : 36 : log_msg(LOG_INFO, "Enable fault injection tag: %s",
1065 : : opts->config[CONF_FAULT_INJECTION_TAG]);
1066 [ - + ]: 36 : if(fiu_init(0) != 0)
1067 : : {
1068 : 0 : fprintf(stderr, "[*] Could not enable fault injection tag: %s\n",
1069 : : opts->config[CONF_FAULT_INJECTION_TAG]);
1070 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1071 : : }
1072 [ - + ]: 36 : if (fiu_enable(opts->config[CONF_FAULT_INJECTION_TAG], 1, NULL, 0) != 0)
1073 : : {
1074 : 0 : fprintf(stderr, "[*] Could not enable fault injection tag: %s\n",
1075 : : opts->config[CONF_FAULT_INJECTION_TAG]);
1076 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1077 : : }
1078 : : }
1079 : 6027 : return;
1080 : : }
1081 : : #endif
1082 : :
1083 : : /***EOF***/
|