root/psad/tags/psad-2.0.2-pre7/kmsgsd.c

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

- Added has_sub_var() and expand_sub_var_value() to expand embedded variable

values.

- Simplified configuration parsing by using global variables.
- Added dump_config() in DEBUG mode.
- Updated find_char_var() to require a space char after a variable name (this

simplifies the calls to find_char_var() so that spaces do not have to be
part of the variable name that is passed in).

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