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