1 /* $Id$ */
2 /*
3 ** Copyright (C) 2002-2009 Sourcefire, Inc.
4 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 ** Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License Version 2 as
9 ** published by the Free Software Foundation. You may not use, modify or
10 ** distribute this program under any other version of the GNU General
11 ** Public License.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <stdarg.h>
36
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40
41 #ifndef WIN32
42 # include <netdb.h>
43 # include <sys/socket.h>
44 # include <netinet/in.h>
45 # include <arpa/inet.h>
46 # include <grp.h>
47 # include <pwd.h>
48 # include <fnmatch.h>
49 #endif /* !WIN32 */
50
51 #include "bounds.h"
52 #include "rules.h"
53 #include "parser.h"
54 #include "plugbase.h"
55 #include "debug.h"
56 #include "util.h"
57 #include "mstring.h"
58 #include "log.h"
59 #include "generators.h"
60 #include "strlcatu.h"
61 #include "strlcpyu.h"
62 #include "barnyard2.h"
63 #include "sf_vartable.h"
64 #include "ipv6_port.h"
65 #include "sfutil/sf_ip.h"
66
67 #ifdef TARGET_BASED
68 # include "sftarget_reader.h"
69 #endif
70
71 #ifdef PORTLISTS
72 # include "sfutil/sfrim.h"
73 # include "sfutil/sfportobject.h"
74 #endif
75
76 /* MPLS payload types */
77 #ifdef MPLS
78 # define MPLS_PAYLOAD_OPT__IPV4 "ipv4"
79 # define MPLS_PAYLOAD_OPT__IPV6 "ipv6"
80 # define MPLS_PAYLOAD_OPT__ETHERNET "ethernet"
81 #endif
82
83 /* Macros *********************************************************************/
84 #define MAX_RULE_OPTIONS 256
85 #define MAX_LINE_LENGTH 32768
86 #define MAX_IPLIST_ENTRIES 4096
87 #define DEFAULT_LARGE_RULE_GROUP 9
88 #define SF_IPPROTO_UNKNOWN -1
89 #define MAX_RULE_COUNT (65535 * 2)
90
91 /* For user defined rule type */
92 #define RULE_TYPE_OPT__TYPE "type"
93
94 #define ERR_PAIR_COUNT \
95 "%s has incorrect argument count; should be %d pairs.", ERR_KEY
96 #define ERR_NOT_PAIRED \
97 "%s is missing an option or argument to go with: %s.", ERR_KEY, pairs[0]
98 #define ERR_EXTRA_OPTION \
99 "%s has extra option of type: %s.", ERR_KEY, pairs[0]
100 #define ERR_BAD_OPTION \
101 "%s has unknown option: %s.", ERR_KEY, pairs[0]
102 #define ERR_BAD_VALUE \
103 "%s has unknown %s: %s.", ERR_KEY, pairs[0], pairs[1]
104 #define ERR_BAD_ARG_COUNT \
105 "%s has incorrect argument count.", ERR_KEY
106 #define ERR_CREATE \
107 "%s could not be created.", ERR_KEY
108 #define ERR_CREATE_EX \
109 "%s could not be created: %s.", ERR_KEY
110
111 // arbitrary conf file name used to allow initialization w/o conf
112 // (required for packet logging mode)
113 #define NULL_CONF "null"
114
115 /* Data types *****************************************************************/
116 typedef void (*ParseFunc)(Barnyard2Config *, char *);
117 typedef void (*ParseConfigFunc)(Barnyard2Config *, char *);
118
119 /* Used to determine whether or not to parse the keyword line based on
120 * whether or not we're parsing rules */
121 typedef enum _KeywordType
122 {
123 KEYWORD_TYPE__MAIN,
124 KEYWORD_TYPE__RULE,
125 KEYWORD_TYPE__ALL
126
127 } KeywordType;
128
129 typedef enum _VarType
130 {
131 VAR_TYPE__DEFAULT,
132 VAR_TYPE__PORTVAR,
133 VAR_TYPE__IPVAR
134
135 } VarType;
136
137 typedef struct _KeywordFunc
138 {
139 char *name;
140 KeywordType type;
141 int expand_vars;
142 ParseFunc parse_func;
143
144 } KeywordFunc;
145
146 typedef struct _ConfigFunc
147 {
148 char *name;
149 int args_required;
150 int only_once;
151 ParseConfigFunc parse_func;
152
153 } ConfigFunc;
154
155 /* Externs ********************************************************************/
156 extern VarNode *cmd_line_var_list;
157 extern char *barnyard2_conf_file;
158 extern char *barnyard2_conf_dir;
159
160 /* Globals ********************************************************************/
161
162 /* Set to the current barnyard2 config we're parsing. Mostly used for the
163 * plugins (input and output) since the callbacks don't pass a barnyard2
164 * configuration */
165 Barnyard2Config *barnyard2_conf_for_parsing = NULL;
166
167 char *file_name = NULL; /* current config file being processed */
168 int file_line = 0; /* current line being processed in the file */
169
170 /* Main parsing function uses this to indicate whether or not
171 * rules are to be parsed. */
172 static int parse_rules = 0;
173
174 static void ParseConfig(Barnyard2Config *, char *);
175 static void ParseIpVar(Barnyard2Config *, char *);
176 static void ParseVar(Barnyard2Config *, char *);
177 static void AddVarToTable(Barnyard2Config *, char *, char *);
178
179 static const KeywordFunc barnyard2_conf_keywords[] =
180 {
181 /* Non-rule keywords */
182 { BARNYARD2_CONF_KEYWORD__VAR, KEYWORD_TYPE__MAIN, 0, ParseVar },
183 { BARNYARD2_CONF_KEYWORD__CONFIG, KEYWORD_TYPE__MAIN, 1, ParseConfig },
184 { BARNYARD2_CONF_KEYWORD__IPVAR, KEYWORD_TYPE__MAIN, 0, ParseIpVar },
185 { BARNYARD2_CONF_KEYWORD__INPUT, KEYWORD_TYPE__MAIN, 1, ParseInput },
186 { BARNYARD2_CONF_KEYWORD__OUTPUT, KEYWORD_TYPE__MAIN, 1, ParseOutput },
187 { NULL, 0, 0, NULL } /* Marks end of array */
188 };
189
190 static const ConfigFunc config_opts[] =
191 {
192 { CONFIG_OPT__DISABLE_ALERT_ON_EACH_PACKET_IN_STREAM, 0, 1, ConfigDisableAlertOnEachPacketInStream },
193 { CONFIG_OPT__EVENT_CACHE_SIZE, 0, 1, ConfigSetEventCacheSize },
194 { CONFIG_OPT__ALERT_ON_EACH_PACKET_IN_STREAM, 0, 1, ConfigAlertOnEachPacketInStream },
195 { CONFIG_OPT__ALERT_WITH_IFACE_NAME, 0, 1, ConfigAlertWithInterfaceName },
196 { CONFIG_OPT__ARCHIVE_DIR, 1, 1, ConfigArchiveDir },
197 { CONFIG_OPT__CHROOT_DIR, 1, 1, ConfigChrootDir },
198 { CONFIG_OPT__CLASSIFICATION, 1, 0, ConfigClassification },
199 { CONFIG_OPT__CLASSIFICATION_FILE, 1, 0, ConfigClassificationFile },
200 { CONFIG_OPT__DAEMON, 0, 1, ConfigDaemon },
201 { CONFIG_OPT__DECODE_DATA_LINK, 0, 1, ConfigDecodeDataLink },
202 { CONFIG_OPT__DUMP_CHARS_ONLY, 0, 1, ConfigDumpCharsOnly },
203 { CONFIG_OPT__DUMP_PAYLOAD, 0, 1, ConfigDumpPayload },
204 { CONFIG_OPT__DUMP_PAYLOAD_VERBOSE, 0, 1, ConfigDumpPayloadVerbose },
205 { CONFIG_OPT__GEN_FILE, 1, 0, ConfigGenFile },
206 { CONFIG_OPT__HOSTNAME, 1, 0, ConfigHostname },
207 { CONFIG_OPT__INTERFACE, 1, 1, ConfigInterface },
208 { CONFIG_OPT__LOG_DIR, 1, 1, ConfigLogDir },
209 { CONFIG_OPT__OBFUSCATE, 0, 1, ConfigObfuscate },
210 { CONFIG_OPT__SIGSUPPRESS,0,0,ConfigSigSuppress},
211 /* XXX We can configure this on the command line - why not in config file ??? */
212 #ifdef NOT_UNTIL_WE_DAEMONIZE_AFTER_READING_CONFFILE
213 { CONFIG_OPT__PID_PATH, 1, 1, ConfigPidPath },
214 #endif
215 { CONFIG_OPT__PROCESS_NEW_RECORDS_ONLY, 0, 1, ConfigProcessNewRecordsOnly },
216 { CONFIG_OPT__QUIET, 0, 1, ConfigQuiet },
217 { CONFIG_OPT__REFERENCE, 1, 0, ConfigReference },
218 { CONFIG_OPT__REFERENCE_FILE, 1, 0, ConfigReferenceFile },
219 { CONFIG_OPT__REFERENCE_NET, 1, 1, ConfigReferenceNet },
220 { CONFIG_OPT__SET_GID, 1, 1, ConfigSetGid },
221 { CONFIG_OPT__SET_UID, 1, 1, ConfigSetUid },
222 { CONFIG_OPT__SID_FILE, 1, 0, ConfigSidFile },
223 { CONFIG_OPT__SHOW_YEAR, 0, 1, ConfigShowYear },
224 { CONFIG_OPT__UMASK, 1, 1, ConfigUmask },
225 { CONFIG_OPT__UTC, 0, 1, ConfigUtc },
226 { CONFIG_OPT__VERBOSE, 0, 1, ConfigVerbose },
227 { CONFIG_OPT__WALDO_FILE, 1, 0, ConfigWaldoFile },
228 #ifdef MPLS
229 { CONFIG_OPT__MAX_MPLS_LABELCHAIN_LEN, 0, 1, ConfigMaxMplsLabelChain },
230 { CONFIG_OPT__MPLS_PAYLOAD_TYPE, 0, 1, ConfigMplsPayloadType },
231 #endif
232 { NULL, 0, 0, NULL } /* Marks end of array */
233 };
234
235 /* Used to determine if a config option has already been configured
236 * Gets zeroed when initially parsing a configuration file, then each
237 * index gets set to 1 as an option is configured. Maps to config_opts */
238 static uint8_t config_opt_configured[sizeof(config_opts) / sizeof(ConfigFunc)];
239
240
241 /* Private function prototypes ************************************************/
242 static void InitVarTables(Barnyard2Config *);
243 static void InitParser(void);
244 #ifdef SUP_IP6
245 static int VarIsIpAddr(vartable_t *, char *);
246 #endif
247 static void ParseConfigFile(Barnyard2Config *, char *);
248 static int ContinuationCheck(char *);
249 static VarEntry * VarDefine(Barnyard2Config *, char *, char *);
250 static char * VarSearch(Barnyard2Config *, char *);
251 static char * ExpandVars(Barnyard2Config *, char *);
252 static VarEntry * VarAlloc(void);
253 static void DeleteVars(VarEntry *);
254 static void TransferOutputConfigs(OutputConfig *, OutputConfig **);
255 static OutputConfig * DupOutputConfig(OutputConfig *);
256 static void RemoveOutputConfigs(OutputConfig **, int);
257
258 static void DisallowCrossTableDuplicateVars(Barnyard2Config *, char *, VarType);
259
260 /****************************************************************************
261 * Function: ParseSnortConf()
262 *
263 * Read the rules file a line at a time and send each rule to the rule parser
264 * This is the first pass of the configuration file. It parses everything
265 * except the rules.
266 *
267 * Arguments: None
268 *
269 * Returns:
270 * Barnyard2Config *
271 * An initialized and configured snort configuration struct.
272 * This struct should be passed on the second pass of the
273 * configuration file to parse the rules.
274 *
275 ***************************************************************************/
ParseBarnyard2Conf(void)276 Barnyard2Config * ParseBarnyard2Conf(void)
277 {
278 Barnyard2Config *bc = Barnyard2ConfNew();
279 VarNode *tmp = cmd_line_var_list;
280
281 file_line = 0;
282 file_name = barnyard2_conf_file ? barnyard2_conf_file : NULL_CONF;
283
284 /* Need to set this for plugin configurations since they're using
285 * lists of callbacks */
286 barnyard2_conf_for_parsing = bc;
287
288 InitParser();
289
290 /* We're not going to parse rules on the first pass */
291 parse_rules = 0;
292
293 InitVarTables(bc);
294
295 /* Add command line defined variables - duplicates will already
296 * have been resolved */
297 while (tmp != NULL)
298 {
299 AddVarToTable(bc, tmp->name, tmp->value);
300 tmp = tmp->next;
301 }
302
303 if ( strcmp(file_name, NULL_CONF) )
304 ParseConfigFile(bc, file_name);
305
306 /* Add command line defined variables - duplicates will already
307 * have been resolved */
308 tmp = cmd_line_var_list;
309 while (tmp != NULL)
310 {
311 AddVarToTable(bc, tmp->name, tmp->value);
312 tmp = tmp->next;
313 }
314
315 /* Make sure this gets set back to NULL when we're done parsing */
316 barnyard2_conf_for_parsing = NULL;
317
318 /* Reset these. The only issue in not reseting would be if we were
319 * parsing a command line again, but do it anyway */
320 file_name = NULL;
321 file_line = 0;
322
323 return bc;
324 }
325
ParseInput(Barnyard2Config * bc,char * args)326 void ParseInput(Barnyard2Config *bc, char *args)
327 {
328 char **toks;
329 int num_toks;
330 char *opts = NULL;
331 InputConfig *config;
332
333 toks = mSplit(args, ":", 2, &num_toks, '\\');
334
335 if (num_toks > 1)
336 opts = toks[1];
337
338 config = (InputConfig *)SnortAlloc(sizeof(InputConfig));
339
340 if (bc->input_configs == NULL)
341 {
342 bc->input_configs = config;
343 }
344 else
345 {
346 InputConfig *tmp = bc->input_configs;
347
348 while (tmp->next != NULL)
349 tmp = tmp->next;
350
351 tmp->next = config;
352 }
353
354 config->keyword = SnortStrdup(toks[0]);
355 if (opts != NULL)
356 config->opts = SnortStrdup(opts);
357
358 /* This could come from parsing the command line */
359 if (file_name != NULL)
360 {
361 config->file_name = SnortStrdup(file_name);
362 config->file_line = file_line;
363 }
364
365 mSplitFree(&toks, num_toks);
366 }
367
ConfigureInputPlugins(Barnyard2Config * bc)368 void ConfigureInputPlugins(Barnyard2Config *bc)
369 {
370 InputConfig *config;
371 char *stored_file_name = file_name;
372 int stored_file_line = file_line;
373
374 barnyard2_conf_for_parsing = bc;
375
376 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Input Plugin\n"););
377
378 for (config = bc->input_configs; config != NULL; config = config->next)
379 {
380 InputConfigFunc func;
381
382 file_name = config->file_name;
383 file_line = config->file_line;
384
385 func = GetInputConfigFunc(config->keyword);
386 if (func == NULL)
387 ParseError("Unknown input plugin: \"%s\"", config->keyword);
388
389 func(config->opts);
390 }
391
392 /* Reset these since we're done with configuring dynamic preprocessors */
393 file_name = stored_file_name;
394 file_line = stored_file_line;
395
396 barnyard2_conf_for_parsing = NULL;
397 }
398
ParseOutput(Barnyard2Config * bc,char * args)399 void ParseOutput(Barnyard2Config *bc, char *args)
400 {
401 char **toks;
402 int num_toks;
403 char *opts = NULL;
404 OutputConfig *config;
405
406 toks = mSplit(args, ":", 2, &num_toks, '\\');
407
408 if (num_toks > 1)
409 opts = toks[1];
410
411 config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
412
413 if (bc->output_configs == NULL)
414 {
415 bc->output_configs = config;
416 }
417 else
418 {
419 OutputConfig *tmp = bc->output_configs;
420
421 while (tmp->next != NULL)
422 tmp = tmp->next;
423
424 tmp->next = config;
425 }
426
427 config->keyword = SnortStrdup(toks[0]);
428 if (opts != NULL)
429 config->opts = SnortStrdup(opts);
430
431 /* This could come from parsing the command line */
432 if (file_name != NULL)
433 {
434 config->file_name = SnortStrdup(file_name);
435 config->file_line = file_line;
436 }
437
438 mSplitFree(&toks, num_toks);
439 }
440
TransferOutputConfigs(OutputConfig * from_list,OutputConfig ** to_list)441 static void TransferOutputConfigs(OutputConfig *from_list, OutputConfig **to_list)
442 {
443 if ((from_list == NULL) || (to_list == NULL))
444 return;
445
446 for (; from_list != NULL; from_list = from_list->next)
447 {
448 if (*to_list == NULL)
449 {
450 *to_list = DupOutputConfig(from_list);
451 }
452 else
453 {
454 OutputConfig *tmp = DupOutputConfig(from_list);
455
456 if (tmp != NULL)
457 {
458 tmp->next = *to_list;
459 *to_list = tmp;
460 }
461 }
462 }
463 }
464
DupOutputConfig(OutputConfig * dupme)465 static OutputConfig * DupOutputConfig(OutputConfig *dupme)
466 {
467 OutputConfig *medup;
468
469 if (dupme == NULL)
470 return NULL;
471
472 medup = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
473
474 if (dupme->keyword != NULL)
475 medup->keyword = SnortStrdup(dupme->keyword);
476
477 if (dupme->opts != NULL)
478 medup->opts = SnortStrdup(dupme->opts);
479
480 if (dupme->file_name != NULL)
481 medup->file_name = SnortStrdup(dupme->file_name);
482
483 medup->file_line = dupme->file_line;
484
485 return medup;
486 }
487
RemoveOutputConfigs(OutputConfig ** head,int remove_flags)488 static void RemoveOutputConfigs(OutputConfig **head, int remove_flags)
489 {
490 OutputConfig *config;
491 OutputConfig *last = NULL;
492
493 if (head == NULL)
494 return;
495
496 config = *head;
497
498 while (config != NULL)
499 {
500 int type_flags = GetOutputTypeFlags(config->keyword);
501
502 if (type_flags & remove_flags)
503 {
504 OutputConfig *tmp = config;
505
506 config = config->next;
507
508 if (last == NULL)
509 *head = config;
510 else
511 last->next = config;
512
513 free(tmp->keyword);
514
515 if (tmp->opts != NULL)
516 free(tmp->opts);
517
518 if (tmp->file_name != NULL)
519 free(tmp->file_name);
520
521 free(tmp);
522 }
523 else
524 {
525 last = config;
526 config = config->next;
527 }
528 }
529 }
530
ResolveOutputPlugins(Barnyard2Config * cmd_line,Barnyard2Config * config_file)531 void ResolveOutputPlugins(Barnyard2Config *cmd_line, Barnyard2Config *config_file)
532 {
533 int cmd_line_type_flags = 0;
534
535 if (cmd_line == NULL)
536 return;
537
538 /* Command line overrides configuration file output */
539 if (cmd_line->output_configs != NULL)
540 {
541 OutputConfig *config = cmd_line->output_configs;
542
543 for (; config != NULL; config = config->next)
544 {
545 int type_flags = GetOutputTypeFlags(config->keyword);
546
547 cmd_line_type_flags |= type_flags;
548
549 if (config_file != NULL)
550 {
551 RemoveOutputConfigs(&config_file->output_configs, type_flags);
552 }
553 }
554
555 /* Put what's in the command line output into the config file output */
556 if (config_file != NULL)
557 TransferOutputConfigs(cmd_line->output_configs, &config_file->output_configs);
558 }
559
560 /* Don't try to configure defaults if running in test mode */
561 if (!BcTestMode())
562 {
563 if (config_file == NULL)
564 {
565 if (!(cmd_line_type_flags & OUTPUT_TYPE__LOG))
566 ParseOutput(cmd_line, "log_tcpdump");
567
568 if (!(cmd_line_type_flags & OUTPUT_TYPE__ALERT))
569 ParseOutput(cmd_line, "alert_full");
570 }
571 else
572 {
573 int config_file_type_flags = 0;
574 OutputConfig *config = config_file->output_configs;
575
576 for (; config != NULL; config = config->next)
577 config_file_type_flags |= GetOutputTypeFlags(config->keyword);
578
579 // if (!(config_file_type_flags & OUTPUT_TYPE__LOG))
580 // ParseOutput(config_file, "log_tcpdump");
581
582 // if (!(config_file_type_flags & OUTPUT_TYPE__ALERT))
583 // ParseOutput(config_file, "alert_full");
584 }
585 }
586 }
587
ConfigureOutputPlugins(Barnyard2Config * bc)588 void ConfigureOutputPlugins(Barnyard2Config *bc)
589 {
590 OutputConfig *config;
591 char *stored_file_name = file_name;
592 int stored_file_line = file_line;
593
594 barnyard2_conf_for_parsing = bc;
595
596 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n"););
597
598 for (config = bc->output_configs; config != NULL; config = config->next)
599 {
600 OutputConfigFunc func;
601
602 file_name = config->file_name;
603 file_line = config->file_line;
604
605 func = GetOutputConfigFunc(config->keyword);
606 if (func == NULL)
607 ParseError("Unknown output plugin: \"%s\"", config->keyword);
608
609 func(config->opts);
610 }
611
612 /* Reset these since we're done with configuring dynamic preprocessors */
613 file_name = stored_file_name;
614 file_line = stored_file_line;
615
616 barnyard2_conf_for_parsing = NULL;
617 }
618
619 /****************************************************************************
620 *
621 * Function: VarAlloc()
622 *
623 * Purpose: allocates memory for a variable
624 *
625 * Arguments: none
626 *
627 * Returns: pointer to new VarEntry
628 *
629 ***************************************************************************/
VarAlloc()630 VarEntry *VarAlloc()
631 {
632 VarEntry *new;
633
634 new = (VarEntry *)SnortAlloc(sizeof(VarEntry));
635
636 return(new);
637 }
638
639 #ifdef SUP_IP6
640 /****************************************************************************
641 *
642 * Function: VarIsIpAddr(char *, char *)
643 *
644 * Purpose: Checks if a var is an IP address. Necessary since moving forward
645 * we want all IP addresses handled by the IP variable table.
646 * If a list is given, this checks each value.
647 *
648 * Arguments: value => the string to check
649 *
650 * Returns: 1 if IP address, 0 otherwise
651 *
652 ***************************************************************************/
VarIsIpAddr(vartable_t * ip_vartable,char * value)653 static int VarIsIpAddr(vartable_t *ip_vartable, char *value)
654 {
655 char *tmp;
656
657 /* empty list, consider this an IP address */
658 if ((*value == '[') && (*(value+1) == ']'))
659 return 1;
660
661 while(*value == '!' || *value == '[') value++;
662
663 /* Check for dotted-quad */
664 if( isdigit((int)*value) &&
665 ((tmp = strchr(value, (int)'.')) != NULL) &&
666 ((tmp = strchr(tmp+1, (int)'.')) != NULL) &&
667 (strchr(tmp+1, (int)'.') != NULL))
668 return 1;
669
670 /* IPv4 with a mask, and fewer than 4 fields */
671 else if( isdigit((int)*value) &&
672 (strchr(value+1, (int)':') == NULL) &&
673 ((tmp = strchr(value+1, (int)'/')) != NULL) &&
674 isdigit((int)(*(tmp+1))) )
675 return 1;
676
677 /* IPv6 */
678 else if((tmp = strchr(value, (int)':')) != NULL)
679 {
680 char *tmp2;
681
682 if((tmp2 = strchr(tmp+1, (int)':')) == NULL)
683 return 0;
684
685 for(tmp++; tmp < tmp2; tmp++)
686 if(!isxdigit((int)*tmp))
687 return 0;
688
689 return 1;
690 }
691
692 /* Check if it's a variable containing an IP */
693 else if(sfvt_lookup_var(ip_vartable, value+1) || sfvt_lookup_var(ip_vartable, value))
694 return 1;
695
696 return 0;
697 }
698
699 /****************************************************************************
700 *
701 * Function: CheckBrackets(char *)
702 *
703 * Purpose: Check that the brackets match up in a string that
704 * represents a list.
705 *
706 * Arguments: value => the string to check
707 *
708 * Returns: 1 if the brackets match correctly, 0 otherwise
709 *
710 ***************************************************************************/
CheckBrackets(char * value)711 static int CheckBrackets(char *value)
712 {
713 int num_brackets = 0;
714
715 while (*value == '!')
716 value++;
717
718 if ((value[0] != '[') || value[strlen(value)-1] != ']')
719 {
720 /* List does not begin or end with a bracket. */
721 return 0;
722 }
723
724 while ((*value != '\0') && (num_brackets >= 0))
725 {
726 if (*value == '[')
727 num_brackets++;
728 else if (*value == ']')
729 num_brackets--;
730 value++;
731 }
732 if (num_brackets != 0)
733 {
734 /* Mismatched brackets */
735 return 0;
736 }
737
738 return 1;
739 }
740
741 /****************************************************************************
742 *
743 * Function: VarIsIpList(vartable_t *, char*)
744 *
745 * Purpose: Checks if a var is a list of IP addresses.
746 *
747 * Arguments: value => the string to check
748 *
749 * Returns: 1 if each item is an IP address, 0 otherwise
750 *
751 ***************************************************************************/
VarIsIpList(vartable_t * ip_vartable,char * value)752 static int VarIsIpList(vartable_t *ip_vartable, char *value)
753 {
754 char *copy, *item;
755 int item_is_ip = 1;
756
757 copy = SnortStrdup((const char*)value);
758
759 /* Ensure that the brackets are correct. */
760 if (strchr((const char*)copy, ','))
761 {
762 /* This is a list! */
763 if (CheckBrackets(copy) == 0)
764 {
765 free(copy);
766 return 0;
767 }
768 }
769
770 /* There's no need to worry about the list structure here.
771 * We just strip out the IP delimiters and process each one. */
772 item = strtok(copy, "[],!");
773 while ((item != NULL) && item_is_ip)
774 {
775 item_is_ip = VarIsIpAddr(ip_vartable, item);
776 item = strtok(NULL, "[],!");
777 }
778
779 free(copy);
780 return item_is_ip;
781 }
782 #endif
783
784 /****************************************************************************
785 *
786 * Function: DisallowCrossTableDuplicateVars(char *, int)
787 *
788 * Purpose: FatalErrors if the a variable name is redefined across variable
789 * types. Enforcing this mutual exclusion prevents the
790 * catatrophe where the variable lookup fall-through (see VarSearch)
791 * finds an unintended variable from the wrong table. Note: VarSearch
792 * is only necessary for ExpandVars.
793 *
794 * Arguments: name => The name of the variable
795 * var_type => The type of the variable that is about to be defined.
796 * The corresponding variable table will not be searched.
797 *
798 * Returns: void function
799 *
800 ***************************************************************************/
DisallowCrossTableDuplicateVars(Barnyard2Config * bc,char * name,VarType var_type)801 static void DisallowCrossTableDuplicateVars(Barnyard2Config *bc, char *name, VarType var_type)
802 {
803 #ifdef SUP_IP6
804 VarEntry *var_table = bc->var_table;
805 vartable_t *ip_vartable = bc->ip_vartable;
806 VarEntry *p = var_table;
807 #endif
808
809
810 switch (var_type)
811 {
812 case VAR_TYPE__DEFAULT:
813 if(
814 #ifdef SUP_IP6
815 sfvt_lookup_var(ip_vartable, name) ||
816 #endif
817 /* This 0 is for the case that neither IPv6
818 * support or Portlists is compiled in. Quiets a warning. */
819 0)
820 {
821 ParseError("Can not redefine variable name %s to be of type "
822 "'var'. Use a different name.", name);
823 }
824 break;
825
826 #ifdef SUP_IP6
827 case VAR_TYPE__IPVAR:
828 if (var_table != NULL)
829 {
830 do
831 {
832 if(strcasecmp(p->name, name) == 0)
833 {
834 ParseError("Can not redefine variable name %s to be of "
835 "type 'ipvar'. Use a different name.", name);
836 }
837
838 p = p->next;
839 } while(p != var_table);
840 }
841 #endif /* SUP_IP6 */
842
843 default:
844 /* Invalid function usage */
845 break;
846 }
847 }
848
849 /****************************************************************************
850 *
851 * Function: VarDefine(char *, char *)
852 *
853 * Purpose: define the contents of a variable
854 *
855 * Arguments: name => the name of the variable
856 * value => the contents of the variable
857 *
858 * Returns: void function
859 *
860 ***************************************************************************/
VarDefine(Barnyard2Config * bc,char * name,char * value)861 VarEntry * VarDefine(Barnyard2Config *bc, char *name, char *value)
862 {
863 VarEntry *var_table = bc->var_table;
864 #ifdef SUP_IP6
865 vartable_t *ip_vartable = bc->ip_vartable;
866 #endif
867 VarEntry *p;
868 //int vlen,n;
869 //char *s;
870
871 if(value == NULL)
872 {
873 ParseError("Bad value in variable definition! Make sure you don't "
874 "have a \"$\" in the var name.");
875 }
876
877 #ifdef SUP_IP6
878 if(VarIsIpList(ip_vartable, value))
879 {
880 SFIP_RET ret;
881
882 if (ip_vartable == NULL)
883 return NULL;
884
885 /* Verify a variable by this name is not already used as either a
886 * portvar or regular var. Enforcing this mutual exclusion prevents the
887 * catatrophe where the variable lookup fall-through (see VarSearch)
888 * finds an unintended variable from the wrong table. Note: VarSearch
889 * is only necessary for ExpandVars. */
890 DisallowCrossTableDuplicateVars(bc, name, VAR_TYPE__IPVAR);
891
892 if((ret = sfvt_define(ip_vartable, name, value)) != SFIP_SUCCESS)
893 {
894 switch(ret) {
895 case SFIP_ARG_ERR:
896 ParseError("The following is not allowed: %s.", value);
897 break;
898
899 case SFIP_DUPLICATE:
900 ParseMessage("Var '%s' redefined.", name);
901 break;
902
903 case SFIP_CONFLICT:
904 ParseError("Negated IP ranges that are more general than "
905 "non-negated ranges are not allowed. Consider "
906 "inverting the logic in %s.", name);
907 break;
908
909 case SFIP_NOT_ANY:
910 ParseError("!any is not allowed in %s.", name);
911 break;
912
913 default:
914 ParseError("Failed to parse the IP address: %s.", value);
915 }
916 }
917 return NULL;
918 }
919 /* Check if this is a variable that stores an IP */
920 else if(*value == '$')
921 {
922 sfip_var_t *var;
923 if((var = sfvt_lookup_var(ip_vartable, value)) != NULL)
924 {
925 sfvt_define(ip_vartable, name, value);
926 return NULL;
927 }
928 }
929
930 #endif
931
932 DisallowCrossTableDuplicateVars(bc, name, VAR_TYPE__DEFAULT);
933
934 if (var_table == NULL)
935 {
936 p = VarAlloc();
937 p->name = SnortStrdup(name);
938 p->value = SnortStrdup(value);
939
940 p->prev = p;
941 p->next = p;
942
943 bc->var_table = p;
944
945 return p;
946 }
947
948 /* See if an existing variable is being redefined */
949 p = var_table;
950
951 do
952 {
953 if (strcasecmp(p->name, name) == 0)
954 {
955 if (p->value != NULL)
956 free(p->value);
957
958 p->value = SnortStrdup(value);
959 LogMessage("Var '%s' redefined\n", p->name);
960 return p;
961 }
962
963 p = p->next;
964
965 } while (p != var_table); /* List is circular */
966
967 p = VarAlloc();
968 p->name = SnortStrdup(name);
969 p->value = SnortStrdup(value);
970 p->prev = var_table;
971 p->next = var_table->next;
972 p->next->prev = p;
973 var_table->next = p;
974
975 return p;
976 }
977
DeleteVars(VarEntry * var_table)978 static void DeleteVars(VarEntry *var_table)
979 {
980 VarEntry *q, *p = var_table;
981
982 while (p)
983 {
984 q = p->next;
985 if (p->name)
986 free(p->name);
987 if (p->value)
988 free(p->value);
989 free(p);
990 p = q;
991 if (p == var_table)
992 break; /* Grumble, it's a friggin circular list */
993 }
994 }
995
996 /****************************************************************************
997 *
998 * Function: VarGet(char *)
999 *
1000 * Purpose: get the contents of a variable
1001 *
1002 * Arguments: name => the name of the variable
1003 *
1004 * Returns: char * to contents of variable or FatalErrors on an
1005 * undefined variable name
1006 *
1007 ***************************************************************************/
VarGet(char * name)1008 char *VarGet(char *name)
1009 {
1010 Barnyard2Config *bc = barnyard2_conf_for_parsing;
1011 VarEntry *var_table;
1012 #ifdef SUP_IP6
1013 vartable_t *ip_vartable;
1014 sfip_var_t *var;
1015 #else
1016 VarEntry *p = NULL;
1017 char *ret = NULL;
1018 #endif
1019
1020 if (bc == NULL)
1021 return NULL;
1022
1023 var_table = bc->var_table;
1024
1025 #ifdef SUP_IP6
1026 // XXX-IPv6 This function should never be used if IP6 support is enabled!
1027 // Infact it won't presently even work for IP variables since the raw ASCII
1028 // value is never stored, and is never meant to be used.
1029 ip_vartable = bc->ip_vartable;
1030
1031 if((var = sfvt_lookup_var(ip_vartable, name)) == NULL) {
1032 /* Do the old style lookup since it wasn't found in
1033 * the variable table */
1034 if(var_table != NULL)
1035 {
1036 VarEntry *p = var_table;
1037 do
1038 {
1039 if(strcasecmp(p->name, name) == 0)
1040 return p->value;
1041 p = p->next;
1042 } while(p != var_table);
1043 }
1044
1045 ParseError("Undefined variable name: %s.", name);
1046 }
1047
1048 return name;
1049
1050 #else
1051
1052 if (var_table != NULL)
1053 {
1054 p = var_table;
1055
1056 do
1057 {
1058 if (strcasecmp(p->name, name) == 0)
1059 {
1060 ret = p->value;
1061 break;
1062 }
1063
1064 p = p->next;
1065
1066 } while (p != var_table);
1067 }
1068
1069 if (ret == NULL)
1070 ParseError("Undefined variable name: %s.", name);
1071
1072 return ret;
1073 #endif
1074 }
1075
1076 /****************************************************************************
1077 *
1078 * Function: ExpandVars()
1079 *
1080 * Purpose: expand all variables in a string
1081 *
1082 * Arguments:
1083 * Barnyard2Config *
1084 * The snort config that has the vartables.
1085 * char *
1086 * The name of the variable.
1087 *
1088 * Returns:
1089 * char *
1090 * The expanded string. Note that the string is returned in a
1091 * static variable and most likely needs to be string dup'ed.
1092 *
1093 ***************************************************************************/
ExpandVars(Barnyard2Config * bc,char * string)1094 static char * ExpandVars(Barnyard2Config *bc, char *string)
1095 {
1096 static char estring[ PARSERULE_SIZE ];
1097
1098 char rawvarname[128], varname[128], varaux[128], varbuffer[128];
1099 char varmodifier, *varcontents;
1100 int varname_completed, c, i, j, iv, jv, l_string, name_only;
1101 int quote_toggle = 0;
1102
1103 if(!string || !*string || !strchr(string, '$'))
1104 return(string);
1105
1106 memset((char *) estring, 0, PARSERULE_SIZE); /* bzero() deprecated, replaced by memset() */
1107
1108 i = j = 0;
1109 l_string = strlen(string);
1110 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string););
1111
1112 while(i < l_string && j < (int)sizeof(estring) - 1)
1113 {
1114 c = string[i++];
1115
1116 if(c == '"')
1117 {
1118 /* added checks to make sure that we are inside a quoted string
1119 */
1120 quote_toggle ^= 1;
1121 }
1122
1123 if(c == '$' && !quote_toggle)
1124 {
1125 memset((char *) rawvarname, 0, sizeof(rawvarname)); /* bzero() deprecated, replaced by memset() */
1126 varname_completed = 0;
1127 name_only = 1;
1128 iv = i;
1129 jv = 0;
1130
1131 if(string[i] == '(')
1132 {
1133 name_only = 0;
1134 iv = i + 1;
1135 }
1136
1137 while(!varname_completed
1138 && iv < l_string
1139 && jv < (int)sizeof(rawvarname) - 1)
1140 {
1141 c = string[iv++];
1142
1143 if((name_only && !(isalnum(c) || c == '_'))
1144 || (!name_only && c == ')'))
1145 {
1146 varname_completed = 1;
1147
1148 if(name_only)
1149 iv--;
1150 }
1151 else
1152 {
1153 rawvarname[jv++] = (char)c;
1154 }
1155 }
1156
1157 if(varname_completed || iv == l_string)
1158 {
1159 char *p;
1160
1161 i = iv;
1162
1163 varcontents = NULL;
1164
1165 memset((char *) varname, 0, sizeof(varname)); /* bzero() deprecated, replaced by memset() */
1166 memset((char *) varaux, 0, sizeof(varaux)); /* bzero() deprecated, replaced by memset() */
1167 varmodifier = ' ';
1168
1169 p = strchr(rawvarname, ':');
1170 if (p)
1171 {
1172 SnortStrncpy(varname, rawvarname, p - rawvarname);
1173
1174 if(strlen(p) >= 2)
1175 {
1176 varmodifier = *(p + 1);
1177 SnortStrncpy(varaux, p + 2, sizeof(varaux));
1178 }
1179 }
1180 else
1181 SnortStrncpy(varname, rawvarname, sizeof(varname));
1182
1183 memset((char *) varbuffer, 0, sizeof(varbuffer)); /* bzero() deprecated, replaced by memset() */
1184
1185 varcontents = VarSearch(bc, varname);
1186
1187 switch(varmodifier)
1188 {
1189 case '-':
1190 if(!varcontents || !strlen(varcontents))
1191 varcontents = varaux;
1192 break;
1193
1194 case '?':
1195 if(!varcontents || !strlen(varcontents))
1196 {
1197 ErrorMessage("%s(%d): ", file_name, file_line);
1198
1199 if(strlen(varaux))
1200 ParseError("%s", varaux);
1201 else
1202 ParseError("Undefined variable \"%s\".", varname);
1203 }
1204 break;
1205 }
1206
1207 /* If variable not defined now, we're toast */
1208 if(!varcontents || !strlen(varcontents))
1209 ParseError("Undefined variable name: %s.", varname);
1210
1211 if(varcontents)
1212 {
1213 int l_varcontents = strlen(varcontents);
1214
1215 iv = 0;
1216
1217 while(iv < l_varcontents && j < (int)sizeof(estring) - 1)
1218 estring[j++] = varcontents[iv++];
1219 }
1220 }
1221 else
1222 {
1223 estring[j++] = '$';
1224 }
1225 }
1226 else
1227 {
1228 estring[j++] = (char)c;
1229 }
1230 }
1231
1232 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring););
1233
1234 return estring;
1235 }
1236
ProcessFileOption(Barnyard2Config * bc,const char * filespec)1237 char * ProcessFileOption(Barnyard2Config *bc, const char *filespec)
1238 {
1239 char *filename = NULL;
1240 char buffer[STD_BUF];
1241
1242 if (bc == NULL)
1243 bc = barnyard2_conf;
1244
1245 if(filespec == NULL)
1246 {
1247 FatalError("no arguement in this file option, remove extra ':' at the end of the alert option\n");
1248 }
1249
1250 /* look for ".." in the string and complain and exit if it is found */
1251 if(strstr(filespec, "..") != NULL)
1252 {
1253 FatalError("file definition contains \"..\". Do not do that!\n");
1254 }
1255
1256 if(filespec[0] == '/')
1257 {
1258 /* absolute filespecs are saved as is */
1259 filename = SnortStrdup(filespec);
1260 }
1261 else
1262 {
1263 /* relative filespec is considered relative to the log directory */
1264 /* or /var/log if the log directory has not been set */
1265 /* Make sure this function isn't called before log dir is set */
1266 if ((bc != NULL) && (bc->log_dir != NULL))
1267 {
1268 strlcpy(buffer, barnyard2_conf->log_dir, STD_BUF);
1269 }
1270 else
1271 {
1272 strlcpy(buffer, "/var/log/barnyard2", STD_BUF);
1273 }
1274
1275 strlcat(buffer, "/", STD_BUF - strlen(buffer));
1276 strlcat(buffer, filespec, STD_BUF - strlen(buffer));
1277 buffer[sizeof(buffer) - 1] = '\0';
1278 filename = SnortStrdup(buffer);
1279 }
1280
1281 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ProcessFileOption: %s\n", filename););
1282
1283 return filename;
1284 }
1285
ParseConfig(Barnyard2Config * bc,char * args)1286 static void ParseConfig(Barnyard2Config *bc, char *args)
1287 {
1288 char **toks;
1289 int num_toks;
1290 char *opts = NULL;
1291 int i;
1292
1293 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n"););
1294
1295 toks = mSplit(args, ":", 2, &num_toks, 0);
1296
1297 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Opt: %s\n", toks[0]););
1298
1299 if (num_toks > 1)
1300 {
1301
1302 opts = SnortStrdup(toks[1]);
1303 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Args: %s\n", opts););
1304 }
1305
1306 for (i = 0; config_opts[i].name != NULL; i++)
1307 {
1308 if (strcasecmp(toks[0], config_opts[i].name) == 0)
1309 {
1310 if (config_opts[i].only_once && config_opt_configured[i])
1311 {
1312 /* Configured already and set to only configure once
1313 * This array is reset for each policy read in so this is
1314 * on a per policy basis */
1315 ParseError("Config option \"%s\" can only be "
1316 "configured once.", toks[0]);
1317 }
1318
1319 if (config_opts[i].args_required && (opts == NULL))
1320 {
1321 /* Need arguments and there are none */
1322 ParseError("Config option \"%s\" requires arguments.", toks[0]);
1323 }
1324
1325 config_opts[i].parse_func(bc, opts);
1326 config_opt_configured[i] = 1;
1327 break;
1328 }
1329 }
1330
1331 if (config_opts[i].name == NULL)
1332 {
1333 /* Didn't find a matching config option */
1334 ParseError("Unknown config directive: %s.", toks[0]);
1335 }
1336
1337 mSplitFree(&toks, num_toks);
1338
1339 if(opts)
1340 {
1341 free(opts);
1342 }
1343
1344 }
1345
1346 /*
1347 * Same as VarGet - but this does not Fatal out if a var is not found
1348 */
VarSearch(Barnyard2Config * bc,char * name)1349 static char * VarSearch(Barnyard2Config *bc, char *name)
1350 {
1351 VarEntry *var_table = bc->var_table;
1352 #ifdef SUP_IP6
1353 vartable_t *ip_vartable = bc->ip_vartable;
1354 #endif
1355
1356 #ifdef SUP_IP6
1357 if(!sfvt_lookup_var(ip_vartable, name))
1358 {
1359 #endif
1360
1361 if(var_table != NULL)
1362 {
1363 VarEntry *p = var_table;
1364 do
1365 {
1366 if(strcasecmp(p->name, name) == 0)
1367 return p->value;
1368 p = p->next;
1369 } while(p != var_table);
1370 }
1371
1372 return NULL;
1373
1374 #ifdef SUP_IP6
1375 }
1376 #endif
1377
1378 return name;
1379 }
1380
ParserCleanup(void)1381 void ParserCleanup(void)
1382 {
1383 }
1384
InitVarTables(Barnyard2Config * bc)1385 static void InitVarTables(Barnyard2Config *bc)
1386 {
1387 if (bc == NULL)
1388 return;
1389
1390 if (bc->var_table != NULL)
1391 DeleteVars(bc->var_table);
1392
1393 #ifdef SUP_IP6
1394 if (bc->ip_vartable != NULL)
1395 sfvt_free_table(bc->ip_vartable);
1396 bc->ip_vartable = sfvt_alloc_table();
1397 #endif
1398 }
1399
InitParser(void)1400 static void InitParser(void)
1401 {
1402 /* This is for determining if a config option has already been
1403 * configured. Most can only be configured once */
1404 memset(config_opt_configured, 0, sizeof(config_opt_configured));
1405 }
1406
ParseConfigFile(Barnyard2Config * bc,char * fname)1407 static void ParseConfigFile(Barnyard2Config *bc, char *fname)
1408 {
1409 /* Used for line continuation */
1410 int continuation = 0;
1411 char *saved_line = NULL;
1412 char *new_line = NULL;
1413 char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1);
1414 FILE *fp = fopen(fname, "r");
1415
1416 /* open the rules file */
1417 if (fp == NULL)
1418 {
1419 FatalError("Unable to open config file \"%s\": %s.\n",
1420 fname, strerror(errno));
1421 }
1422
1423 /* loop thru each file line and send it to the rule parser */
1424 while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL)
1425 {
1426 /* buffer indexing pointer */
1427 char *index = buf;
1428
1429 /* Increment the line counter so the error messages know which
1430 * line to bitch about */
1431 file_line++;
1432
1433 /* fgets always appends a null, so doing a strlen should be safe */
1434 if ((strlen(buf) + 1) == MAX_LINE_LENGTH)
1435 {
1436 ParseError("Line greater than or equal to %u characters which is "
1437 "more than the parser is willing to handle. Try "
1438 "splitting it up on multiple lines if possible.",
1439 MAX_LINE_LENGTH);
1440 }
1441
1442 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n",
1443 fname, file_line, buf););
1444
1445 /* advance through any whitespace at the beginning of the line */
1446 while (isspace((int)*index))
1447 index++;
1448
1449 /* If it's an empty line or starts with a comment character */
1450 if ((strlen(index) == 0) || (*index == '#') || (*index == ';'))
1451 continue;
1452
1453 if (continuation)
1454 {
1455 int new_line_len = strlen(saved_line) + strlen(index) + 1;
1456
1457 if (new_line_len >= PARSERULE_SIZE)
1458 {
1459 ParseError("Rule greater than or equal to %u characters which "
1460 "is more than the parser is willing to handle. "
1461 "Submit a bug to bugs@snort.org if you legitimately "
1462 "feel like your rule or keyword configuration needs "
1463 "more than this amount of space.", PARSERULE_SIZE);
1464 }
1465
1466 new_line = (char *)SnortAlloc(new_line_len);
1467 snprintf(new_line, new_line_len, "%s%s", saved_line, index);
1468
1469 free(saved_line);
1470 saved_line = NULL;
1471 index = new_line;
1472
1473 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n",
1474 new_line););
1475 }
1476
1477 /* check for a '\' continuation character at the end of the line
1478 * if it's there we need to get the next line in the file */
1479 if (ContinuationCheck(index) == 0)
1480 {
1481 char **toks;
1482 int num_toks;
1483 char *keyword;
1484 char *args;
1485 int i;
1486
1487 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
1488 "[*] Processing keyword: %s\n", index););
1489
1490 /* Get the keyword and args */
1491 toks = mSplit(index, " \t", 2, &num_toks, 0);
1492 if (num_toks != 2)
1493 ParseError("Invalid configuration line: %s", index);
1494
1495 keyword = SnortStrdup(ExpandVars(bc, toks[0]));
1496 args = toks[1];
1497
1498 for (i = 0; barnyard2_conf_keywords[i].name != NULL; i++)
1499 {
1500 if (strcasecmp(keyword, barnyard2_conf_keywords[i].name) == 0)
1501 {
1502 if (barnyard2_conf_keywords[i].expand_vars)
1503 args = SnortStrdup(ExpandVars(bc, toks[1]));
1504
1505 barnyard2_conf_keywords[i].parse_func(bc, args);
1506
1507 break;
1508 }
1509 }
1510
1511 if (args != toks[1])
1512 free(args);
1513
1514 free(keyword);
1515 mSplitFree(&toks, num_toks);
1516
1517 if(new_line != NULL)
1518 {
1519 free(new_line);
1520 new_line = NULL;
1521 continuation = 0;
1522 }
1523 }
1524 else
1525 {
1526 /* save the current line */
1527 saved_line = SnortStrdup(index);
1528
1529 /* current line was a continuation itself... */
1530 if (new_line != NULL)
1531 {
1532 free(new_line);
1533 new_line = NULL;
1534 }
1535
1536 /* set the flag to let us know the next line is
1537 * a continuation line */
1538 continuation = 1;
1539 }
1540 }
1541
1542 fclose(fp);
1543 free(buf);
1544 }
1545
ContinuationCheck(char * rule)1546 static int ContinuationCheck(char *rule)
1547 {
1548 char *idx; /* indexing var for moving around on the string */
1549
1550 idx = rule + strlen(rule) - 1;
1551
1552 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n",
1553 *idx););
1554
1555 while(isspace((int)*idx))
1556 {
1557 idx--;
1558 }
1559
1560 if(*idx == '\\')
1561 {
1562 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, "
1563 "clearing char and returning 1\n"););
1564
1565 /* clear the '\' so there isn't a problem on the appended string */
1566 *idx = '\x0';
1567 return 1;
1568 }
1569
1570 return 0;
1571 }
1572
1573
ConfigAlertOnEachPacketInStream(Barnyard2Config * bc,char * args)1574 void ConfigAlertOnEachPacketInStream(Barnyard2Config *bc, char *args)
1575 {
1576 if (bc == NULL)
1577 return;
1578
1579 LogMessage("INFO: Alerting on each packet associated with an event: is now enabled by default. \n"
1580 " use: command line argument --disable-alert-on-each-packet-in-stream or \n"
1581 " configure file argument disable-alert-on-each-packet-in-stream to disable the feature \n");
1582
1583 return;
1584 }
1585
1586
ConfigSetEventCacheSize(Barnyard2Config * bc,char * args)1587 void ConfigSetEventCacheSize(Barnyard2Config *bc, char *args)
1588 {
1589 if( (bc == NULL) ||
1590 (args == NULL))
1591 {
1592 return;
1593 }
1594
1595 bc->event_cache_size = strtoul(args,NULL,10);
1596 return;
1597 }
1598
ConfigDisableAlertOnEachPacketInStream(Barnyard2Config * bc,char * args)1599 void ConfigDisableAlertOnEachPacketInStream(Barnyard2Config *bc, char *args)
1600 {
1601 if (bc == NULL)
1602 return;
1603
1604 bc->alert_on_each_packet_in_stream_flag = 0;
1605 }
1606
ConfigArchiveDir(Barnyard2Config * bc,char * args)1607 void ConfigArchiveDir(Barnyard2Config *bc, char *args)
1608 {
1609 if ((args == NULL) || (bc == NULL) || (bc->archive_dir != NULL))
1610 return;
1611
1612 bc->archive_dir = SnortStrdup(args);
1613 }
1614
ConfigAlertWithInterfaceName(Barnyard2Config * bc,char * args)1615 void ConfigAlertWithInterfaceName(Barnyard2Config *bc, char *args)
1616 {
1617 if (bc == NULL)
1618 return;
1619
1620 bc->output_flags |= OUTPUT_FLAG__ALERT_IFACE;
1621 }
1622
ConfigChrootDir(Barnyard2Config * bc,char * args)1623 void ConfigChrootDir(Barnyard2Config *bc, char *args)
1624 {
1625 #ifdef WIN32
1626 ParseError("Setting the chroot directory is not supported in "
1627 "the WIN32 port of snort!");
1628 #else
1629 if ((args == NULL) || (bc == NULL) || (bc->chroot_dir != NULL))
1630 return;
1631
1632 bc->chroot_dir = SnortStrdup(args);
1633 #endif
1634 }
1635
ConfigClassification(Barnyard2Config * bc,char * args)1636 void ConfigClassification(Barnyard2Config *bc, char *args)
1637 {
1638 char **toks;
1639 int num_toks;
1640 char *endptr;
1641 ClassType *new_node, *current;
1642 int max_id = 0;
1643
1644 if ((args == NULL) || (bc == NULL))
1645 return;
1646
1647 toks = mSplit(args, ",", 0, &num_toks, '\\');
1648 if (num_toks != 3)
1649 ParseError("Invalid classification config: %s.", args);
1650
1651 /* create the new node */
1652 new_node = (ClassType *)SnortAlloc(sizeof(ClassType));
1653
1654 new_node->type = SnortStrdup(toks[0]);
1655 new_node->name = SnortStrdup(toks[1]);
1656
1657 new_node->priority = strtol(toks[2], &endptr, 0);
1658 if ((errno == ERANGE) || (*endptr != '\0') || (new_node->priority <= 0))
1659 {
1660 ParseError("Invalid argument for classification priority "
1661 "configuration: %s. Must be a positive integer.", toks[2]);
1662 }
1663
1664 current = bc->classifications;
1665 while (current != NULL)
1666 {
1667 /* dup check */
1668 if (strcasecmp(current->type, new_node->type) == 0)
1669 {
1670 LogMessage("%s(%d): Duplicate classification \"%s\""
1671 "found, ignoring this line\n", file_name, file_line,
1672 new_node->type);
1673 break;
1674 }
1675
1676 if (current->id > max_id)
1677 max_id = current->id;
1678
1679 current = current->next;
1680 }
1681
1682 /* Got a dup */
1683 if (current != NULL)
1684 {
1685 free(new_node->name);
1686 free(new_node->type);
1687 free(new_node);
1688 mSplitFree(&toks, num_toks);
1689 return;
1690 }
1691
1692 /* insert node */
1693 new_node->id = max_id + 1;
1694 new_node->next = bc->classifications;
1695 bc->classifications = new_node;
1696
1697 mSplitFree(&toks, num_toks);
1698 }
1699
ConfigClassificationFile(Barnyard2Config * bc,char * args)1700 void ConfigClassificationFile(Barnyard2Config *bc, char *args)
1701 {
1702 if ((args == NULL) || (bc == NULL) )
1703 return;
1704
1705 bc->class_file = strndup(args,strlen(args));
1706
1707 ReadClassificationFile(bc);
1708 }
1709
ConfigCreatePidFile(Barnyard2Config * bc,char * args)1710 void ConfigCreatePidFile(Barnyard2Config *bc, char *args)
1711 {
1712 if (bc == NULL)
1713 return;
1714
1715 bc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
1716 }
1717
ConfigDaemon(Barnyard2Config * bc,char * args)1718 void ConfigDaemon(Barnyard2Config *bc, char *args)
1719 {
1720 #ifdef WIN32
1721 ParseError("Setting the Daemon mode is not supported in the "
1722 "WIN32 port of barnyard2! Use 'barnyard2 /SERVICE ...' instead.");
1723 #else
1724 if (bc == NULL)
1725 return;
1726
1727 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Daemon mode flag set\n"););
1728 bc->run_flags |= RUN_FLAG__DAEMON;
1729 bc->logging_flags |= LOGGING_FLAG__QUIET;
1730 #endif
1731 }
1732
ConfigDecodeDataLink(Barnyard2Config * bc,char * args)1733 void ConfigDecodeDataLink(Barnyard2Config *bc, char *args)
1734 {
1735 if (bc == NULL)
1736 return;
1737
1738 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Decode DLL set\n"););
1739 bc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK;
1740 }
1741
ConfigDumpCharsOnly(Barnyard2Config * bc,char * args)1742 void ConfigDumpCharsOnly(Barnyard2Config *bc, char *args)
1743 {
1744 if (bc == NULL)
1745 return;
1746
1747 /* dump the application layer as text only */
1748 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Character payload dump set\n"););
1749 bc->output_flags |= OUTPUT_FLAG__CHAR_DATA;
1750 }
1751
ConfigDumpPayload(Barnyard2Config * bc,char * args)1752 void ConfigDumpPayload(Barnyard2Config *bc, char *args)
1753 {
1754 if (bc == NULL)
1755 return;
1756
1757 /* dump the application layer */
1758 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Payload dump set\n"););
1759 bc->output_flags |= OUTPUT_FLAG__APP_DATA;
1760 }
1761
ConfigDumpPayloadVerbose(Barnyard2Config * bc,char * args)1762 void ConfigDumpPayloadVerbose(Barnyard2Config *bc, char *args)
1763 {
1764 if (bc == NULL)
1765 return;
1766
1767 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose packet bytecode dumps enabled\n"););
1768 bc->output_flags |= OUTPUT_FLAG__VERBOSE_DUMP;
1769 }
1770
ConfigGenFile(Barnyard2Config * bc,char * args)1771 void ConfigGenFile(Barnyard2Config *bc, char *args)
1772 {
1773 if ((args == NULL) || (bc == NULL) )
1774 return;
1775
1776 bc->gen_msg_file = strndup(args,PATH_MAX);
1777 return;
1778 }
1779
ConfigHostname(Barnyard2Config * bc,char * args)1780 void ConfigHostname(Barnyard2Config *bc, char *args)
1781 {
1782 if ((args == NULL) || (bc == NULL) || (bc->hostname != NULL))
1783 return;
1784
1785 /* this code handles the case in which the user specifies
1786 * the entire name of the host and it is compiled regardless
1787 * of which OS you have */
1788 bc->hostname = SnortStrdup(args);
1789 }
1790
ConfigInterface(Barnyard2Config * bc,char * args)1791 void ConfigInterface(Barnyard2Config *bc, char *args)
1792 {
1793 if ((args == NULL) || (bc == NULL) || (bc->interface != NULL))
1794 return;
1795
1796 /* this code handles the case in which the user specifies
1797 * the entire name of the interface and it is compiled
1798 * regardless of which OS you have */
1799 bc->interface = SnortStrdup(args);
1800 }
1801
ConfigLogDir(Barnyard2Config * bc,char * args)1802 void ConfigLogDir(Barnyard2Config *bc, char *args)
1803 {
1804 if ((args == NULL) || (bc == NULL) || (bc->log_dir != NULL))
1805 return;
1806
1807 bc->log_dir = SnortStrdup(args);
1808 }
1809
ConfigNoLoggingTimestamps(Barnyard2Config * bc,char * args)1810 void ConfigNoLoggingTimestamps(Barnyard2Config *bc, char *args)
1811 {
1812 if (bc == NULL)
1813 return;
1814
1815 bc->output_flags |= OUTPUT_FLAG__NO_TIMESTAMP;
1816 }
1817
ConfigObfuscate(Barnyard2Config * bc,char * args)1818 void ConfigObfuscate(Barnyard2Config *bc, char *args)
1819 {
1820 if (bc == NULL)
1821 return;
1822
1823 bc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
1824 }
1825
ConfigObfuscationMask(Barnyard2Config * bc,char * args)1826 void ConfigObfuscationMask(Barnyard2Config *bc, char *args)
1827 {
1828 #ifndef SUP_IP6
1829 struct in_addr net; /* place to stick the local network data */
1830 char **toks; /* dbl ptr to store mSplit return data in */
1831 int num_toks; /* number of tokens mSplit returns */
1832 int nmask; /* temporary netmask storage */
1833 # ifdef DEBUG
1834 struct in_addr sin;
1835 # endif
1836 #endif
1837
1838 if ((bc == NULL) || (args == NULL))
1839 return;
1840
1841 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Got obfus data: %s\n", args););
1842
1843 #ifdef SUP_IP6
1844 sfip_pton(args, &bc->obfuscation_net);
1845 bc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
1846 #else
1847 /* break out the CIDR notation from the IP address */
1848 toks = mSplit(args, "/", 2, &num_toks, 0);
1849
1850 if(num_toks > 1)
1851 {
1852 /* convert the CIDR notation into a real live netmask */
1853 nmask = atoi(toks[1]);
1854
1855 if((nmask > 0) && (nmask < 33))
1856 {
1857 bc->obfuscation_mask = htonl(netmasks[nmask]);
1858 }
1859 else
1860 {
1861 ParseError("Bad CIDR block (%s) in obfuscation mask %s. "
1862 "1 to 32 please!", toks[1], args);
1863 }
1864 }
1865 else
1866 {
1867 ParseError("No netmask specified for obsucation mask!");
1868 }
1869
1870 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "obfuscation netmask = %#8lX\n",
1871 bc->obfuscation_mask););
1872
1873 /* convert the IP addr into its 32-bit value */
1874 if((net.s_addr = inet_addr(toks[0])) == INADDR_NONE)
1875 ParseError("Obfuscation mask (%s) didn't translate.", toks[0]);
1876
1877 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Obfuscation Net = %s (%X)\n",
1878 inet_ntoa(net), net.s_addr););
1879
1880 /* set the final homenet address up */
1881 bc->obfuscation_net = net.s_addr & bc->obfuscation_mask;
1882
1883 #ifdef DEBUG
1884 sin.s_addr = bc->obfuscation_net;
1885 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Obfuscation Net = %s (%X)\n",
1886 inet_ntoa(sin), sin.s_addr););
1887 #endif
1888
1889 bc->obfuscation_mask = ~bc->obfuscation_mask;
1890 bc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
1891
1892 mSplitFree(&toks, num_toks);
1893 #endif
1894 }
1895
ConfigPidPath(Barnyard2Config * bc,char * args)1896 void ConfigPidPath(Barnyard2Config *bc, char *args)
1897 {
1898 if ((args == NULL) || (bc == NULL))
1899 return;
1900
1901 LogMessage("Found pid path directive (%s)\n", args);
1902
1903 bc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
1904 if (SnortStrncpy(bc->pid_path, args, sizeof(bc->pid_path)) != SNORT_STRNCPY_SUCCESS)
1905 ParseError("Pid path too long.");
1906
1907 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Pid Path directory = %s\n",
1908 bc->pid_path););
1909 }
1910
ConfigQuiet(Barnyard2Config * bc,char * args)1911 void ConfigQuiet(Barnyard2Config *bc, char *args)
1912 {
1913 if (bc == NULL)
1914 return;
1915
1916 bc->logging_flags |= LOGGING_FLAG__QUIET;
1917 }
1918
ConfigReference(Barnyard2Config * bc,char * args)1919 void ConfigReference(Barnyard2Config *bc, char *args)
1920 {
1921 char **toks;
1922 int num_toks;
1923 char *url = NULL;
1924
1925 if ((bc == NULL) || (args == NULL))
1926 return;
1927
1928 /* 2 tokens: name <url> */
1929 toks = mSplit(args, " \t", 0, &num_toks, 0);
1930
1931 if (num_toks > 2)
1932 {
1933 ParseError("Reference config requires at most two arguments: "
1934 "\"name [<url>]\".");
1935 }
1936
1937 if (num_toks == 2)
1938 url = toks[1];
1939
1940 ReferenceSystemAdd(&bc->references, toks[0], url);
1941
1942 mSplitFree(&toks, num_toks);
1943 }
1944
ConfigReferenceFile(Barnyard2Config * bc,char * args)1945 void ConfigReferenceFile(Barnyard2Config *bc, char *args)
1946 {
1947 if ((args == NULL) || (bc == NULL) )
1948 return;
1949
1950 ReadReferenceFile(bc, args);
1951 }
1952
1953 /*
1954 * Function: ConfigReferenceNet
1955 *
1956 * Purpose: Translate the command line character string into its equivalent
1957 * 32-bit network byte ordered value (with netmask)
1958 *
1959 * Arguments: args => The address/CIDR block
1960 *
1961 * Returns: void function
1962 */
ConfigReferenceNet(Barnyard2Config * bc,char * args)1963 void ConfigReferenceNet(Barnyard2Config *bc, char *args)
1964 {
1965 #ifndef SUP_IP6
1966 struct in_addr net; /* place to stick the local network data */
1967 char **toks; /* dbl ptr to store mSplit return data in */
1968 int num_toks; /* number of tokens mSplit returns */
1969 int nmask; /* temporary netmask storage */
1970 # ifdef DEBUG
1971 struct in_addr sin;
1972 # endif
1973 #endif
1974
1975 if ((bc == NULL) || (args == NULL))
1976 return;
1977
1978 #ifdef SUP_IP6
1979 sfip_pton(args, &bc->homenet);
1980 #else
1981
1982 /* break out the CIDR notation from the IP address */
1983 toks = mSplit(args, "/", 2, &num_toks, 0);
1984
1985 if(num_toks > 1)
1986 {
1987 /* convert the CIDR notation into a real live netmask */
1988 nmask = atoi(toks[1]);
1989
1990 if((nmask > 0) && (nmask < 33))
1991 {
1992 bc->netmask = htonl(netmasks[nmask]);
1993 }
1994 else
1995 {
1996 ParseError("Bad CIDR block (%s) in obfuscation mask %s. "
1997 "1 to 32 please!", toks[1], args);
1998 }
1999 }
2000 else
2001 {
2002 ParseError("No netmask specified for home network!");
2003 }
2004
2005 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "homenet netmask = %#8lX\n",
2006 bc->netmask););
2007
2008 /* convert the IP addr into its 32-bit value */
2009 if((net.s_addr = inet_addr(toks[0])) == INADDR_NONE)
2010 ParseError("Homenet (%s) didn't translate", toks[0]);
2011
2012 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Net = %s (%X)\n",
2013 inet_ntoa(net), net.s_addr););
2014
2015 /* set the final homenet address up */
2016 bc->homenet = net.s_addr & bc->netmask;
2017
2018 # ifdef DEBUG
2019 sin.s_addr = bc->homenet;
2020 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Homenet = %s (%X)\n",
2021 inet_ntoa(sin), sin.s_addr););
2022 # endif
2023
2024 mSplitFree(&toks, num_toks);
2025 #endif
2026 }
2027
ConfigSetGid(Barnyard2Config * bc,char * args)2028 void ConfigSetGid(Barnyard2Config *bc, char *args)
2029 {
2030 #ifdef WIN32
2031 ParseError("Setting the group id is not supported in the "
2032 "WIN32 port of barnyard2!");
2033 #else
2034 size_t i;
2035 char *endptr;
2036
2037 if ((bc == NULL) || (args == NULL))
2038 return;
2039
2040 for (i = 0; i < strlen(args); i++)
2041 {
2042 /* If we get something other than a digit, assume it's
2043 * a group name */
2044 if (!isdigit((int)args[i]))
2045 {
2046 struct group *gr = getgrnam(args);
2047
2048 if (gr == NULL)
2049 ParseError("Group \"%s\" unknown.", args);
2050
2051 bc->group_id = gr->gr_gid;
2052 break;
2053 }
2054 }
2055
2056 /* It's all digits. Assume it's a group id */
2057 if (i == strlen(args))
2058 {
2059 bc->group_id = strtol(args, &endptr, 10);
2060 if ((errno == ERANGE) || (*endptr != '\0') ||
2061 (bc->group_id < 0))
2062 {
2063 ParseError("Group id \"%s\" out of range.", args);
2064 }
2065 }
2066 #endif
2067 }
2068
ConfigSetUid(Barnyard2Config * bc,char * args)2069 void ConfigSetUid(Barnyard2Config *bc, char *args)
2070 {
2071 #ifdef WIN32
2072 ParseError("Setting the user id is not supported in the "
2073 "WIN32 port of barnyard2!");
2074 #else
2075 size_t i;
2076 char *endptr;
2077
2078 if ((bc == NULL) || (args == NULL))
2079 return;
2080
2081 for (i = 0; i < strlen(args); i++)
2082 {
2083 /* If we get something other than a digit, assume it's
2084 * a user name */
2085 if (!isdigit((int)args[i]))
2086 {
2087 struct passwd *pw = getpwnam(args);
2088
2089 if (pw == NULL)
2090 ParseError("User \"%s\" unknown.", args);
2091
2092 bc->user_id = (int)pw->pw_uid;
2093
2094 /* Why would someone want to run as another user
2095 * but still as root group? */
2096 if (bc->group_id == -1)
2097 bc->group_id = (int)pw->pw_gid;
2098
2099 break;
2100 }
2101 }
2102
2103 /* It's all digits. Assume it's a user id */
2104 if (i == strlen(args))
2105 {
2106 bc->user_id = strtol(args, &endptr, 10);
2107 if ((errno == ERANGE) || (*endptr != '\0'))
2108 ParseError("User id \"%s\" out of range.", args);
2109
2110 /* Set group id to user's default group if not
2111 * already set */
2112 if (bc->group_id == -1)
2113 {
2114 struct passwd *pw = getpwuid((uid_t)bc->user_id);
2115
2116 if (pw == NULL)
2117 ParseError("User \"%s\" unknown.", args);
2118
2119 bc->group_id = (int)pw->pw_gid;
2120 }
2121 }
2122
2123 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "UserID: %d GroupID: %d.\n",
2124 bc->user_id, bc->group_id););
2125 #endif /* !WIN32 */
2126 }
2127
ConfigShowYear(Barnyard2Config * bc,char * args)2128 void ConfigShowYear(Barnyard2Config *bc, char *args)
2129 {
2130 if (bc == NULL)
2131 return;
2132
2133 bc->output_flags |= OUTPUT_FLAG__INCLUDE_YEAR;
2134 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabled year in timestamp\n"););
2135 }
2136
ConfigSidFile(Barnyard2Config * bc,char * args)2137 void ConfigSidFile(Barnyard2Config *bc, char *args)
2138 {
2139 if ((args == NULL) || (bc == NULL) )
2140 return;
2141
2142 bc->sid_msg_file = strndup(args,PATH_MAX);
2143 }
2144
ConfigUmask(Barnyard2Config * bc,char * args)2145 void ConfigUmask(Barnyard2Config *bc, char *args)
2146 {
2147 #ifdef WIN32
2148 ParseError("Setting the umask is not supported in the "
2149 "WIN32 port of snort!");
2150 #else
2151 char *endptr;
2152 long mask;
2153
2154 if ((bc == NULL) || (args == NULL))
2155 return;
2156
2157 mask = strtol(args, &endptr, 0);
2158
2159 if ((errno == ERANGE) || (*endptr != '\0') ||
2160 (mask < 0) || (mask & ~FILEACCESSBITS))
2161 {
2162 ParseError("Bad umask: %s", args);
2163 }
2164 bc->file_mask = (mode_t)mask;
2165 #endif
2166 }
2167
ConfigUtc(Barnyard2Config * bc,char * args)2168 void ConfigUtc(Barnyard2Config *bc, char *args)
2169 {
2170 if (bc == NULL)
2171 return;
2172
2173 bc->output_flags |= OUTPUT_FLAG__USE_UTC;
2174 }
2175
ConfigVerbose(Barnyard2Config * bc,char * args)2176 void ConfigVerbose(Barnyard2Config *bc, char *args)
2177 {
2178 if (bc == NULL)
2179 return;
2180
2181 bc->logging_flags |= LOGGING_FLAG__VERBOSE;
2182 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose Flag active\n"););
2183 }
2184
ConfigProcessNewRecordsOnly(Barnyard2Config * bc,char * args)2185 void ConfigProcessNewRecordsOnly(Barnyard2Config *bc, char *args)
2186 {
2187 if (bc == NULL)
2188 return;
2189
2190 bc->process_new_records_only_flag = 1;
2191 }
2192
ConfigSpoolFilebase(Barnyard2Config * bc,char * args)2193 void ConfigSpoolFilebase(Barnyard2Config *bc, char *args)
2194 {
2195 if ((args == NULL) || (bc == NULL) )
2196 return;
2197
2198 if ( SnortSnprintf(bc->waldo.data.spool_filebase, STD_BUF, "%s", args) != SNORT_SNPRINTF_SUCCESS )
2199 FatalError("barnyard2: spool filebase too long\n");
2200 }
2201
ConfigSpoolDirectory(Barnyard2Config * bc,char * args)2202 void ConfigSpoolDirectory(Barnyard2Config *bc, char *args)
2203 {
2204 if ((args == NULL) || (bc == NULL) )
2205 return;
2206
2207 if ( SnortSnprintf(bc->waldo.data.spool_dir, STD_BUF, "%s", args) != SNORT_SNPRINTF_SUCCESS )
2208 FatalError("barnyard2: spool directory too long\n");
2209 }
2210
ConfigWaldoFile(Barnyard2Config * bc,char * args)2211 void ConfigWaldoFile(Barnyard2Config *bc, char *args)
2212 {
2213 if ((args == NULL) || (bc == NULL) )
2214 return;
2215
2216 if ( SnortSnprintf(bc->waldo.filepath, STD_BUF, "%s", args) != SNORT_SNPRINTF_SUCCESS )
2217 FatalError("barnyard2: waldo filepath too long\n");
2218
2219 bc->waldo.state |= WALDO_STATE_ENABLED;
2220 }
2221
2222
DisplaySigSuppress(SigSuppress_list ** sHead)2223 void DisplaySigSuppress(SigSuppress_list **sHead)
2224 {
2225 if(sHead == NULL)
2226 {
2227 return;
2228 }
2229 SigSuppress_list *cNode = *sHead;
2230
2231 LogMessage("\n\n+[ Signature Suppress list ]+\n"
2232 "----------------------------\n");
2233
2234 if(cNode)
2235 {
2236 while(cNode)
2237 {
2238 LogMessage("-- Element type:[%s] gid:[%d] sid min:[%d] sid max:[%d] \n",
2239 (cNode->ss_type & SS_SINGLE) ? "SINGLE" : "RANGE ",
2240 cNode->gid,
2241 cNode->ss_min,
2242 cNode->ss_max);
2243
2244 cNode = cNode->next;
2245 }
2246 }
2247 else
2248 {
2249 LogMessage("+[No entry in Signature Suppress List]+\n");
2250 }
2251 LogMessage("----------------------------\n"
2252 "+[ Signature Suppress list ]+\n\n");
2253 return;
2254 }
2255
SigSuppressUnlinkNode(SigSuppress_list ** sHead,SigSuppress_list ** cNode,SigSuppress_list ** pNode)2256 int SigSuppressUnlinkNode(SigSuppress_list **sHead,SigSuppress_list **cNode,SigSuppress_list **pNode)
2257 {
2258 SigSuppress_list *nNode = NULL;
2259
2260 if( ((sHead == NULL) || (*sHead == NULL)) ||
2261 ((cNode == NULL) || (*cNode == NULL)) ||
2262 ((pNode == NULL) || (*pNode == NULL)))
2263 {
2264 return 1;
2265 }
2266
2267 nNode =(SigSuppress_list *)(*cNode)->next;
2268
2269 if( *cNode == *sHead)
2270 {
2271 *sHead = nNode;
2272 free(*cNode);
2273 *cNode = nNode;
2274 *pNode = *cNode;
2275 }
2276 else
2277 {
2278 (*(SigSuppress_list **)(pNode))->next = nNode;
2279 free(*cNode);
2280 *cNode = nNode;
2281 }
2282
2283 return 0;
2284 }
2285
SigSuppressAddElement(SigSuppress_list ** sHead,SigSuppress_list * sElement)2286 int SigSuppressAddElement(SigSuppress_list **sHead,SigSuppress_list *sElement)
2287 {
2288 SigSuppress_list *cNode = NULL;
2289 SigSuppress_list *pNode = NULL;
2290 SigSuppress_list *newNode = NULL;
2291
2292 u_int8_t comp_set[4] = {0};
2293
2294 int has_flag = 0;
2295 int no_add = 0;
2296
2297 if( (sHead == NULL) ||
2298 (sElement == NULL))
2299 {
2300 return 1;
2301 }
2302
2303 if(*sHead == NULL)
2304 {
2305 if( (newNode = calloc(1,sizeof(SigSuppress_list))) == NULL)
2306 {
2307 return 1;
2308 }
2309
2310 memcpy(newNode,sElement,sizeof(SigSuppress_list));
2311 *sHead = newNode;
2312 }
2313 else
2314 {
2315 cNode = *sHead;
2316 pNode = cNode;
2317
2318 has_flag = 0;
2319 no_add = 0;
2320
2321 while(cNode != NULL)
2322 {
2323 memset(&comp_set,'\0',(sizeof(u_int8_t)*4));
2324
2325 if (cNode->gid == sElement->gid)
2326 {
2327 switch(sElement->ss_type)
2328 {
2329 case SS_SINGLE:
2330 switch(cNode->ss_type)
2331 {
2332 case SS_SINGLE:
2333 if( ((cNode->ss_min == sElement->ss_min) &&
2334 (cNode->ss_max == sElement->ss_max)))
2335 {
2336 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,"[%s()], Signature Suppress configuration entry type:[SINGLE] gid:[%d] sid:[%d] was not added because it is already in present.\n",
2337 __FUNCTION__,
2338 sElement->gid,
2339 sElement->ss_min););
2340 return 0;
2341 }
2342 break;
2343
2344 case SS_RANGE:
2345 if( ((cNode->ss_min <= sElement->ss_min) &&
2346 (cNode->ss_max >= sElement->ss_max)))
2347 {
2348 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2349 "[%s()], Signature Suppress configuration entry gid:[%d] sid[%d] already covered by\n"
2350 "Signature Suppress configuration list element type:[RANGE] gid:[%d] sid min:[%d] sid max:[%d].\n",
2351 __FUNCTION__,
2352 sElement->gid,
2353 sElement->ss_min,
2354 cNode->gid,
2355 cNode->ss_min,
2356 cNode->ss_max););
2357 return 0;
2358 }
2359 break;
2360
2361 default:
2362 /* XXX */
2363 return 1;
2364 break;
2365 }
2366 break;
2367
2368 case SS_RANGE:
2369 switch(cNode->ss_type)
2370 {
2371 case SS_SINGLE:
2372 if( ((sElement->ss_min <= cNode->ss_min) &&
2373 (sElement->ss_max >= cNode->ss_max)))
2374 {
2375 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2376 "[%s()], Signature Suppress configuration gid:[%d] sid:[%d] flagged for deletion from list,\n"
2377 "Element is intersecting with Signature Suppress list range gid[%d] sid min:[%d] sid max:[%d]\n\n",
2378 __FUNCTION__,
2379 cNode->gid,
2380 cNode->ss_min,
2381 sElement->gid,
2382 sElement->ss_min,
2383 sElement->ss_max););
2384 cNode->flag = 1;
2385 has_flag = 1;
2386 }
2387 break;
2388
2389 case SS_RANGE:
2390 if(sElement->ss_min <= cNode->ss_min)
2391 comp_set[0] = 1;
2392
2393 if(sElement->ss_min >= cNode->ss_max)
2394 comp_set[1] = 1;
2395
2396 if(sElement->ss_max >= cNode->ss_min)
2397 comp_set[2] = 1;
2398
2399 if(sElement->ss_max <= cNode->ss_max)
2400 comp_set[3] = 1;
2401
2402 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2403 "[%s()]: Comparing Signature intersection comp0:[%d] comp1:[%d] comp2:[%d] comp3:[%d]\n"
2404 "Signature Suppress configuration entry: gid:[%d] sid min:[%d] sid max:[%d]\n"
2405 "Signature Suppress list entry: gid:[%d] sid min:[%d] sid max:[%d]\n\n",
2406 __FUNCTION__,
2407 comp_set[0],comp_set[1],comp_set[2],comp_set[3],
2408 sElement->gid,sElement->ss_min,sElement->ss_max,
2409 cNode->gid,cNode->ss_min,cNode->ss_max););
2410
2411 if( (comp_set[0] && !comp_set[1] && comp_set[2] && comp_set[3]) ||
2412 (!comp_set[0] && !comp_set[1] && comp_set[2] && comp_set[3]))
2413 {
2414 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2415 "[%s()]: Signature Suppress configuration entry gid:[%d] sid min:[%d] sid max:[%d] is INCLUDED in \n"
2416 "Signature Suppress list entry gid:[%d] sid min:[%d] sid max:[%d]\n\n",
2417 __FUNCTION__,
2418 sElement->gid,sElement->ss_min,sElement->ss_max,
2419 cNode->gid,cNode->ss_min,cNode->ss_max););
2420
2421 no_add = 1;
2422 }
2423 else if( (comp_set[0] && comp_set[1] && !comp_set[2] && comp_set[3]) ||
2424 (!comp_set[0] && !comp_set[1] && comp_set[2] && !comp_set[3]))
2425 {
2426
2427 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2428 "[%s()]: Signature Suppress list entry gid:[%d] sid min:[%d] sid max:[%d] and\n"
2429 "Signature Suppress configuration entry gid:[%d] sid min:[%d] sid max:[%d] share some intesection, altering list entry. \n\n",
2430 __FUNCTION__,
2431 cNode->gid,cNode->ss_min,cNode->ss_max,
2432 sElement->gid,sElement->ss_min,sElement->ss_max););
2433
2434 if(sElement->ss_min <= cNode->ss_min)
2435 {
2436 cNode->ss_min = sElement->ss_min;
2437 }
2438
2439 if(sElement->ss_max >= cNode->ss_max)
2440 {
2441 cNode->ss_max = sElement->ss_max;
2442 }
2443
2444 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2445 "[%s()]: Modified Signature Suppress list entry gid:[%d] sid min:[%d] sid max:[%d] \n",
2446 __FUNCTION__,
2447 cNode->gid,cNode->ss_min,cNode->ss_max););
2448
2449 no_add = 1;
2450 }
2451 break;
2452
2453 default:
2454 FatalError("[%s()]: Unknown type[%d] for Signature Suppress configuration entry gid:[%d] sid min:[%d] max sid:[%d] \n",
2455 __FUNCTION__,
2456 cNode->ss_type,
2457 cNode->gid,
2458 cNode->ss_min,
2459 cNode->ss_max);
2460 return 1;
2461 break;
2462
2463 }
2464 break;
2465
2466 default:
2467 FatalError("[%s()]: Unknown type[%d] for Signature Suppress configuration entry gid:[%d] sid min:[%d] max sid:[%d] \n",
2468 __FUNCTION__,
2469 sElement->ss_type,
2470 sElement->gid,
2471 sElement->ss_min,
2472 sElement->ss_max);
2473 return 1;
2474 break;
2475 }
2476 }
2477
2478 pNode = cNode;
2479 cNode = cNode->next;
2480 }
2481
2482 /* We could keep an index, but rolling is way faster isin't ;) */
2483 if(has_flag)
2484 {
2485 cNode = *sHead;
2486 pNode = cNode;
2487
2488 while(cNode)
2489 {
2490 if(cNode->flag)
2491 {
2492 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2493 "[%s(), unlinking Signature Suppress list entry type:[%d] gid:[%d] sid_min:[%d] sid_max:[%d] \n",
2494 __FUNCTION__,
2495 cNode->ss_type,
2496 cNode->gid,
2497 cNode->ss_min,
2498 cNode->ss_max););
2499
2500 if( SigSuppressUnlinkNode(sHead,&cNode,&pNode))
2501 {
2502 return 1;
2503 }
2504 }
2505
2506 if(cNode)
2507 {
2508 pNode = cNode;
2509 cNode = cNode->next;
2510 }
2511 }
2512 }
2513
2514 if(!no_add)
2515 {
2516 if( (newNode = calloc(1,sizeof(SigSuppress_list))) == NULL)
2517 {
2518 return 1;
2519 }
2520
2521 memcpy(newNode,sElement,sizeof(SigSuppress_list));
2522
2523 pNode->next = newNode;
2524
2525 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS,
2526 "[%s()], Signature Suppress configuration entry type:[%s] gid:[%d] sid min:[%d] sid max:[%d] added to Signature Suppress list.\n",
2527 __FUNCTION__,
2528 (newNode->ss_type & SS_SINGLE) ? "SINGLE" : "RANGE",
2529 newNode->gid,
2530 newNode->ss_min,
2531 newNode->ss_max););
2532 }
2533 }
2534
2535
2536 return 0;
2537 }
2538
ConfigSigSuppress(Barnyard2Config * bc,char * args)2539 void ConfigSigSuppress(Barnyard2Config *bc, char *args)
2540 {
2541 char **toks = NULL;
2542 int num_toks = 0;
2543 int ptoks = 0;
2544
2545 char gid_string[256] = {0};
2546
2547 char **range_toks = NULL;
2548 int range_num_toks = 0;
2549
2550 char **gid_toks = NULL;
2551 char *gid_sup_toks = NULL;
2552 int gid_num_toks = 0;
2553
2554 SigSuppress_list t_supp_elem = {0};
2555
2556 if( (bc == NULL) || (args == NULL))
2557 {
2558 return;
2559 }
2560
2561 toks = mSplit(args, ",", 0, &num_toks, 0);
2562
2563 while(ptoks < num_toks)
2564 {
2565 memset(gid_string,'\0',256);
2566
2567 gid_toks = mSplit(toks[ptoks], ":", 2, &gid_num_toks, 0);
2568
2569 if(gid_num_toks == 1)
2570 {
2571 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS_PARSE,"Defaulting gid 1 for toks [%s]\n",
2572 toks[ptoks]););
2573 t_supp_elem.gid = 1;
2574 gid_sup_toks = toks[ptoks];
2575 }
2576 else if(gid_num_toks == 2)
2577 {
2578 memcpy(gid_string,gid_toks[0],strlen(gid_toks[0]));
2579
2580 if( BY2Strtoul(gid_string,&t_supp_elem.gid))
2581 {
2582 FatalError("[%s] \n",__FUNCTION__);
2583 }
2584
2585 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS_PARSE,"Using gid [%d] for toks [%s]\n",
2586 t_supp_elem.gid,
2587 toks[ptoks]););
2588
2589 gid_sup_toks = gid_toks[1];
2590 }
2591 else
2592 {
2593 FatalError("[%s()]: Invalid gid split value for [%s]\n",
2594 __FUNCTION__,
2595 toks[ptoks]);
2596 }
2597
2598 range_toks = mSplit(gid_sup_toks, "-", 0, &range_num_toks, 0);
2599
2600 if(range_num_toks == 1)
2601 {
2602 t_supp_elem.ss_type = SS_SINGLE;
2603
2604 if( BY2Strtoul(gid_sup_toks,&t_supp_elem.ss_min))
2605 {
2606 FatalError("[%s] \n",__FUNCTION__);
2607 }
2608
2609 t_supp_elem.ss_max = t_supp_elem.ss_min;
2610
2611 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS_PARSE,"Single element gid[%d] sid[%d] \n",
2612 t_supp_elem.gid,
2613 t_supp_elem.ss_min););
2614 }
2615 else if(range_num_toks == 2)
2616 {
2617 DEBUG_WRAP(DebugMessage(DEBUG_SID_SUPPRESS_PARSE,"Got range [%s] : [%s] [%s] \n",
2618 gid_sup_toks,
2619 range_toks[0],
2620 range_toks[1]););
2621
2622 t_supp_elem.ss_type = SS_RANGE;
2623
2624 if( BY2Strtoul(range_toks[0],&t_supp_elem.ss_min))
2625 {
2626 FatalError("[%s] \n",__FUNCTION__);
2627 }
2628
2629 if( BY2Strtoul(range_toks[1],&t_supp_elem.ss_max))
2630 {
2631 FatalError("[%s] \n",__FUNCTION__);
2632 }
2633
2634 if(t_supp_elem.ss_min > t_supp_elem.ss_max)
2635 {
2636 FatalError("[%s()], Min greater than max, invalid range [%s] \n",
2637 __FUNCTION__,
2638 gid_sup_toks);
2639 }
2640
2641 if(t_supp_elem.ss_min == t_supp_elem.ss_max)
2642 {
2643 FatalError("[%s()], Min equal than max, invalid range [%s] \n",
2644 __FUNCTION__,
2645 gid_sup_toks);
2646 }
2647 }
2648 else
2649 {
2650 FatalError("element[%s] is an invalid range \n",gid_sup_toks);
2651 }
2652
2653 mSplitFree(&range_toks, range_num_toks);
2654 mSplitFree(&gid_toks, gid_num_toks);
2655
2656 if(SigSuppressAddElement(BCGetSigSuppressHead(),&t_supp_elem))
2657 {
2658 FatalError("[%s()], unrecoverable call to SigSuppressAddElement() \n",
2659 __FUNCTION__);
2660 }
2661
2662 ptoks++;
2663 }
2664
2665 mSplitFree(&toks, num_toks);
2666 return;
2667 }
2668
2669
2670
2671
2672 #ifdef MPLS
ConfigMaxMplsLabelChain(Barnyard2Config * bc,char * args)2673 void ConfigMaxMplsLabelChain(Barnyard2Config *bc, char *args)
2674 {
2675 char *endp;
2676 long val = 0;
2677
2678 if (bc == NULL)
2679 return;
2680
2681 if (args != NULL)
2682 {
2683 val = strtol(args, &endp, 0);
2684 if ((args == endp) || *endp || (val < -1))
2685 val = DEFAULT_LABELCHAIN_LENGTH;
2686 }
2687 else
2688 {
2689 val = DEFAULT_LABELCHAIN_LENGTH;
2690 }
2691
2692 bc->mpls_stack_depth = val;
2693 }
2694
ConfigMplsPayloadType(Barnyard2Config * bc,char * args)2695 void ConfigMplsPayloadType(Barnyard2Config *bc, char *args)
2696 {
2697 if (bc == NULL)
2698 return;
2699
2700 if (args != NULL)
2701 {
2702 if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV4) == 0)
2703 {
2704 bc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV4;
2705 }
2706 else if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV6) == 0)
2707 {
2708 bc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV6;
2709 }
2710 else if (strcasecmp(args, MPLS_PAYLOAD_OPT__ETHERNET) == 0)
2711 {
2712 bc->mpls_payload_type = MPLS_PAYLOADTYPE_ETHERNET;
2713 }
2714 else
2715 {
2716 ParseError("Non supported mpls payload type: %s.", args);
2717 }
2718 }
2719 else
2720 {
2721 bc->mpls_payload_type = DEFAULT_MPLS_PAYLOADTYPE;
2722 }
2723 }
2724 #endif
2725
2726 #ifdef SUP_IP6
ParseIpVar(Barnyard2Config * bc,char * args)2727 static void ParseIpVar(Barnyard2Config *bc, char *args)
2728 {
2729 char **toks;
2730 int num_toks;
2731
2732 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "IpVar\n"););
2733
2734 toks = mSplit(args, " \t", 0, &num_toks, 0);
2735 if (num_toks != 2)
2736 {
2737 ParseError("Missing argument to %s", toks[0]);
2738 }
2739
2740 /* Check command line variables to see if this has already
2741 * been defined */
2742 if (cmd_line_var_list != NULL)
2743 {
2744 VarNode *tmp = cmd_line_var_list;
2745
2746 while (tmp != NULL)
2747 {
2748 /* Already defined this via command line */
2749 if (strcasecmp(toks[0], tmp->name) == 0)
2750 {
2751 mSplitFree(&toks, num_toks);
2752 return;
2753 }
2754
2755 tmp = tmp->next;
2756 }
2757 }
2758
2759 DisallowCrossTableDuplicateVars(bc, toks[0], VAR_TYPE__IPVAR);
2760 sfvt_define(bc->ip_vartable, toks[0], toks[1]);
2761
2762 mSplitFree(&toks, num_toks);
2763 }
2764 #else
ParseIpVar(Barnyard2Config * bc,char * args)2765 static void ParseIpVar(Barnyard2Config *bc, char *args)
2766 {
2767 ParseError("Unknown rule type: %s.", "ipvar");
2768 }
2769 #endif
2770
ParseVar(Barnyard2Config * bc,char * args)2771 static void ParseVar(Barnyard2Config *bc, char *args)
2772 {
2773 char **toks;
2774 int num_toks;
2775
2776 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Variable\n"););
2777
2778 toks = mSplit(args, " \t", 0, &num_toks, 0);
2779 if (num_toks != 2)
2780 {
2781 ParseError("Missing argument to %s", toks[0]);
2782 }
2783
2784 /* Check command line variables to see if this has already
2785 * been defined */
2786 if (cmd_line_var_list != NULL)
2787 {
2788 VarNode *tmp = cmd_line_var_list;
2789
2790 while (tmp != NULL)
2791 {
2792 // Already defined this via command line
2793 if (strcasecmp(toks[0], tmp->name) == 0)
2794 {
2795 mSplitFree(&toks, num_toks);
2796 return;
2797 }
2798
2799 tmp = tmp->next;
2800 }
2801 }
2802
2803 AddVarToTable(bc, toks[0], toks[1]);
2804 mSplitFree(&toks, num_toks);
2805 }
2806
AddVarToTable(Barnyard2Config * bc,char * name,char * value)2807 static void AddVarToTable(Barnyard2Config *bc, char *name, char *value)
2808 {
2809 VarDefine(bc, name, value);
2810 }
2811
VarTablesFree(Barnyard2Config * bc)2812 void VarTablesFree(Barnyard2Config *bc)
2813 {
2814 if (bc == NULL)
2815 return;
2816
2817 if (bc->var_table != NULL)
2818 {
2819 DeleteVars(bc->var_table);
2820 bc->var_table = NULL;
2821 }
2822
2823 #ifdef SUP_IP6
2824 if (bc->ip_vartable != NULL)
2825 {
2826 sfvt_free_table(bc->ip_vartable);
2827 bc->ip_vartable = NULL;
2828 }
2829 #endif
2830 }
2831
ParseError(const char * format,...)2832 NORETURN void ParseError(const char *format, ...)
2833 {
2834 char buf[STD_BUF+1];
2835 va_list ap;
2836
2837 va_start(ap, format);
2838 vsnprintf(buf, STD_BUF, format, ap);
2839 va_end(ap);
2840
2841 buf[STD_BUF] = '\0';
2842
2843 if (file_name != NULL)
2844 FatalError("%s(%d) %s\n", file_name, file_line, buf);
2845 else
2846 FatalError("%s\n", buf);
2847 }
2848
ParseMessage(const char * format,...)2849 void ParseMessage(const char *format, ...)
2850 {
2851 char buf[STD_BUF+1];
2852 va_list ap;
2853
2854 va_start(ap, format);
2855 vsnprintf(buf, STD_BUF, format, ap);
2856 va_end(ap);
2857
2858 buf[STD_BUF] = '\0';
2859
2860 if (file_name != NULL)
2861 LogMessage("%s(%d) %s\n", file_name, file_line, buf);
2862 else
2863 LogMessage("%s\n", buf);
2864 }
2865
2866 // the presence of ip lists exceeds mSplit's one-level parsing
2867 // so we transform rule string into something that mSplit can
2868 // handle by changing ',' to c outside ip lists.
2869 // we also strip the leading keyword.
FixSeparators(char * rule,char c,const char * err)2870 char* FixSeparators (char* rule, char c, const char* err)
2871 {
2872 int list = 0;
2873 char* p = strchr(rule, c);
2874
2875 if ( p && err )
2876 {
2877 FatalError("%s(%d) => %s: '%c' not allowed in argument\n",
2878 file_name, file_line, err, c);
2879 }
2880 while ( isspace((int)*rule) ) rule++;
2881
2882 p = rule;
2883
2884 while ( *p ) {
2885 if ( *p == '[' ) list++;
2886 else if ( *p == ']' ) list--;
2887 else if ( *p == ',' && !list ) *p = c;
2888 p++;
2889 }
2890 return rule;
2891 }
2892
GetNameValue(char * arg,char ** nam,char ** val,const char * err)2893 void GetNameValue (char* arg, char** nam, char** val, const char* err)
2894 {
2895 while ( isspace((int)*arg) ) arg++;
2896 *nam = arg;
2897
2898 while ( *arg && !isspace((int)*arg) ) arg++;
2899 if ( *arg ) *arg++ = '\0';
2900 *val = arg;
2901
2902 if ( err && !**val )
2903 {
2904 FatalError("%s(%d) => %s: name value pair expected: %s\n",
2905 file_name, file_line, err, *nam);
2906 }
2907 }
2908
2909