[test suite] added tests/rijndael_hmac_fuzzing.pl file
[fwknop.git] / perl / legacy / fwknop / knopmd.c
1 /*
2 ******************************************************************************
3 *
4 *  File: knopmd.c
5 *
6 *  Purpose: knopmd separates iptables messages from all other kernel
7 *           messages.  NOTE: This daemon is obselete since the main method
8 *           of passive authorization is Single Packet Authorization (SPA),
9 *           which offers better security properties than port knocking.
10 *
11 *  Author: Michael Rash (mbr@cipherdyne.org)
12 *
13 *  Version: 1.8
14 *
15 *  Copyright (C) 2004-2009 Michael Rash (mbr@cipherdyne.org)
16 *
17 *  License (GNU Public License):
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 *  NOTE: This code is essentially borrowed from kmsgsd.c that is bundled
30 *        psad: http://www.cipherdyne.org/psad/
31 *
32 ******************************************************************************
33 *
34 *  $Id: knopmd.c 1519 2009-08-11 23:56:57Z mbr $
35 */
36
37 /* includes */
38 #include "fwknop.h"
39 #include <getopt.h>
40
41 /* defines */
42 #define FWKNOP_CONF "/etc/fwknop/fwknop.conf"
43
44 /* globals */
45 static volatile sig_atomic_t received_sighup = 0;
46 extern char *optarg; /* for getopt */
47 extern int   optind; /* for getopt */
48 char *fw_msg_search[MAX_GEN_LEN];
49 int num_fw_search_strings = 0;
50 int fw_search_all_flag = 1;  /* default to parse all iptables messages */
51 char fwknopfifo_file[MAX_PATH_LEN];
52 char fwdata_file[MAX_PATH_LEN];
53 char config_file[MAX_PATH_LEN];
54 char fw_search_file[MAX_PATH_LEN];
55 char knopmd_pid_file[MAX_PATH_LEN];
56 char fwknop_dir[MAX_PATH_LEN];
57 char fwknop_fifo_dir[MAX_PATH_LEN];
58 char fwknop_run_dir[MAX_PATH_LEN];
59
60 /* prototypes */
61 static void parse_config(void);
62 static void find_sub_var_value(
63     char *value,
64     char *sub_var,
65     char *pre_str,
66     char *post_str
67 );
68 static void expand_config_vars(void);
69 static void check_auth_mode(void);
70 static int match_fw_msg(char *fw_mgs);
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     strlcpy(config_file, FWKNOP_CONF, MAX_PATH_LEN);
90
91     while((cmdlopt = getopt(argc, argv, "c:")) != -1) {
92         switch(cmdlopt) {
93             case 'c':
94                 strlcpy(config_file, optarg, MAX_PATH_LEN);
95                 break;
96             default:
97                 printf("[+] Usage:  knopmd [-c <config file>] ");
98                 exit(EXIT_FAILURE);
99         }
100     }
101
102 #ifdef DEBUG
103     fprintf(stderr, "[+] parsing config_file: %s\n", config_file);
104 #endif
105     /* parse config file (knopmd.conf) */
106     parse_config();
107
108     /* make sure there isn't another knopmd already running */
109     check_unique_pid(knopmd_pid_file, "knopmd");
110
111 #ifndef DEBUG
112     /* become a daemon */
113     daemonize_process(knopmd_pid_file);
114 #endif
115
116     /* install signal handler for HUP signals */
117     signal(SIGHUP, sighup_handler);
118
119     /* start doing the real work now that the daemon is running and
120      * the config file has been processed */
121
122     /* open the fwknopfifo named pipe.  Note that we are opening the pipe
123      * _without_ the O_NONBLOCK flag since we want the read on the file
124      * descriptor to block until there is something new in the pipe.
125      * Also, not that we are opening with O_RDWR, since this seems to
126      * fix the problem with knopmd not blocking on the read() if the
127      * system logger dies (and hence closes its file descriptor for the
128      * fwknopfifo). */
129     if ((fifo_fd = open(fwknopfifo_file, O_RDWR)) < 0) {
130         fprintf(stderr, "[-] Could not open %s for reading.\n",
131             fwknopfifo_file);
132         exit(EXIT_FAILURE);  /* could not open fwknopfifo named pipe */
133     }
134
135     /* open the fwdata file in append mode so we can write messages from
136      * the pipe into this file. */
137     if ((fwdata_fd = open(fwdata_file,
138             O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0) {
139         fprintf(stderr, "[-] Could not open %s for writing.\n", fwdata_file);
140         exit(EXIT_FAILURE);  /* could not open fwdata file */
141     }
142
143     /* MAIN LOOP;
144      * Read data from the pipe indefinitely (we opened it _without_
145      * O_NONBLOCK) and write it to the fwdata file if it is a firewall message
146      */
147     while ((numbytes = read(fifo_fd, buf, MAX_LINE_BUF-1)) >= 0) {
148
149 #ifdef DEBUG
150         fprintf(stderr,
151             "read %d bytes from %s fifo.\n", numbytes, fwknopfifo_file);
152 #endif
153
154         /* make sure the buf contents qualifies as a string */
155         buf[numbytes] = '\0';
156
157         if (received_sighup) {
158             /* clear the signal flag */
159             received_sighup = 0;
160
161             /* re-parse the config file after receiving HUP signal */
162             parse_config();
163
164             /* close file descriptors and re-open them after
165              * re-reading config file */
166             close(fifo_fd);
167             close(fwdata_fd);
168
169             /* re-open fwknopfifo and fwdata files */
170             if ((fifo_fd = open(fwknopfifo_file, O_RDONLY)) < 0) {
171                 fprintf(stderr, "[-] Could not open %s for reading.\n",
172                     fwknopfifo_file);
173                 exit(EXIT_FAILURE);  /* could not open fwknopfifo named pipe */
174             }
175
176             if ((fwdata_fd = open(fwdata_file, O_CREAT|O_WRONLY|O_APPEND,
177                     0600)) < 0) {
178                 fprintf(stderr, "[-] Could not open %s for writing.\n",
179                     fwdata_file);
180                 exit(EXIT_FAILURE);  /* could not open fwdata file */
181             }
182             slogr("fwknop(knopmd)",
183                     "[+] received HUP signal, re-imported knopmd.conf");
184         }
185
186         /* see if we matched a firewall message and write it to the
187          * fwdata file */
188         if ((strstr(buf, "OUT") != NULL
189                 && strstr(buf, "IN") != NULL)) {
190             if (! fw_search_all_flag) {  /* we are looking for specific log prefixes */
191                 if (match_fw_msg(buf)) {
192                     if (write(fwdata_fd, buf, numbytes) < 0) {
193                         exit(EXIT_FAILURE);  /* could not write to the fwdata file */
194                     }
195 #ifdef DEBUG
196                     matched_ipt_log_msg = 1;
197 #endif
198                 }
199             } else {
200                 if (write(fwdata_fd, buf, numbytes) < 0)
201                     exit(EXIT_FAILURE);  /* could not write to the fwdata file */
202 #ifdef DEBUG
203                 matched_ipt_log_msg = 1;
204 #endif
205             }
206 #ifdef DEBUG
207             if (matched_ipt_log_msg) {
208                 puts(buf);
209                 fprintf(stderr, "[+] Line matched search strings.\n");
210                 fwlinectr++;
211                 if (fwlinectr % 50 == 0)
212                     fprintf(stderr,
213                         "[+] Processed %d firewall lines.\n", fwlinectr);
214                 matched_ipt_log_msg = 0;
215             } else {
216                 puts(buf);
217                 printf("[-] Line did not match search strings.\n");
218             }
219 #endif
220         }
221     }
222
223     /* these statements don't get executed, but for completeness... */
224     close(fifo_fd);
225     close(fwdata_fd);
226
227     exit(EXIT_SUCCESS);
228 }
229 /******************** end main ********************/
230
231 static int match_fw_msg(char *fw_msg)
232 {
233     int i;
234     for (i=0; i < num_fw_search_strings; i++)
235         if (strstr(fw_msg, fw_msg_search[i]) != NULL)
236             return 1;
237     return 0;
238 }
239
240 static void parse_config(void)
241 {
242     FILE *config_ptr;   /* FILE pointer to the config file */
243     unsigned int linectr = 0, i;
244     char config_buf[MAX_LINE_BUF], tmp_fw_search_buf[MAX_GEN_LEN];
245     char *index;
246
247     /* first check to see if knopmd should not be running (i.e.
248      * AUTH_MODE in the fwknop.conf file is set to a pcap-based
249      * method). */
250     check_auth_mode();
251
252     for (i=0; i < num_fw_search_strings; i++)
253         free(fw_msg_search[i]);
254
255     num_fw_search_strings = 0;
256     fw_msg_search[num_fw_search_strings] = NULL;
257
258     if ((config_ptr = fopen(config_file, "r")) == NULL) {
259         fprintf(stderr, "[-] Could not open %s for reading.\n",
260             config_file);
261         exit(EXIT_FAILURE);
262     }
263
264     /* increment through each line of the config file */
265     while ((fgets(config_buf, MAX_LINE_BUF, config_ptr)) != NULL) {
266         linectr++;
267         /* set the index pointer to the beginning of the line */
268         index = config_buf;
269
270         /* advance the index pointer through any whitespace
271          * at the beginning of the line */
272         while (*index == ' ' || *index == '\t') index++;
273
274         /* skip comments and blank lines, etc. */
275         if ((*index != '#') && (*index != '\n') &&
276                 (*index != ';') && (index != NULL)) {
277
278             find_char_var("FWKNOP_DIR", fwknop_dir, index);
279             find_char_var("KNOPMD_FIFO", fwknopfifo_file, index);
280             find_char_var("FW_DATA_FILE", fwdata_file, index);
281             find_char_var("KNOPMD_PID_FILE", knopmd_pid_file, index);
282             find_char_var("FWKNOP_LIB_DIR", fwknop_fifo_dir, index);
283             find_char_var("FWKNOP_RUN_DIR", fwknop_run_dir, index);
284
285             if (find_char_var("FW_MSG_SEARCH", tmp_fw_search_buf, index)) {
286                 fw_msg_search[num_fw_search_strings]
287                     = (char *) safe_malloc(strlen(tmp_fw_search_buf)+1);
288                 strlcpy(fw_msg_search[num_fw_search_strings],
289                     tmp_fw_search_buf, MAX_GEN_LEN);
290                 num_fw_search_strings++;
291             }
292             if (find_char_var("FW_SEARCH_ALL", tmp_fw_search_buf, index)) {
293                 if (tmp_fw_search_buf[0] == 'N')
294                     fw_search_all_flag = 0;
295             }
296         }
297     }
298     fclose(config_ptr);
299
300     /* resolve any embedded variables */
301     expand_config_vars();
302
303 #ifdef DEBUG
304     fprintf(stderr, "[+] FWKNOP_DIR: %s\n", fwknop_dir);
305     fprintf(stderr, "[+] KNOPMD_FIFO: %s\n", fwknopfifo_file);
306     fprintf(stderr, "[+] FW_DATA_FILE: %s\n", fwdata_file);
307     fprintf(stderr, "[+] KNOPMD_PID_FILE: %s\n", knopmd_pid_file);
308 #endif
309     return;
310 }
311
312 static void check_auth_mode(void)
313 {
314     FILE *config_ptr;   /* FILE pointer to the config file */
315     char config_buf[MAX_LINE_BUF];
316     char auth_mode[MAX_GEN_LEN];
317     char *index;
318
319     if ((config_ptr = fopen(FWKNOP_CONF, "r")) == NULL) {
320         fprintf(stderr, "[-] Could not open %s for reading.\n",
321             FWKNOP_CONF);
322         exit(EXIT_FAILURE);
323     }
324
325     auth_mode[0] = '\0';
326
327     /* increment through each line of the config file */
328     while ((fgets(config_buf, MAX_LINE_BUF, config_ptr)) != NULL) {
329         /* set the index pointer to the beginning of the line */
330         index = config_buf;
331
332         /* advance the index pointer through any whitespace
333          * at the beginning of the line */
334         while (*index == ' ' || *index == '\t') index++;
335
336         /* skip comments and blank lines, etc. */
337         if ((*index != '#') && (*index != '\n') &&
338                 (*index != ';') && (index != NULL)) {
339
340             find_char_var("AUTH_MODE ", auth_mode, index);
341         }
342     }
343     fclose(config_ptr);
344
345     /* see if we are using the ULOG_PCAP mode */
346     if (strncmp(auth_mode, "ULOG_PCAP", MAX_GEN_LEN) == 0)
347         exit(EXIT_FAILURE);
348
349     /* see if we are using the PCAP mode */
350     if (strncmp(auth_mode, "PCAP", MAX_GEN_LEN) == 0)
351         exit(EXIT_FAILURE);
352
353     return;
354 }
355
356 static void expand_config_vars(void)
357 {
358     char sub_var[MAX_GEN_LEN]  = "";
359     char pre_str[MAX_GEN_LEN]  = "";
360     char post_str[MAX_GEN_LEN] = "";
361     int found_sub_var = 1, resolve_ctr = 0;
362
363     while (found_sub_var) {
364         resolve_ctr++;
365         if (resolve_ctr >= 20) {
366             fprintf(stderr, "[*] Exceeded maximum variable resolution attempts.\n");
367             exit(EXIT_FAILURE);
368         }
369         found_sub_var = 0;
370
371         if (has_sub_var("FW_DATA_FILE", fwdata_file, sub_var,
372                 pre_str, post_str)) {
373             find_sub_var_value(fwdata_file, sub_var, pre_str, post_str);
374             found_sub_var = 1;
375         }
376
377         if (has_sub_var("KNOPMD_FIFO", fwknopfifo_file, sub_var,
378                 pre_str, post_str)) {
379             find_sub_var_value(fwknopfifo_file, sub_var, pre_str, post_str);
380             found_sub_var = 1;
381         }
382
383         if (has_sub_var("KNOPMD_PID_FILE", knopmd_pid_file, sub_var,
384                 pre_str, post_str)) {
385             find_sub_var_value(knopmd_pid_file, sub_var, pre_str, post_str);
386             found_sub_var = 1;
387         }
388     }
389     return;
390 }
391
392 static void find_sub_var_value(char *value, char *sub_var, char *pre_str,
393     char *post_str)
394 {
395     int found_var = 0;
396     if (strncmp(sub_var, "FWKNOP_DIR", MAX_GEN_LEN) == 0) {
397         strlcpy(sub_var, fwknop_dir, MAX_GEN_LEN);
398         found_var = 1;
399     } else if (strncmp(sub_var, "FWKNOP_LIB_DIR", MAX_GEN_LEN) == 0) {
400         strlcpy(sub_var, fwknop_fifo_dir, MAX_GEN_LEN);
401         found_var = 1;
402     } else if (strncmp(sub_var, "FWKNOP_RUN_DIR", MAX_GEN_LEN) == 0) {
403         strlcpy(sub_var, fwknop_run_dir, MAX_GEN_LEN);
404         found_var = 1;
405     } else if (strncmp(sub_var, "FW_DATA_FILE", MAX_GEN_LEN) == 0) {
406         strlcpy(sub_var, fwdata_file, MAX_GEN_LEN);
407         found_var = 1;
408     } else if (strncmp(sub_var, "KNOPMD_FIFO", MAX_GEN_LEN) == 0) {
409         strlcpy(sub_var, fwknopfifo_file, MAX_GEN_LEN);
410         found_var = 1;
411     } else if (strncmp(sub_var, "KNOPMD_PID_FILE", MAX_GEN_LEN) == 0) {
412         strlcpy(sub_var, knopmd_pid_file, MAX_GEN_LEN);
413         found_var = 1;
414     }
415
416     if (found_var) {
417
418         /* substitute the variable value */
419         expand_sub_var_value(value, sub_var, pre_str, post_str);
420
421     } else {
422         fprintf(stderr, "[*] Could not resolve sub-var: %s to a value.\n",
423             sub_var);
424         exit(EXIT_FAILURE);
425     }
426     return;
427 }
428
429 static void sighup_handler(int sig)
430 {
431     received_sighup = 1;
432 }