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