0eaf02c4ad1bd7cbbdb356b1ecc45c66ad1dd214
[psad.git] / psadwatchd.c
1 /*
2 *****************************************************************************
3 *
4 *  File: psadwatchd.c
5 *
6 *  Purpose: psadwatchd checks on an interval of every five seconds to make
7 *           sure that both kmsgsd and psad are running on the box. If
8 *           either daemon has died, psadwatchd will restart it and notify
9 *           each email address in @email_addresses that the daemon has been
10 *           restarted.
11 *
12 *  Author: Michael Rash (mbr@cipherdyne.org)
13 *
14 *  Credits:  (see the CREDITS file)
15 *
16 *  Copyright (C) 1999-2007 Michael Rash (mbr@cipherdyne.org)
17 *
18 *  License (GNU Public License):
19 *
20 *     This program is distributed in the hope that it will be useful,
21 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
22 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 *     GNU General Public License for more details.
24 *
25 *     You should have received a copy of the GNU General Public License
26 *     along with this program; if not, write to the Free Software
27 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 *     USA
29 *
30 *****************************************************************************
31 */
32
33 /* includes */
34 #include "psad.h"
35
36 /* defines */
37 #define CONFIG_FILE "/etc/psad/psad.conf" /* only used for DATA_INPUT_METHOD */
38
39 /* Maximum number of overwrite files allowed on the command line */
40 #define MAX_OVW_FILES   3
41
42 /* globals */
43 short int psad_syscalls_ctr     = 0;
44 short int kmsgsd_syscalls_ctr   = 0;
45 unsigned short int no_email     = 0;
46 unsigned short int check_kmsgsd;
47 const char mail_redr[] = " < /dev/null > /dev/null 2>&1";
48 char hostname[MAX_GEN_LEN];
49 char mail_addrs[MAX_EMAIL_LEN];
50 char shCmd[MAX_GEN_LEN];
51 char mailCmd[MAX_GEN_LEN];
52 char alerting_methods[MAX_GEN_LEN];
53 char psadCmd[MAX_PATH_LEN];
54 char psad_pid_file[MAX_PATH_LEN];
55 char psad_cmdline_file[MAX_PATH_LEN];
56 char psad_run_dir[MAX_PATH_LEN];
57 char kmsgsdCmd[MAX_PATH_LEN];
58 char kmsgsd_pid_file[MAX_PATH_LEN];
59 char psadwatchd_pid_file[MAX_PATH_LEN];
60 char data_input_mode[MAX_GEN_LEN];
61 char enable_syslog_file[MAX_GEN_LEN];
62 char char_psadwatchd_check_interval[MAX_NUM_LEN];
63 char char_psadwatchd_max_retries[MAX_NUM_LEN];
64 unsigned int psadwatchd_check_interval;
65 unsigned int psadwatchd_max_retries;
66 static volatile sig_atomic_t received_sighup = 0;
67 unsigned char dump_cfg;
68
69 /* prototypes */
70 static void usage(void);
71 static void clean_settings(void);
72 static void parse_config(char *file);
73 static void check_config(void);
74 static void dump_config(void);
75 static unsigned short int is_kmsgsd_required(void);
76
77 static void expand_config_vars(void);
78 static void find_sub_var_value(
79     char *value,
80     char *sub_var,
81     char *pre_str,
82     char *post_str
83 );
84 static void check_process(
85     const char *pid_name,
86     const char *pid_file,
87     const char *cmdline_file,
88     const char *binary_path,
89     unsigned int max_retries
90 );
91 static void incr_syscall_ctr(const char *pid_name, unsigned int max_retries);
92 static void reset_syscall_ctr(const char *pid_name);
93 static void give_up(const char *pid_name);
94 static void exec_binary(const char *binary_path, const char *cmdline_file);
95 static void sighup_handler(int sig);
96
97 /* main */
98 int main(int argc, char *argv[]) {
99
100     int    cmdlopt;
101     char **ovw_file_ptr;
102     char  *overwrite_files[MAX_OVW_FILES+1];
103     char   overwrite_cmd[MAX_PATH_LEN];
104     char   config_file[MAX_PATH_LEN];
105
106 #ifdef DEBUG
107     fprintf(stderr, "[+] Entering DEBUG mode\n");
108     sleep(1);
109 #endif
110
111     overwrite_files[0] = NULL;
112     strlcpy(config_file, CONFIG_FILE, MAX_PATH_LEN);
113     dump_cfg = 0;
114
115     while((cmdlopt = getopt(argc, argv, "c:O:Dh")) != -1) {
116         switch(cmdlopt) {
117             case 'c':
118                 strlcpy(config_file, optarg, MAX_PATH_LEN);
119                 break;
120             case 'O':
121                 strlcpy(overwrite_cmd, optarg, MAX_PATH_LEN);
122                 list_to_array(overwrite_cmd, ',', overwrite_files, MAX_OVW_FILES);
123                 break;
124             case 'D':
125                 dump_cfg = 1;
126                 break;
127             default:
128                 usage();
129         }
130     }
131
132     /* clean our settings */
133     clean_settings();
134
135     /* Parse both the overwrite and configuration file */
136     for (ovw_file_ptr=overwrite_files; *ovw_file_ptr!=NULL; ovw_file_ptr++)
137         parse_config(*ovw_file_ptr);
138     parse_config(config_file);
139
140     /* Check our settings */
141     check_config();
142
143     if (dump_cfg == 1)
144         dump_config();
145
146     /* see if we are suppose to disable all email alerts */
147     if (strncmp("noemail", alerting_methods, MAX_GEN_LEN) == 0)
148         no_email = 1;
149
150     /* first make sure there isn't another psadwatchd already running */
151     check_unique_pid(psadwatchd_pid_file, "psadwatchd");
152
153 #ifndef DEBUG
154     /* become a daemon */
155     daemonize_process(psadwatchd_pid_file);
156 #endif
157
158     /* install signal handler for HUP signals */
159     signal(SIGHUP, sighup_handler);
160
161     /* start doing the real work now that the daemon is running and
162      * the config file has been processed */
163
164     /* MAIN LOOP */
165     for (;;) {
166         /* restart processes as necessary */
167         check_process("psad", psad_pid_file, psad_cmdline_file,
168             psadCmd, psadwatchd_max_retries);
169
170         if (check_kmsgsd)
171             check_process("kmsgsd", kmsgsd_pid_file, NULL,
172                 kmsgsdCmd, psadwatchd_max_retries);
173
174         /* sleep and then check to see if we received any signals */
175         sleep(psadwatchd_check_interval);
176
177         /* check for sighup */
178         if (received_sighup) {
179
180             slogr("psad(psadwatchd)", "received HUP signal");
181             received_sighup = 0;
182
183             /* clean our settings */
184             clean_settings();
185
186             /* reparse the config file since we received a HUP signal */
187             for (ovw_file_ptr=overwrite_files; *ovw_file_ptr!=NULL; ovw_file_ptr++)
188                 parse_config(*ovw_file_ptr);
189             parse_config(config_file);
190
191             check_config();
192         }
193     }
194
195     /* this statement doesn't get executed, but for completeness... */
196     exit(EXIT_SUCCESS);
197 }
198 /******************** end main ********************/
199
200 static void check_process(
201     const char *pid_name,
202     const char *pid_file,
203     const char *cmdline_file,
204     const char *binary_path,
205     unsigned int max_retries)
206 {
207     FILE *pidfile_ptr;
208     pid_t pid;
209     unsigned short int restart = 0;
210     char mail_str[MAX_MSG_LEN] = "";
211     char syslog_str[MAX_MSG_LEN] = "";
212     char pid_line[MAX_PID_SIZE];
213
214     if ((pidfile_ptr = fopen(pid_file, "r")) == NULL) {
215 #ifdef DEBUG
216     fprintf(stderr, "[-] Could not open pid file: %s\n", pid_file);
217 #endif
218         /* the pid file must not exist (or we can't read it), so
219          * setup to start the appropriate process */
220         restart = 1;
221     }
222
223     /* read the first line of the pid_file, which will contain the
224      * process id of any running pid_name process. */
225     if (! restart) {
226         if (fgets(pid_line, MAX_PID_SIZE, pidfile_ptr) == NULL) {
227 #ifdef DEBUG
228             fprintf(stderr, "[-] Could not read the pid file: %s\n",
229                 pid_file);
230 #endif
231             /* see if we need to give up */
232             incr_syscall_ctr(pid_name, max_retries);
233             fclose(pidfile_ptr);
234             return;
235         }
236
237         /* convert the pid_line into an integer */
238         pid = atoi(pid_line);
239
240         /* close the pid_file now that we have read it */
241         fclose(pidfile_ptr);
242
243         if (kill(pid, 0) != 0) {
244             /* the process is not running so start it */
245             restart = 1;
246         }
247     }
248
249     if (restart) {
250 #ifdef DEBUG
251         fprintf(stderr, "[+] executing exec_binary(%s)\n", binary_path);
252 #endif
253         //strlcat(mail_str, mailCmd, MAX_MSG_LEN);
254         strlcat(mail_str, " -s \"[*] psadwatchd: Restarting ", MAX_MSG_LEN);
255         strlcat(mail_str, pid_name, MAX_MSG_LEN);
256         strlcat(mail_str, " on ", MAX_MSG_LEN);
257         strlcat(mail_str, hostname, MAX_MSG_LEN);
258         strlcat(mail_str, "\" ", MAX_MSG_LEN);
259         strlcat(mail_str, mail_addrs, MAX_MSG_LEN);
260         strlcat(mail_str, mail_redr, MAX_MSG_LEN);
261
262 #ifdef DEBUG
263         fprintf(stderr, "sending mail:  %s\n", mail_str);
264 #endif
265
266         snprintf(syslog_str, MAX_MSG_LEN,
267             "restarting %s on %s", pid_name, hostname);
268         slogr("psad(psadwatchd)", syslog_str);
269
270         if (! no_email) {
271             /* send the email */
272             send_alert_email(shCmd, mailCmd, mail_str);
273         }
274
275         /* execute the binary_path psad daemon */
276         exec_binary(binary_path, cmdline_file);
277
278         /* increment the number of times we have tried to restart the binary */
279         incr_syscall_ctr(pid_name, max_retries);
280     } else {
281 #ifdef DEBUG
282         fprintf(stderr, "[+] %s is running.\n", pid_name);
283 #endif
284         /* reset the syscall counter since the process is successfully
285          * running. */
286         reset_syscall_ctr(pid_name);
287     }
288     return;
289 }
290
291 static void incr_syscall_ctr(const char *pid_name, unsigned int max_retries)
292 {
293     if (strncmp("psad", pid_name, MAX_PATH_LEN) == 0) {
294         psad_syscalls_ctr++;
295 #ifdef DEBUG
296         fprintf(stderr,
297             "[-] %s not running. Trying to restart (%d tries so far).\n",
298             pid_name, psad_syscalls_ctr);
299 #endif
300         if (psad_syscalls_ctr >= max_retries)
301             give_up(pid_name);
302     } else if (strncmp("kmsgsd", pid_name, MAX_PATH_LEN) == 0) {
303         kmsgsd_syscalls_ctr++;
304 #ifdef DEBUG
305         fprintf(stderr,
306             "[-] %s not running. Trying to restart (%d tries so far).\n",
307             pid_name, kmsgsd_syscalls_ctr);
308 #endif
309         if (kmsgsd_syscalls_ctr >= max_retries)
310             give_up(pid_name);
311     }
312     return;
313 }
314
315 static void reset_syscall_ctr(const char *pid_name)
316 {
317     if (strncmp("psad", pid_name, MAX_PATH_LEN) == 0) {
318         psad_syscalls_ctr = 0;
319     } else if (strncmp("kmsgsd", pid_name, MAX_PATH_LEN) == 0) {
320         kmsgsd_syscalls_ctr = 0;
321     }
322     return;
323 }
324
325 static void give_up(const char *pid_name)
326 {
327     char mail_str[MAX_MSG_LEN] = "";
328 #ifdef DEBUG
329     fprintf(stderr, "[*] Could not restart %s process. Exiting.\n", pid_name);
330 #endif
331     strlcat(mail_str, " -s \"[*] psadwatchd: Could not restart ", MAX_MSG_LEN);
332     strlcat(mail_str, pid_name, MAX_MSG_LEN);
333     strlcat(mail_str, " on ", MAX_MSG_LEN);
334     strlcat(mail_str, hostname, MAX_MSG_LEN);
335     strlcat(mail_str, ". Exiting.\" ", MAX_MSG_LEN);
336     strlcat(mail_str, mail_addrs, MAX_MSG_LEN);
337     strlcat(mail_str, mail_redr, MAX_MSG_LEN);
338
339     if (! no_email) {
340         /* Send the email */
341         send_alert_email(shCmd, mailCmd, mail_str);
342     }
343     exit(EXIT_FAILURE);
344 }
345
346 static void exec_binary(const char *binary, const char *cmdlinefile)
347 {
348     FILE *cmdline_ptr;
349     char *prog_argv[MAX_ARG_LEN];
350     char cmdline_buf[MAX_LINE_BUF];
351     char *index;
352     pid_t child_pid;
353     int arg_num=0, non_ws, i;
354
355     prog_argv[arg_num] = (char *) safe_malloc(strlen(binary)+1);
356
357     strlcpy(prog_argv[arg_num], binary, strlen(binary)+1);
358     arg_num++;
359
360     if (cmdlinefile != NULL) {
361         /* restart binary with its command line arguments intact */
362         if ((cmdline_ptr = fopen(cmdlinefile, "r")) == NULL) {
363             exit(EXIT_FAILURE);
364         }
365         if ((fgets(cmdline_buf, MAX_LINE_BUF, cmdline_ptr)) == NULL) {
366             exit(EXIT_FAILURE);
367         }
368         fclose(cmdline_ptr);
369
370         /* initialize index to the beginning of the line */
371         index = cmdline_buf;
372
373         /* advance the index pointer through any whitespace
374          * at the beginning of the line */
375         while (*index == ' ' || *index == '\t') index++;
376
377         while (*index != '\n' && *index != '\0') {
378             non_ws = 0;
379             while (*index != ' ' && *index != '\t'
380                     && index != '\0' && *index != '\n') {
381                 index++;
382                 non_ws++;
383             }
384
385             if (arg_num >= MAX_ARG_LEN)
386                 exit(EXIT_FAILURE);
387
388             prog_argv[arg_num] = (char *) safe_malloc(non_ws+1);
389
390             for (i=0; i<non_ws; i++)
391                 prog_argv[arg_num][i] = *(index - (non_ws - i));
392             prog_argv[arg_num][i] = '\0';
393
394             arg_num++;
395
396             /* get past any whitespace */
397             while (*index == ' ' || *index == '\t') index++;
398         }
399     }
400
401     if (arg_num >= MAX_ARG_LEN)
402         exit(EXIT_FAILURE);
403     prog_argv[arg_num] = NULL;
404
405     if ((child_pid = fork()) < 0)
406         /* could not fork */
407         exit(EXIT_FAILURE);
408     else if (child_pid > 0) {
409         wait(NULL);
410         for (i=0; i<=arg_num; i++) {
411             free(prog_argv[i]);
412         }
413     } else {
414 #ifdef DEBUG
415         fprintf(stderr, "[+] restarting %s\n", binary);
416 #endif
417         execve(binary, prog_argv, NULL);  /* don't use environment */
418     }
419     return;
420 }
421
422 static void parse_config(char * file)
423 {
424     FILE *config_ptr;         /* FILE pointer to the config file */
425     int linectr = 0;
426     char config_buf[MAX_LINE_BUF];
427     char *index;
428     int tmp;
429
430 #ifdef DEBUG
431     fprintf(stderr, "[+] Parsing file %s\n", file);
432 #endif
433
434     if ((config_ptr = fopen(file, "r")) == NULL) {
435         perror("[*] Could not open config file");
436         exit(EXIT_FAILURE);
437     }
438
439     /* increment through each line of the config file */
440     while ((fgets(config_buf, MAX_LINE_BUF, config_ptr)) != NULL) {
441         linectr++;
442         index = config_buf;  /* set the index pointer to the
443                                 beginning of the line */
444
445         /* advance the index pointer through any whitespace
446          * at the beginning of the line */
447         while (*index == ' ' || *index == '\t') index++;
448
449         /* skip comments and blank lines, etc. */
450         if ((*index != '#') && (*index != '\n') &&
451                 (*index != ';') && (index != NULL)) {
452
453             find_char_var("HOSTNAME", hostname, index);
454             find_char_var("PSAD_RUN_DIR", psad_run_dir, index);
455             find_char_var("PSAD_PID_FILE", psad_pid_file, index);
456             find_char_var("PSAD_CMDLINE_FILE", psad_cmdline_file, index);
457             find_char_var("ALERTING_METHODS", alerting_methods, index);
458             find_char_var("KMSGSD_PID_FILE", kmsgsd_pid_file, index);
459             find_char_var("PSADWATCHD_PID_FILE", psadwatchd_pid_file, index);
460             find_char_var("PSADWATCHD_CHECK_INTERVAL",
461                 char_psadwatchd_check_interval, index);
462             find_char_var("PSADWATCHD_MAX_RETRIES",
463                 char_psadwatchd_max_retries, index);
464             find_char_var("SYSLOG_DAEMON", data_input_mode, index);
465             find_char_var("ENABLE_SYSLOG_FILE", enable_syslog_file, index);
466             find_char_var("EMAIL_ADDRESSES", mail_addrs, index);
467
468             /* commands */
469             find_char_var("kmsgsdCmd", kmsgsdCmd, index);
470             find_char_var("mailCmd", mailCmd, index);
471             find_char_var("shCmd", shCmd, index);
472             find_char_var("psadCmd", psadCmd, index);
473         }
474     }
475     fclose(config_ptr);
476
477     tmp = atoi(char_psadwatchd_check_interval);
478     if (tmp != 0)
479         psadwatchd_check_interval = tmp;
480
481     tmp = atoi(char_psadwatchd_max_retries);
482     if (tmp != 0)
483         psadwatchd_max_retries = tmp;
484
485     return;
486 }
487
488 static void expand_config_vars(void)
489 {
490     char sub_var[MAX_GEN_LEN]  = "";
491     char pre_str[MAX_GEN_LEN]  = "";
492     char post_str[MAX_GEN_LEN] = "";
493     int found_sub_var = 1, resolve_ctr = 0;
494
495     while (found_sub_var) {
496         resolve_ctr++;
497         if (resolve_ctr >= 20) {
498             fprintf(stderr, "[*] Exceeded maximum variable resolution attempts.\n");
499             exit(EXIT_FAILURE);
500         }
501         found_sub_var = 0;
502         if (has_sub_var("EMAIL_ADDRESSES", mail_addrs, sub_var,
503                 pre_str, post_str)) {
504             find_sub_var_value(mail_addrs, sub_var, pre_str, post_str);
505             found_sub_var = 1;
506         }
507
508         if (has_sub_var("HOSTNAME", hostname, sub_var,
509                 pre_str, post_str)) {
510             find_sub_var_value(hostname, sub_var, pre_str, post_str);
511             found_sub_var = 1;
512         }
513
514         if (has_sub_var("PSAD_RUN_DIR", psad_run_dir, sub_var,
515                 pre_str, post_str)) {
516             find_sub_var_value(psad_run_dir, sub_var, pre_str, post_str);
517             found_sub_var = 1;
518         }
519
520         if (has_sub_var("PSAD_PID_FILE", psad_pid_file, sub_var,
521                 pre_str, post_str)) {
522             find_sub_var_value(psad_pid_file, sub_var, pre_str, post_str);
523             found_sub_var = 1;
524         }
525
526         if (has_sub_var("PSAD_CMDLINE_FILE", psad_cmdline_file, sub_var,
527                 pre_str, post_str)) {
528             find_sub_var_value(psad_cmdline_file, sub_var, pre_str, post_str);
529             found_sub_var = 1;
530         }
531
532         if (has_sub_var("KMSGSD_PID_FILE", kmsgsd_pid_file, sub_var,
533                 pre_str, post_str)) {
534             find_sub_var_value(kmsgsd_pid_file, sub_var, pre_str, post_str);
535             found_sub_var = 1;
536         }
537
538         if (has_sub_var("PSADWATCHD_PID_FILE", psadwatchd_pid_file, sub_var,
539                 pre_str, post_str)) {
540             find_sub_var_value(psadwatchd_pid_file, sub_var, pre_str, post_str);
541             found_sub_var = 1;
542         }
543
544         if (has_sub_var("PSADWATCHD_CHECK_INTERVAL",
545                 char_psadwatchd_check_interval, sub_var,
546                 pre_str, post_str)) {
547             find_sub_var_value(char_psadwatchd_check_interval,
548                 sub_var, pre_str, post_str);
549             found_sub_var = 1;
550         }
551
552         if (has_sub_var("PSADWATCHD_MAX_RETRIES", char_psadwatchd_max_retries,
553                 sub_var, pre_str, post_str)) {
554             find_sub_var_value(char_psadwatchd_max_retries,
555                 sub_var, pre_str, post_str);
556             found_sub_var = 1;
557         }
558
559         if (has_sub_var("mailCmd", mailCmd, sub_var,
560                 pre_str, post_str)) {
561             find_sub_var_value(mailCmd, sub_var, pre_str, post_str);
562             found_sub_var = 1;
563         }
564
565         if (has_sub_var("shCmd", shCmd, sub_var,
566                 pre_str, post_str)) {
567             find_sub_var_value(shCmd, sub_var, pre_str, post_str);
568             found_sub_var = 1;
569         }
570
571         if (has_sub_var("kmsgsdCmd", kmsgsdCmd, sub_var,
572                 pre_str, post_str)) {
573             find_sub_var_value(kmsgsdCmd, sub_var, pre_str, post_str);
574             found_sub_var = 1;
575         }
576
577         if (has_sub_var("psadCmd", psadCmd, sub_var,
578                 pre_str, post_str)) {
579             find_sub_var_value(psadCmd, sub_var, pre_str, post_str);
580             found_sub_var = 1;
581         }
582     }
583
584     return;
585 }
586
587 static void find_sub_var_value(char *value, char *sub_var, char *pre_str,
588     char *post_str)
589 {
590     int found_var = 0;
591     if (strncmp(sub_var, "EMAIL_ADDRESSES", MAX_GEN_LEN) == 0) {
592         strlcpy(sub_var, mail_addrs, MAX_GEN_LEN);
593         found_var = 1;
594     } else if (strncmp(sub_var, "HOSTNAME", MAX_GEN_LEN) == 0) {
595         strlcpy(sub_var, hostname, MAX_GEN_LEN);
596         found_var = 1;
597     } else if (strncmp(sub_var, "PSAD_RUN_DIR", MAX_GEN_LEN) == 0) {
598         strlcpy(sub_var, psad_run_dir, MAX_GEN_LEN);
599         found_var = 1;
600     } else if (strncmp(sub_var, "PSAD_PID_FILE", MAX_GEN_LEN) == 0) {
601         strlcpy(sub_var, psad_pid_file, MAX_GEN_LEN);
602         found_var = 1;
603     } else if (strncmp(sub_var, "PSAD_CMDLINE_FILE", MAX_GEN_LEN) == 0) {
604         strlcpy(sub_var, psad_cmdline_file, MAX_GEN_LEN);
605         found_var = 1;
606     } else if (strncmp(sub_var, "KMSGSD_PID_FILE", MAX_GEN_LEN) == 0) {
607         strlcpy(sub_var, kmsgsd_pid_file, MAX_GEN_LEN);
608         found_var = 1;
609     } else if (strncmp(sub_var, "PSADWATCHD_PID_FILE", MAX_GEN_LEN) == 0) {
610         strlcpy(sub_var, psadwatchd_pid_file, MAX_GEN_LEN);
611         found_var = 1;
612     } else if (strncmp(sub_var, "PSADWATCHD_CHECK_INTERVAL", MAX_GEN_LEN) == 0) {
613         strlcpy(sub_var, char_psadwatchd_check_interval, MAX_GEN_LEN);
614         found_var = 1;
615     } else if (strncmp(sub_var, "PSADWATCHD_MAX_RETRIES", MAX_GEN_LEN) == 0) {
616         strlcpy(sub_var, char_psadwatchd_max_retries, MAX_GEN_LEN);
617         found_var = 1;
618     } else if (strncmp(sub_var, "mailCmd", MAX_GEN_LEN) == 0) {
619         strlcpy(sub_var, mailCmd, MAX_GEN_LEN);
620         found_var = 1;
621     } else if (strncmp(sub_var, "shCmd", MAX_GEN_LEN) == 0) {
622         strlcpy(sub_var, shCmd, MAX_GEN_LEN);
623         found_var = 1;
624     } else if (strncmp(sub_var, "kmsgsdCmd", MAX_GEN_LEN) == 0) {
625         strlcpy(sub_var, kmsgsdCmd, MAX_GEN_LEN);
626         found_var = 1;
627     } else if (strncmp(sub_var, "psadCmd", MAX_GEN_LEN) == 0) {
628         strlcpy(sub_var, psadCmd, MAX_GEN_LEN);
629         found_var = 1;
630     }
631
632     if (found_var)
633
634         /* substitute the variable value */
635         expand_sub_var_value(value, sub_var, pre_str, post_str);
636
637     else {
638         fprintf(stderr, "[*] Could not resolve sub-var: %s to a value.\n",
639             sub_var);
640         exit(EXIT_FAILURE);
641     }
642     return;
643 }
644
645 static void check_config(void)
646 {
647     unsigned char err;
648
649 #ifdef DEBUG
650     fprintf(stderr, "[+] Checking configuration...\n");
651 #endif
652
653     err = 1;
654     if (psadwatchd_check_interval <= 0)
655         fprintf(stderr, "[*] PSADWATCHD_CHECK_INTERVAL must be > 0\n");
656
657     else if (psadwatchd_max_retries <= 0)
658         fprintf(stderr, "[*] PSADWATCHD_MAX_RETRIES must be > 0\n");
659
660     else if (mail_addrs[0] == '\0')
661         fprintf(stderr, "[*] Could not find EMAIL_ADDRESSES\n");
662
663     else if (hostname[0] == '\0')
664         fprintf(stderr, "[*] Could not find HOSTNAME\n");
665
666     else if (psad_run_dir[0] == '\0')
667         fprintf(stderr, "[*] Could not find PSAD_RUN_DIR\n");
668
669     else if (psad_pid_file[0] == '\0')
670         fprintf(stderr, "[*] Could not find PSAD_PID_DIR\n");
671
672     else if (psad_cmdline_file[0] == '\0')
673         fprintf(stderr, "[*] Could not find PSAD_CMDLINE_FILE\n");
674
675     else if (kmsgsd_pid_file[0] == '\0')
676         fprintf(stderr, "[*] Could not find KMSGD_PID_FILE\n");
677
678     else if (psadwatchd_pid_file[0] == '\0')
679         fprintf(stderr, "[*] Could not find PSADWATCHD_PID_FILE\n");
680
681     else if (mailCmd[0] == '\0')
682         fprintf(stderr, "[*] Could not find mailCmd\n");
683
684     else if (shCmd[0] == '\0')
685         fprintf(stderr, "[*] Could not find shCmd\n");
686
687     else if (kmsgsdCmd[0] == '\0')
688         fprintf(stderr, "[*] Could not find kmsgsdCmd\n");
689
690     else if (psadCmd[0] == '\0')
691         fprintf(stderr, "[*] Could not find psadCmd\n");
692
693     else if (alerting_methods[0] == '\0')
694         fprintf(stderr, "[*] Could not find ALERTING_METHODS\n");
695
696     else {
697
698         /* Resolve any embedded variables */
699         expand_config_vars();
700
701         /* Refresh the need to check kmsgsd */
702         check_kmsgsd = is_kmsgsd_required();
703
704         err = 0;
705     }
706
707     if (err == 1)
708         exit(EXIT_FAILURE);
709 }
710
711 static void clean_settings (void)
712 {
713
714 #ifdef DEBUG
715     fprintf(stderr, "[+] Cleaning settings\n");
716 #endif
717
718     /* Set the default values used by psadwatchd when trying to
719      * restart the psad and kmsgsd daemons (5s /10 times) */
720     psadwatchd_check_interval = 5;
721     psadwatchd_max_retries    = 10;
722
723     *mail_addrs             = '\0';
724     *hostname               = '\0';
725     *psad_run_dir           = '\0';
726     *psad_pid_file          = '\0';
727     *psad_cmdline_file      = '\0';
728     *kmsgsd_pid_file        = '\0';
729     *psadwatchd_pid_file    = '\0';
730     *mailCmd                = '\0';
731     *shCmd                  = '\0';
732     *kmsgsdCmd              = '\0';
733     *psadCmd                = '\0';
734     *alerting_methods       = '\0';
735     
736     *data_input_mode        = '\0';
737     *enable_syslog_file     = '\0';
738 }
739
740 static void dump_config(void)
741 {
742     fprintf(stderr, "[+] dump_config()\n");
743     fprintf(stderr, "    EMAIL_ADDRESSES: %s\n", mail_addrs);
744     fprintf(stderr, "    HOSTNAME: %s\n", hostname);
745     fprintf(stderr, "    PSAD_RUN_DIR: %s\n", psad_run_dir);
746     fprintf(stderr, "    PSAD_PID_FILE: %s\n", psad_pid_file);
747     fprintf(stderr, "    PSAD_CMDLINE_FILE: %s\n", psad_cmdline_file);
748     fprintf(stderr, "    KMSGSD_PID_FILE: %s\n", kmsgsd_pid_file);
749     fprintf(stderr, "    ALERTING_METHODS: %s\n", alerting_methods);
750     fprintf(stderr, "    PSADWATCHD_PID_FILE: %s\n", psadwatchd_pid_file);
751     fprintf(stderr, "    PSADWATCHD_CHECK_INTERVAL: %u\n",
752         psadwatchd_check_interval);
753     fprintf(stderr, "    PSADWATCHD_MAX_RETRIES: %u\n",
754         psadwatchd_max_retries);
755     fprintf(stderr, "    kmsgsdCmd: %s\n", kmsgsdCmd);
756     fprintf(stderr, "    mailCmd: %s\n", mailCmd);
757     fprintf(stderr, "    shCmd: %s\n", shCmd);
758     fprintf(stderr, "    psadCmd: %s\n", psadCmd);
759
760     exit(EXIT_SUCCESS);
761 }
762
763 static void sighup_handler(int sig)
764 {
765     received_sighup = 1;
766 }
767
768 /*
769  * Check to see if kmsgsd should not be running:
770  *
771  *   - first check if we are using the ulog mode
772  *   - then, if ENABLE_SYSLOG_FILE is enabled so psad is just parsing
773  *     a file written to by syslog directly
774  *
775  * \return 0 if not required
776  *         1 otherwise
777  */
778 static unsigned short int is_kmsgsd_required(void)
779 {
780     unsigned short int required;
781
782     if (strncmp(data_input_mode, "ulogd", MAX_GEN_LEN) == 0)
783         required = 0;
784
785     else if (strncmp(enable_syslog_file, "Y", 1) == 0)
786         required = 0;
787
788     else
789         required = 1;
790
791     return required;
792 }
793
794 /*
795  * Usage message to be displayed when -h option is supplied or a bad option
796  * is passed to the daemon. This function ends the execution of the program.
797  */
798 static void usage (void)
799 {
800     fprintf(stderr, "psadwatchd - Psad watch daemon\n\n");
801
802     fprintf(stderr, "[+] Version: %s\n", PSAD_VERSION);
803     fprintf(stderr,
804 "    By Michael Rash (mbr@cipherdyne.org)\n"
805 "    URL: http://www.cipherdyne.org/psad/\n\n");
806
807     fprintf(stderr, "Usage: psadwatchd [options]\n\n");
808
809     fprintf(stderr,
810 "Options:\n"
811 "    -c <file>          - Specify path to config file instead of using the\n"
812 "                         default $config_file.\n"
813 "    -D                 - Dump  the  configuration values that psad\n"
814 "                         derives from the /etc/psad/psad.conf (or other\n"
815 "                         override files) on STDERR\n"
816 "    -h                 - Display this usage message and exit\n"
817 "    -O <file>          - Override config variable values that are normally\n"
818 "                         read from the /etc/psad/psad.conf file with\n"
819 "                         values from the specified file\n");
820
821     exit(EXIT_FAILURE);
822 }