root/psad/tags/psad-2.1.1/kmsgsd.c

Revision 2026, 13.6 kB (checked in by mbr, 2 years ago)

copyright date update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2 ******************************************************************************
3 *
4 *  File: kmsgsd.c
5 *
6 *  Purpose: kmsgsd separates iptables messages from all other
7 *           kernel messages.
8 *
9 *  Strategy: read messages from the /var/log/psadfifo named pipe and
10 *            print any firewall related dop/reject/deny messages to
11 *            the psad data file "/var/log/psad/fwdata".
12 *
13 *  Author: Michael Rash (mbr@cipherdyne.org)
14 *
15 *  Credits:  (see the CREDITS file)
16 *
17 *  Copyright (C) 1999-2007 Michael Rash (mbr@cipherdyne.org)
18 *
19 *  License (GNU Public License):
20 *
21 *     This program is distributed in the hope that it will be useful,
22 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
23 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 *     GNU General Public License for more details.
25 *
26 *     You should have received a copy of the GNU General Public License
27 *     along with this program; if not, write to the Free Software
28 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
29 *     USA
30 ******************************************************************************
31 *
32 *  $Id$
33 */
34
35 /* includes */
36 #include "psad.h"
37 #include <getopt.h>
38
39 /* defines */
40 #define CONFIG_FILE "/etc/psad/psad.conf"
41
42 /* globals */
43 static volatile sig_atomic_t received_sighup = 0;
44 extern char *optarg; /* for getopt */
45 extern int   optind; /* for getopt */
46 char *fw_msg_search[MAX_GEN_LEN];
47 char psadfifo_file[MAX_PATH_LEN];
48 char fwdata_file[MAX_PATH_LEN];
49 char config_file[MAX_PATH_LEN];
50 char fw_search_file[MAX_PATH_LEN];
51 char snort_sid_str[MAX_PATH_LEN];
52 char psad_dir[MAX_PATH_LEN];
53 char psad_fifo_dir[MAX_PATH_LEN];
54 char psad_run_dir[MAX_PATH_LEN];
55 char kmsgsd_pid_file[MAX_PATH_LEN];
56 int num_fw_search_strings = 0;
57 int fw_search_all_flag = 1;  /* default to parse all iptables messages */
58
59 /* prototypes */
60 static void parse_config(void);
61 static int match_fw_msg(char *fw_mgs);
62 static void find_sub_var_value(
63     char *value,
64     char *sub_var,
65     char *pre_str,
66     char *post_str
67 );
68 #ifdef DEBUG
69 static void dump_config(void);
70 #endif
71 static void expand_config_vars(void);
72 static void sighup_handler(int sig);
73
74 /* main */
75 int main(int argc, char *argv[]) {
76     char buf[MAX_LINE_BUF];
77     int fifo_fd, fwdata_fd;  /* file descriptors */
78     int cmdlopt, numbytes;
79 #ifdef DEBUG
80     int matched_ipt_log_msg = 0;
81     int fwlinectr = 0;
82 #endif
83
84 #ifdef DEBUG
85     fprintf(stderr, "[+] Entering DEBUG mode\n");
86     fprintf(stderr, "[+] Firewall messages will be written to both ");
87     fprintf(stderr, "STDOUT _and_ to fwdata.\n\n");
88 #endif
89
90     /* establish default paths to config file (may be
91      * overriden with command line args below */
92     strlcpy(config_file, CONFIG_FILE, MAX_PATH_LEN);
93
94     while((cmdlopt = getopt(argc, argv, "c:")) != -1) {
95         switch(cmdlopt) {
96             case 'c':
97                 strlcpy(config_file, optarg, MAX_PATH_LEN);
98                 break;
99             default:
100                 printf("[+] Usage:  kmsgsd [-c <config file>]\n");
101                 exit(EXIT_FAILURE);
102         }
103     }
104
105 #ifdef DEBUG
106     fprintf(stderr, "[+] parsing config_file: %s\n", config_file);
107 #endif
108     /* parse config file (psad.conf) */
109     parse_config();
110
111 #ifdef DEBUG
112     dump_config();
113 #endif
114
115     /* make sure there isn't another kmsgsd already running */
116     check_unique_pid(kmsgsd_pid_file, "kmsgsd");
117
118 #ifndef DEBUG
119     /* become a daemon */
120     daemonize_process(kmsgsd_pid_file);
121 #endif
122
123     /* install signal handler for HUP signals */
124     signal(SIGHUP, sighup_handler);
125
126     /* start doing the real work now that the daemon is running and
127      * the config file has been processed */
128
129     /* open the psadfifo named pipe.  Note that we are opening the pipe
130      * _without_ the O_NONBLOCK flag since we want the read on the file
131      * descriptor to block until there is something new in the pipe.
132      * Also, note that we are opening with O_RDWR, since this seems to
133      * fix the problem with kmsgsd not blocking on the read() if the
134      * system logger dies (and hence closes its file descriptor for the
135      * psadfifo). */
136     if ((fifo_fd = open(psadfifo_file, O_RDWR)) < 0) {
137         fprintf(stderr, "[*] Could not open %s for reading.\n",
138             psadfifo_file);
139         exit(EXIT_FAILURE);  /* could not open psadfifo named pipe */
140     }
141
142     /* open the fwdata file in append mode so we can write messages from
143      * the pipe into this file. */
144     if ((fwdata_fd = open(fwdata_file,
145             O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0) {
146         fprintf(stderr, "[*] Could not open %s for writing.\n", fwdata_file);
147         exit(EXIT_FAILURE);  /* could not open fwdata file */
148     }
149
150     /* MAIN LOOP;
151      * Read data from the pipe indefinitely (we opened it _without_
152      * O_NONBLOCK) and write it to the fwdata file if it is a firewall message
153      */
154     while ((numbytes = read(fifo_fd, buf, MAX_LINE_BUF-1)) >= 0) {
155
156 #ifdef DEBUG
157         fprintf(stderr,
158             "read %d bytes from %s fifo.\n", numbytes, psadfifo_file);
159 #endif
160
161         /* make sure the buf contents qualifies as a string */
162         buf[numbytes] = '\0';
163
164         if (received_sighup) {
165             /* clear the signal flag */
166             received_sighup = 0;
167
168             /* re-parse the config file after receiving HUP signal */
169             parse_config();
170
171             /* close file descriptors and re-open them after
172              * re-reading config file */
173             close(fifo_fd);
174             close(fwdata_fd);
175
176             /* re-open psadfifo and fwdata files */
177             if ((fifo_fd = open(psadfifo_file, O_RDWR)) < 0) {
178                 fprintf(stderr, "[*] Could not open %s for reading.\n",
179                     psadfifo_file);
180                 exit(EXIT_FAILURE);  /* could not open psadfifo named pipe */
181             }
182
183             if ((fwdata_fd = open(fwdata_file, O_CREAT|O_WRONLY|O_APPEND,
184                     0600)) < 0) {
185                 fprintf(stderr, "[*] Could not open %s for writing.\n",
186                     fwdata_file);
187                 exit(EXIT_FAILURE);  /* could not open fwdata file */
188             }
189             slogr("psad(kmsgsd)",
190                     "received HUP signal, re-imported psad.conf");
191         }
192
193         /* see if we matched a firewall message and write it to the
194          * fwdata file */
195         if ((strstr(buf, "OUT=") != NULL
196                 && strstr(buf, "IN=") != NULL)) {
197             if (! fw_search_all_flag) {
198                 /* we are looking for specific log prefixes */
199                 if (match_fw_msg(buf) || strstr(buf, snort_sid_str) != NULL) {
200                     if (write(fwdata_fd, buf, numbytes) < 0) {
201                         exit(EXIT_FAILURE);  /* could not write to the fwdata file */
202                     }
203 #ifdef DEBUG
204                     matched_ipt_log_msg = 1;
205 #endif
206                 }
207             } else {
208                 if (write(fwdata_fd, buf, numbytes) < 0)
209                     exit(EXIT_FAILURE);  /* could not write to the fwdata file */
210 #ifdef DEBUG
211                 matched_ipt_log_msg = 1;
212 #endif
213             }
214 #ifdef DEBUG
215             if (matched_ipt_log_msg) {
216                 puts(buf);
217                 fprintf(stderr, "[+] Line matched search strings.\n");
218                 fwlinectr++;
219                 if (fwlinectr % 50 == 0)
220                     fprintf(stderr,
221                         "[+] Processed %d firewall lines.\n", fwlinectr);
222                 matched_ipt_log_msg = 0;
223             } else {
224                 puts(buf);
225                 fprintf(stderr, "[-] Line did not match search strings.\n");
226             }
227 #endif
228         }
229     }
230
231     /* these statements don't get executed, but for completeness... */
232     close(fifo_fd);
233     close(fwdata_fd);
234
235     exit(EXIT_SUCCESS);
236 }
237 /******************** end main ********************/
238
239 static int match_fw_msg(char *fw_msg)
240 {
241     int i;
242     for (i=0; i < num_fw_search_strings; i++)
243         if (strstr(fw_msg, fw_msg_search[i]) != NULL)
244             return 1;
245     return 0;
246 }
247
248 static void parse_config(void)
249 {
250     FILE *config_ptr;   /* FILE pointer to the config file */
251     int linectr = 0, i;
252     char config_buf[MAX_LINE_BUF];
253     char tmp_fw_search_buf[MAX_GEN_LEN], *index;
254
255     for (i=0; i < num_fw_search_strings; i++)
256         if (fw_msg_search[i] != NULL)
257             free(fw_msg_search[i]);
258
259     num_fw_search_strings = 0;
260     fw_msg_search[num_fw_search_strings] = NULL;
261
262     if ((config_ptr = fopen(config_file, "r")) == NULL) {
263         fprintf(stderr, "[*] Could not open %s for reading.\n",
264             config_file);
265         exit(EXIT_FAILURE);
266     }
267
268     /* increment through each line of the config file */
269     while ((fgets(config_buf, MAX_LINE_BUF, config_ptr)) != NULL) {
270         linectr++;
271         /* set the index pointer to the beginning of the line */
272         index = config_buf;
273
274         /* advance the index pointer through any whitespace
275          * at the beginning of the line */
276         while (*index == ' ' || *index == '\t') index++;
277
278         /* skip comments and blank lines, etc. */
279         if ((*index != '#') && (*index != '\n') &&
280                 (*index != ';') && (index != NULL)) {
281
282             find_char_var("PSAD_DIR", psad_dir, index);
283             find_char_var("PSAD_FIFO_DIR", psad_fifo_dir, index);
284             find_char_var("PSAD_RUN_DIR", psad_run_dir, index);
285             find_char_var("SNORT_SID_STR", snort_sid_str, index);
286             find_char_var("PSAD_FIFO_FILE", psadfifo_file, index);
287             find_char_var("FW_DATA_FILE", fwdata_file, index);
288             find_char_var("KMSGSD_PID_FILE", kmsgsd_pid_file, index);
289             if (find_char_var("FW_MSG_SEARCH", tmp_fw_search_buf, index)) {
290                 fw_msg_search[num_fw_search_strings]
291                     = (char *) safe_malloc(strlen(tmp_fw_search_buf)+1);
292                 strlcpy(fw_msg_search[num_fw_search_strings],
293                     tmp_fw_search_buf, strlen(tmp_fw_search_buf)+1);
294                 num_fw_search_strings++;
295             }
296             if (find_char_var("FW_SEARCH_ALL", tmp_fw_search_buf, index)) {
297                 if (tmp_fw_search_buf[0] == 'N')
298                     fw_search_all_flag = 0;
299             }
300         }
301     }
302     fclose(config_ptr);
303
304     if (! fw_search_all_flag && num_fw_search_strings == 0) {
305         /* there are no FW_MSG_SEARCH vars in fw_search.conf; default
306          * to "DROP".  Psad will generate a syslog warning.  */
307         fw_msg_search[num_fw_search_strings]
308             = (char *) safe_malloc(strlen("DROP")+1);
309         strlcpy(fw_msg_search[0], "DROP", strlen("DROP")+1);
310         num_fw_search_strings++;
311     }
312
313     /* resolve any embedded variables */
314     expand_config_vars();
315
316     return;
317 }
318
319 static void expand_config_vars(void)
320 {
321     char sub_var[MAX_GEN_LEN]  = "";
322     char pre_str[MAX_GEN_LEN]  = "";
323     char post_str[MAX_GEN_LEN] = "";
324     int found_sub_var = 1, resolve_ctr = 0;
325
326     while (found_sub_var) {
327         resolve_ctr++;
328         if (resolve_ctr >= 20) {
329             fprintf(stderr, "[*] Exceeded maximum variable resolution attempts.\n");
330             exit(EXIT_FAILURE);
331         }
332         found_sub_var = 0;
333
334         if (has_sub_var("SNORT_SID_STR", snort_sid_str, sub_var,
335                 pre_str, post_str)) {
336             find_sub_var_value(snort_sid_str, sub_var, pre_str, post_str);
337             found_sub_var = 1;
338         }
339
340         if (has_sub_var("FW_DATA_FILE", fwdata_file, sub_var,
341                 pre_str, post_str)) {
342             find_sub_var_value(fwdata_file, sub_var, pre_str, post_str);
343             found_sub_var = 1;
344         }
345
346         if (has_sub_var("PSAD_FIFO_FILE", psadfifo_file, sub_var,
347                 pre_str, post_str)) {
348             find_sub_var_value(psadfifo_file, sub_var, pre_str, post_str);
349             found_sub_var = 1;
350         }
351
352         if (has_sub_var("KMSGSD_PID_FILE", kmsgsd_pid_file, sub_var,
353                 pre_str, post_str)) {
354             find_sub_var_value(kmsgsd_pid_file, sub_var, pre_str, post_str);
355             found_sub_var = 1;
356         }
357     }
358     return;
359 }
360
361 static void find_sub_var_value(char *value, char *sub_var, char *pre_str,
362     char *post_str)
363 {
364     int found_var = 0;
365     if (strncmp(sub_var, "PSAD_DIR", MAX_GEN_LEN) == 0) {
366         strlcpy(sub_var, psad_dir, MAX_GEN_LEN);
367         found_var = 1;
368     } else if (strncmp(sub_var, "PSAD_FIFO_DIR", MAX_GEN_LEN) == 0) {
369         strlcpy(sub_var, psad_fifo_dir, MAX_GEN_LEN);
370         found_var = 1;
371     } else if (strncmp(sub_var, "PSAD_RUN_DIR", MAX_GEN_LEN) == 0) {
372         strlcpy(sub_var, psad_run_dir, MAX_GEN_LEN);
373         found_var = 1;
374     } else if (strncmp(sub_var, "SNORT_SID_STR", MAX_GEN_LEN) == 0) {
375         strlcpy(sub_var, snort_sid_str, MAX_GEN_LEN);
376         found_var = 1;
377     } else if (strncmp(sub_var, "FW_DATA_FILE", MAX_GEN_LEN) == 0) {
378         strlcpy(sub_var, fwdata_file, MAX_GEN_LEN);
379         found_var = 1;
380     } else if (strncmp(sub_var, "PSAD_FIFO_FILE", MAX_GEN_LEN) == 0) {
381         strlcpy(sub_var, psadfifo_file, MAX_GEN_LEN);
382         found_var = 1;
383     } else if (strncmp(sub_var, "KMSGSD_PID_FILE", MAX_GEN_LEN) == 0) {
384         strlcpy(sub_var, kmsgsd_pid_file, MAX_GEN_LEN);
385         found_var = 1;
386     }
387
388     if (found_var) {
389
390         /* substitute the variable value */
391         expand_sub_var_value(value, sub_var, pre_str, post_str);
392
393     } else {
394         fprintf(stderr, "[*] Could not resolve sub-var: %s to a value.\n",
395             sub_var);
396         exit(EXIT_FAILURE);
397     }
398     return;
399 }
400
401 #ifdef DEBUG
402 static void dump_config(void)
403 {
404     fprintf(stderr, "[+] dump_config()\n");
405     fprintf(stderr, "    PSAD_DIR: %s\n", psad_dir);
406     fprintf(stderr, "    PSAD_FIFO_FILE: %s\n", psadfifo_file);
407     fprintf(stderr, "    FW_DATA_FILE: %s\n", fwdata_file);
408     fprintf(stderr, "    SNORT_SID_STR: %s\n", snort_sid_str);
409     fprintf(stderr, "    KMSGSD_PID_FILE: %s\n", kmsgsd_pid_file);
410     return;
411 }
412 #endif
413
414 static void sighup_handler(int sig)
415 {
416     received_sighup = 1;
417 }
Note: See TracBrowser for help on using the browser.