1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2002-2013 Sourcefire, Inc.
5 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
6 ** Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License Version 2 as
10 ** published by the Free Software Foundation.  You may not use, modify or
11 ** distribute this program under any other version of the GNU General
12 ** Public License.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <sys/resource.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <pcap.h>
38 #ifdef HAVE_DUMBNET_H
39 #include <dumbnet.h>
40 #else
41 #include <dnet.h>
42 #endif
43 
44 #ifdef HAVE_STRINGS_H
45 # include <strings.h>
46 #endif
47 
48 #ifndef WIN32
49 # include <netdb.h>
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # include <arpa/inet.h>
53 # include <grp.h>
54 # include <pwd.h>
55 # include <fnmatch.h>
56 #endif /* !WIN32 */
57 
58 #include "encode.h"
59 #include "snort_bounds.h"
60 #include "rules.h"
61 #include "treenodes.h"
62 #include "parser.h"
63 #include "plugbase.h"
64 #include "plugin_enum.h"
65 #include "snort_debug.h"
66 #include "util.h"
67 #include "mstring.h"
68 #include "detect.h"
69 #include "fpcreate.h"
70 #include "log.h"
71 #include "generators.h"
72 #include "tag.h"
73 #include "signature.h"
74 #include "strlcatu.h"
75 #include "strlcpyu.h"
76 #include "sfthreshold.h"
77 #include "sfutil/sfthd.h"
78 #include "snort.h"
79 #include "event_queue.h"
80 #include "asn1.h"
81 #include "sfutil/sfghash.h"
82 #include "sp_preprocopt.h"
83 #include "detection-plugins/sp_icmp_type_check.h"
84 #include "detection-plugins/sp_ip_proto.h"
85 #include "detection-plugins/sp_pattern_match.h"
86 #include "detection-plugins/sp_flowbits.h"
87 #include "sf_vartable.h"
88 #include "ipv6_port.h"
89 #include "sfutil/sf_ip.h"
90 #include "sflsq.h"
91 #include "ppm.h"
92 #include "rate_filter.h"
93 #include "detection_filter.h"
94 #include "sfPolicy.h"
95 #include "sfutil/mpse.h"
96 #include "sfutil/sfrim.h"
97 #include "sfutil/sfportobject.h"
98 #include "sfutil/strvec.h"
99 #include "active.h"
100 #include "file_config.h"
101 #include "file_service_config.h"
102 #include "dynamic-plugins/sp_dynamic.h"
103 #include "dynamic-output/plugins/output.h"
104 #include "stream_common.h"
105 
106 #ifdef SIDE_CHANNEL
107 # include "sidechannel.h"
108 #endif
109 
110 #ifdef TARGET_BASED
111 # include "sftarget_reader.h"
112 #endif
113 
114 
115 /* Macros *********************************************************************/
116 #define ENABLE_ALL_RULES    1
117 #define ENABLE_RULE         1
118 #define ENABLE_ONE_RULE     0
119 #define MAX_RULE_OPTIONS     256
120 #define MAX_LINE_LENGTH    32768
121 #define MAX_IPLIST_ENTRIES  4096
122 #define DEFAULT_LARGE_RULE_GROUP 9
123 #define SF_IPPROTO_UNKNOWN -1
124 #define MAX_RULE_COUNT (65535 * 2)
125 
126 /* Rule list order keywords
127  * This is separate from keywords because activation was used
128  * instead of activate */
129 #define RULE_LIST_TYPE__ALERT       "alert"
130 #define RULE_LIST_TYPE__DROP        "drop"
131 #define RULE_LIST_TYPE__LOG         "log"
132 #define RULE_LIST_TYPE__PASS        "pass"
133 #define RULE_LIST_TYPE__REJECT     "reject"
134 #define RULE_LIST_TYPE__SDROP      "sdrop"
135 
136 #define RULE_PROTO_OPT__IP    "ip"
137 #define RULE_PROTO_OPT__TCP   "tcp"
138 #define RULE_PROTO_OPT__UDP   "udp"
139 #define RULE_PROTO_OPT__ICMP  "icmp"
140 
141 #define RULE_DIR_OPT__DIRECTIONAL    "->"
142 #define RULE_DIR_OPT__BIDIRECTIONAL  "<>"
143 
144 /* For user defined rule type */
145 #define RULE_TYPE_OPT__TYPE    "type"
146 
147 /* Rule options
148  * Only the basic ones are here.  The detection options and preprocessor
149  * detection options define their own */
150 #define RULE_OPT__CLASSTYPE         "classtype"
151 #define RULE_OPT__DETECTION_FILTER  "detection_filter"
152 #define RULE_OPT__GID               "gid"
153 #define RULE_OPT__MSG               "msg"
154 #define RULE_OPT__METADATA          "metadata"
155 #define RULE_OPT__LOGTO             "logto"
156 #define RULE_OPT__PRIORITY          "priority"
157 #define RULE_OPT__REFERENCE         "reference"
158 #define RULE_OPT__REVISION          "rev"
159 #define RULE_OPT__SID               "sid"
160 #define RULE_OPT__TAG               "tag"
161 #define RULE_OPT__THRESHOLD         "threshold"
162 
163 /* Metadata rule option keys */
164 #define METADATA_KEY__ENGINE         "engine"
165 #define METADATA_KEY__OS             "os"
166 #define METADATA_KEY__RULE_FLUSHING  "rule-flushing"
167 #define METADATA_KEY__RULE_TYPE      "rule-type"
168 #define METADATA_KEY__SOID           "soid"
169 #define METADATA_KEY__SERVICE        "service"
170 
171 /* Metadata rule option values */
172 #define METADATA_VALUE__DECODE    "decode"
173 #define METADATA_VALUE__DETECT    "detect"
174 #define METADATA_VALUE__DISABLED  "disabled"
175 #define METADATA_VALUE__ENABLED   "enabled"
176 #define METADATA_VALUE__OFF       "off"
177 #define METADATA_VALUE__ON        "on"
178 #define METADATA_VALUE__PREPROC   "preproc"
179 #define METADATA_VALUE__SHARED    "shared"
180 
181 /* MPLS payload types */
182 #ifdef MPLS
183 # define MPLS_PAYLOAD_OPT__IPV4      "ipv4"
184 # define MPLS_PAYLOAD_OPT__IPV6      "ipv6"
185 # define MPLS_PAYLOAD_OPT__ETHERNET  "ethernet"
186 #endif
187 
188 /* Tag options */
189 #define TAG_OPT__BYTES     "bytes"
190 #define TAG_OPT__DST       "dst"
191 #define TAG_OPT__HOST      "host"
192 #define TAG_OPT__PACKETS   "packets"
193 #define TAG_OPT__SECONDS   "seconds"
194 #define TAG_OPT__SESSION   "session"
195 #define TAG_OPT__SRC       "src"
196 #define TAG_OPT__EXCLUSIVE "exclusive"
197 
198 /* Dynamic library specifier option values */
199 #define DYNAMIC_LIB_OPT__FILE       "file"
200 #define DYNAMIC_LIB_OPT__DIRECTORY  "directory"
201 
202 /* Threshold options */
203 #define THRESHOLD_OPT__COUNT    "count"
204 #define THRESHOLD_OPT__GID      "gen_id"
205 #define THRESHOLD_OPT__IP       "ip"
206 #define THRESHOLD_OPT__SECONDS  "seconds"
207 #define THRESHOLD_OPT__SID      "sig_id"
208 #define THRESHOLD_OPT__TRACK    "track"
209 #define THRESHOLD_OPT__TYPE     "type"
210 
211 #define THRESHOLD_TYPE__BOTH       "both"
212 #define THRESHOLD_TYPE__LIMIT      "limit"
213 #define THRESHOLD_TYPE__THRESHOLD  "threshold"
214 
215 #define THRESHOLD_TRACK__BY_DST    "by_dst"
216 #define THRESHOLD_TRACK__BY_SRC    "by_src"
217 
218 #define RULE_STATE_OPT__DISABLED   "disabled"
219 #define RULE_STATE_OPT__ENABLED    "enabled"
220 
221 #define DETECTION_OPT__BLEEDOVER_PORT_LIMIT                  "bleedover-port-limit"
222 #define DETECTION_OPT__BLEEDOVER_WARNINGS_ENABLED            "bleedover-warnings-enabled"
223 #define DETECTION_OPT__DEBUG                                 "debug"
224 #define DETECTION_OPT__DEBUG_PRINT_NOCONTENT_RULE_TESTS      "debug-print-nocontent-rule-tests"
225 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUP_BUILD_DETAILS  "debug-print-rule-group-build-details"
226 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_UNCOMPILED    "debug-print-rule-groups-uncompiled"
227 #define DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_COMPILED      "debug-print-rule-groups-compiled"
228 #define DETECTION_OPT__ENABLE_SINGLE_RULE_GROUP              "enable-single-rule-group"
229 #define DETECTION_OPT__MAX_QUEUE_EVENTS                      "max_queue_events"
230 #define DETECTION_OPT__NO_STREAM_INSERTS                     "no_stream_inserts"
231 #define DETECTION_OPT__SEARCH_METHOD                         "search-method"
232 #define DETECTION_OPT__SEARCH_OPTIMIZE                       "search-optimize"
233 #define DETECTION_OPT__SPLIT_ANY_ANY                         "split-any-any"
234 #define DETECTION_OPT__MAX_PATTERN_LEN                       "max-pattern-len"
235 #define DETECTION_OPT__DEBUG_PRINT_FAST_PATTERN              "debug-print-fast-pattern"
236 
237 /* Protected Content options  - there should be a better way instead of declaring the type strings here */
238 #define PROTECTED_CONTENT_OPT__HASH_TYPE         "hash"
239 #define EVENT_QUEUE_OPT__LOG                 "log"
240 #define EVENT_QUEUE_OPT__MAX_QUEUE           "max_queue"
241 #define EVENT_QUEUE_OPT__ORDER_EVENTS        "order_events"
242 #define EVENT_QUEUE_OPT__PROCESS_ALL_EVENTS  "process_all_events"
243 
244 #define EVENT_TRACE_OPT__FILE                "file"
245 #define EVENT_TRACE_OPT__MAX_DATA            "max_data"
246 #define EVENT_TRACE_OPT__FILE_DEFAULT        "event_trace.txt"
247 #define EVENT_TRACE_OPT__MAX_DATA_DEFAULT    64
248 
249 #define ORDER_EVENTS_OPT__CONTENT_LENGTH   "content_length"
250 #define ORDER_EVENTS_OPT__PRIORITY         "priority"
251 
252 #define THRESHOLD_OPT__MEMCAP   "memcap"
253 
254 #define CHECKSUM_MODE_OPT__ALL      "all"
255 #define CHECKSUM_MODE_OPT__NONE     "none"
256 #define CHECKSUM_MODE_OPT__IP       "ip"
257 #define CHECKSUM_MODE_OPT__NO_IP    "noip"
258 #define CHECKSUM_MODE_OPT__TCP      "tcp"
259 #define CHECKSUM_MODE_OPT__NO_TCP   "notcp"
260 #define CHECKSUM_MODE_OPT__UDP      "udp"
261 #define CHECKSUM_MODE_OPT__NO_UDP   "noudp"
262 #define CHECKSUM_MODE_OPT__ICMP     "icmp"
263 #define CHECKSUM_MODE_OPT__NO_ICMP  "noicmp"
264 
265 #define RULE_STATE_OPT__DISABLED  "disabled"
266 #define RULE_STATE_OPT__ENABLED   "enabled"
267 
268 #define POLICY_MODE_PASSIVE     "tap"
269 #define POLICY_MODE_INLINE      "inline"
270 #define POLICY_MODE_INLINE_TEST "inline_test"
271 
272 #ifdef PERF_PROFILING
273 # define PROFILE_OPT__FILENAME                "filename"
274 # define PROFILE_OPT__PRINT                   "print"
275 # define PROFILE_OPT__ALL                     "all"
276 # define PROFILE_OPT__SORT                    "sort"
277 # define PROFILE_OPT__CHECKS                  "checks"
278 # define PROFILE_OPT__AVG_TICKS               "avg_ticks"
279 # define PROFILE_OPT__TOTAL_TICKS             "total_ticks"
280 # define PROFILE_OPT__MATCHES                 "matches"
281 # define PROFILE_OPT__NO_MATCHES              "nomatches"
282 # define PROFILE_OPT__AVG_TICKS_PER_MATCH     "avg_ticks_per_match"
283 # define PROFILE_OPT__AVG_TICKS_PER_NO_MATCH  "avg_ticks_per_nomatch"
284 # define PROFILE_OPT__APPEND                  "append"
285 #endif
286 
287 #ifdef PPM_MGR
288 # define PPM_OPT__MAX_PKT_TIME         "max-pkt-time"
289 # define PPM_OPT__MAX_RULE_TIME        "max-rule-time"
290 # define PPM_OPT__SUSPEND_TIMEOUT      "suspend-timeout"
291 # define PPM_OPT__SUSPEND_EXP_RULES    "suspend-expensive-rules"
292 # define PPM_OPT__THRESHOLD            "threshold"
293 # define PPM_OPT__FAST_PATH_EXP_PKTS   "fastpath-expensive-packets"
294 # define PPM_OPT__PKT_LOG              "pkt-log"
295 # define PPM_OPT__RULE_LOG             "rule-log"
296 # define PPM_OPT__ALERT                "alert"
297 # define PPM_OPT__LOG                  "log"
298 # define PPM_OPT__DEBUG_PKTS           "debug-pkts"
299 #endif
300 
301 #ifdef ACTIVE_RESPONSE
302 #define RESPONSE_OPT__ATTEMPTS  "attempts"
303 #define RESPONSE_OPT__DEVICE    "device"
304 #define RESPONSE_OPT__DST_MAC   "dst_mac"
305 #endif
306 
307 #define ERR_PAIR_COUNT \
308     "%s has incorrect argument count; should be %d pairs.", ERR_KEY
309 #define ERR_NOT_PAIRED \
310     "%s is missing an option or argument to go with: %s.", ERR_KEY, pairs[0]
311 #define ERR_EXTRA_OPTION \
312     "%s has extra option of type: %s.", ERR_KEY, pairs[0]
313 #define ERR_BAD_OPTION \
314     "%s has unknown option: %s.", ERR_KEY, pairs[0]
315 #define ERR_BAD_VALUE \
316     "%s has unknown %s: %s.", ERR_KEY, pairs[0], pairs[1]
317 #define ERR_BAD_ARG_COUNT \
318     "%s has incorrect argument count.", ERR_KEY
319 #define ERR_CREATE \
320     "%s could not be created.", ERR_KEY
321 #define ERR_CREATE_EX \
322     "%s could not be created: %s.", ERR_KEY
323 
324 // arbitrary conf file name used to allow initialization w/o conf
325 // (required for packet logging mode)
326 #define NULL_CONF "null"
327 
328 /* Data types *****************************************************************/
329 typedef void (*ParseFunc)(SnortConfig *, SnortPolicy *, char *);
330 typedef void (*ParseConfigFunc)(SnortConfig *, char *);
331 typedef void (*ParseRuleOptFunc)(SnortConfig *, RuleTreeNode *, OptTreeNode *, RuleType, char *);
332 
333 /* Used to determine whether or not to parse the keyword line based on
334  * whether or not we're parsing rules */
335 typedef enum _KeywordType
336 {
337     KEYWORD_TYPE__MAIN,
338     KEYWORD_TYPE__RULE,
339     KEYWORD_TYPE__ALL
340 
341 } KeywordType;
342 
343 typedef enum _VarType
344 {
345     VAR_TYPE__DEFAULT,
346     VAR_TYPE__PORTVAR,
347     VAR_TYPE__IPVAR
348 
349 } VarType;
350 
351 typedef struct _KeywordFunc
352 {
353     char *name;
354     KeywordType type;
355     int expand_vars;
356     int default_policy_only;
357     ParseFunc parse_func;
358 
359 } KeywordFunc;
360 
361 typedef struct _RuleOptFunc
362 {
363     char *name;
364     int args_required;
365     int only_once;
366     int detection;
367     ParseRuleOptFunc parse_func;
368 
369 } RuleOptFunc;
370 
371 typedef struct _ConfigFunc
372 {
373     char *name;
374     int args_required;
375     int only_once;
376     int default_policy_only;
377     ParseConfigFunc parse_func;
378 
379 } ConfigFunc;
380 
381 /* Tracking the port_list_t structure for printing and debugging at
382  * this point...temporarily... */
383 typedef struct
384 {
385     int rule_type;
386     int proto;
387     int icmp_type;
388     int ip_proto;
389     char *protocol;
390     char *src_port;
391     char *dst_port;
392     unsigned int gid;
393     unsigned int sid;
394     int dir;
395     char content;
396     char uricontent;
397 
398 } port_entry_t;
399 
400 typedef struct
401 {
402     int pl_max;
403     int pl_cnt;
404     port_entry_t pl_array[MAX_RULE_COUNT];
405 
406 } port_list_t;
407 
408 /* rule counts for port lists */
409 typedef struct
410 {
411     int src;
412     int dst;
413     int aa;  /* any-any */
414     int sd;  /* src+dst ports specified */
415     int nc;  /* no content */
416 
417 } rule_count_t;
418 
419 
420 /* Externs ********************************************************************/
421 extern VarNode *cmd_line_var_list;
422 extern char *snort_conf_file;
423 extern char *snort_conf_dir;
424 extern RuleOptConfigFuncNode *rule_opt_config_funcs;
425 
426 /* Globals ********************************************************************/
427 
428 char *file_name = NULL;   /* current config file being processed */
429 int file_line = 0;        /* current line being processed in the file */
430 
431 /* Main parsing function uses this to indicate whether or not
432  * rules are to be parsed. */
433 static int parse_rules = 0;
434 
435 /* Used when parsing rule options and a threshold is used.  Need to add
436  * sid and gid to threshold object and they might not have been
437  * parsed yet. */
438 static THDX_STRUCT *thdx_tmp = NULL;
439 
440 int rule_count = 0;          /* number of rules generated */
441 int detect_rule_count = 0;   /* number of detection rules generated */
442 int decode_rule_count = 0;   /* number of decoder rules generated */
443 int preproc_rule_count = 0;  /* number of preprocessor rules generated */
444 int head_count = 0;          /* number of header blocks (chain heads?) */
445 int otn_count = 0;           /* number of chains */
446 
447 static port_list_t port_list;
448 
449 static rule_count_t tcpCnt;
450 static rule_count_t udpCnt;
451 static rule_count_t icmpCnt;
452 static rule_count_t ipCnt;
453 
454 rule_index_map_t *ruleIndexMap = NULL;   /* rule index -> sid:gid map */
455 
456 static void ParseAlert(SnortConfig *, SnortPolicy *, char *);
457 static void ParseDrop(SnortConfig *, SnortPolicy *, char *);
458 static void ParseLog(SnortConfig *, SnortPolicy *, char *);
459 static void ParsePass(SnortConfig *, SnortPolicy *, char *);
460 static void ParseReject(SnortConfig *, SnortPolicy *, char *);
461 static void ParseSdrop(SnortConfig *, SnortPolicy *, char *);
462 
463 #ifdef TARGET_BASED
464 static void ParseAttributeTable(SnortConfig *, SnortPolicy *, char *);
465 #endif  /* TARGET_BASED */
466 static void ParseConfig(SnortConfig *, SnortPolicy *, char *);
467 static void ParseDynamicDetectionInfo(SnortConfig *, SnortPolicy *, char *);
468 static void ParseDynamicEngineInfo(SnortConfig *, SnortPolicy *, char *);
469 static void ParseDynamicPreprocessorInfo(SnortConfig *, SnortPolicy *, char *);
470 # ifdef SIDE_CHANNEL
471 static void ParseDynamicSideChannelInfo(SnortConfig *, SnortPolicy *, char *);
472 # endif /* SIDE_CHANNEL */
473 static void ParseDynamicOutputInfo(SnortConfig *, SnortPolicy *, char *);
474 static void ParseEventFilter(SnortConfig *, SnortPolicy *, char *);
475 static void ParseInclude(SnortConfig *, SnortPolicy *, char *);
476 static void ParseIpVar(SnortConfig *, SnortPolicy *, char *);
477 static void ParsePortVar(SnortConfig *, SnortPolicy *, char *);
478 static void ParsePreprocessor(SnortConfig *, SnortPolicy *, char *);
479 static void ParseRateFilter(SnortConfig *, SnortPolicy *, char *);
480 static void ParseRuleState(SnortConfig *, SnortPolicy *, char *);
481 static void ParseRuleTypeDeclaration(SnortConfig *, SnortPolicy *, char *);
482 #ifdef SIDE_CHANNEL
483 static void ParseSideChannelModule(SnortConfig *, SnortPolicy *, char *);
484 static void ConfigSideChannel(SnortConfig *, char *);
485 #endif /* SIDE_CHANNEL */
486 static void ParseSuppress(SnortConfig *, SnortPolicy *, char *);
487 static void ParseThreshold(SnortConfig *, SnortPolicy *, char *);
488 static void ParseVar(SnortConfig *, SnortPolicy *, char *);
489 static void ParseFile(SnortConfig *, SnortPolicy *, char *);
490 static void AddVarToTable(SnortConfig *, char *, char *);
491 
492 int ParseBool(char *arg);
493 
494 static const KeywordFunc snort_conf_keywords[] =
495 {
496     /* Rule keywords */
497     { SNORT_CONF_KEYWORD__ALERT,    KEYWORD_TYPE__RULE, 0, 0, ParseAlert },
498     { SNORT_CONF_KEYWORD__DROP,     KEYWORD_TYPE__RULE, 0, 0, ParseDrop },
499     { SNORT_CONF_KEYWORD__BLOCK,    KEYWORD_TYPE__RULE, 0, 0, ParseDrop },
500     { SNORT_CONF_KEYWORD__LOG,      KEYWORD_TYPE__RULE, 0, 0, ParseLog },
501     { SNORT_CONF_KEYWORD__PASS,     KEYWORD_TYPE__RULE, 0, 0, ParsePass },
502     { SNORT_CONF_KEYWORD__REJECT,   KEYWORD_TYPE__RULE, 0, 0, ParseReject },
503     { SNORT_CONF_KEYWORD__SDROP,    KEYWORD_TYPE__RULE, 0, 0, ParseSdrop },
504     { SNORT_CONF_KEYWORD__SBLOCK,   KEYWORD_TYPE__RULE, 0, 0, ParseSdrop },
505 
506     /* Non-rule keywords */
507 #ifdef TARGET_BASED
508     /* Need to fatal error if attribute_table is not configured in default
509      * policy.  Since we're just skipping configuring non-default
510      * configurations with default only configuration types, set this to
511      * be configured for non-default policies and fatal in function */
512     { SNORT_CONF_KEYWORD__ATTRIBUTE_TABLE,   KEYWORD_TYPE__MAIN, 1, 0, ParseAttributeTable },
513 #endif
514     { SNORT_CONF_KEYWORD__CONFIG,            KEYWORD_TYPE__MAIN, 1, 0, ParseConfig },
515     { SNORT_CONF_KEYWORD__DYNAMIC_OUTPUT ,   KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicOutputInfo },
516     { SNORT_CONF_KEYWORD__DYNAMIC_DETECTION, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicDetectionInfo },
517     { SNORT_CONF_KEYWORD__DYNAMIC_ENGINE,    KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicEngineInfo },
518     { SNORT_CONF_KEYWORD__DYNAMIC_PREPROC,   KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicPreprocessorInfo },
519 #ifdef SIDE_CHANNEL
520     { SNORT_CONF_KEYWORD__DYNAMIC_SIDE_CHAN, KEYWORD_TYPE__MAIN, 1, 1, ParseDynamicSideChannelInfo },
521 #endif /* SIDE_CHANNEL */
522     { SNORT_CONF_KEYWORD__EVENT_FILTER,      KEYWORD_TYPE__MAIN, 1, 0, ParseEventFilter },
523     { SNORT_CONF_KEYWORD__INCLUDE,           KEYWORD_TYPE__ALL,  1, 0, ParseInclude },
524     { SNORT_CONF_KEYWORD__IPVAR,             KEYWORD_TYPE__MAIN, 0, 0, ParseIpVar },
525     { SNORT_CONF_KEYWORD__OUTPUT,            KEYWORD_TYPE__MAIN, 1, 1, ParseOutput },
526     { SNORT_CONF_KEYWORD__PORTVAR,           KEYWORD_TYPE__MAIN, 0, 0, ParsePortVar },
527     { SNORT_CONF_KEYWORD__PREPROCESSOR,      KEYWORD_TYPE__MAIN, 1, 0, ParsePreprocessor },
528     { SNORT_CONF_KEYWORD__RATE_FILTER,       KEYWORD_TYPE__MAIN, 0, 0, ParseRateFilter },
529     { SNORT_CONF_KEYWORD__RULE_STATE,        KEYWORD_TYPE__MAIN, 1, 0, ParseRuleState },
530     { SNORT_CONF_KEYWORD__RULE_TYPE,         KEYWORD_TYPE__ALL,  1, 0, ParseRuleTypeDeclaration },
531 #ifdef SIDE_CHANNEL
532     { SNORT_CONF_KEYWORD__SIDE_CHANNEL,      KEYWORD_TYPE__MAIN, 1, 1, ParseSideChannelModule },
533 #endif /* SIDE_CHANNEL */
534     { SNORT_CONF_KEYWORD__SUPPRESS,          KEYWORD_TYPE__MAIN, 0, 0, ParseSuppress },
535     { SNORT_CONF_KEYWORD__THRESHOLD,         KEYWORD_TYPE__MAIN, 1, 0, ParseThreshold },
536     { SNORT_CONF_KEYWORD__VAR,               KEYWORD_TYPE__MAIN, 0, 0, ParseVar },
537     { SNORT_CONF_KEYWORD__FILE,              KEYWORD_TYPE__MAIN, 0, 1, ParseFile },
538     { NULL, KEYWORD_TYPE__ALL, 0, 0, NULL }   /* Marks end of array */
539 };
540 
541 static void ParseOtnClassType(SnortConfig *, RuleTreeNode *,
542                               OptTreeNode *, RuleType, char *);
543 static void ParseOtnDetectionFilter(SnortConfig *, RuleTreeNode *,
544                                     OptTreeNode *, RuleType, char *);
545 static void ParseOtnGid(SnortConfig *, RuleTreeNode *,
546                         OptTreeNode *, RuleType, char *);
547 static void ParseOtnLogTo(SnortConfig *, RuleTreeNode *,
548                           OptTreeNode *, RuleType, char *);
549 static void ParseOtnMessage(SnortConfig *, RuleTreeNode *,
550                             OptTreeNode *, RuleType, char *);
551 static void ParseOtnMetadata(SnortConfig *, RuleTreeNode *,
552                              OptTreeNode *, RuleType, char *);
553 static void ParseOtnPriority(SnortConfig *, RuleTreeNode *,
554                              OptTreeNode *, RuleType, char *);
555 static void ParseOtnReference(SnortConfig *, RuleTreeNode *,
556                               OptTreeNode *, RuleType, char *);
557 static void ParseOtnRevision(SnortConfig *, RuleTreeNode *,
558                              OptTreeNode *, RuleType, char *);
559 static void ParseOtnSid(SnortConfig *, RuleTreeNode *,
560                         OptTreeNode *, RuleType, char *);
561 static void ParseOtnTag(SnortConfig *, RuleTreeNode *,
562                         OptTreeNode *, RuleType, char *);
563 static void ParseOtnThreshold(SnortConfig *, RuleTreeNode *,
564                               OptTreeNode *, RuleType, char *);
565 
566 static const RuleOptFunc rule_options[] =
567 {
568     { RULE_OPT__CLASSTYPE,        1, 1, 0, ParseOtnClassType },
569     { RULE_OPT__DETECTION_FILTER, 1, 1, 1, ParseOtnDetectionFilter },
570     { RULE_OPT__GID,              1, 1, 0, ParseOtnGid },
571     { RULE_OPT__LOGTO,            1, 1, 0, ParseOtnLogTo },
572     { RULE_OPT__METADATA,         1, 0, 0, ParseOtnMetadata },
573     { RULE_OPT__MSG,              1, 1, 0, ParseOtnMessage },
574     { RULE_OPT__PRIORITY,         1, 1, 0, ParseOtnPriority },
575     { RULE_OPT__REFERENCE,        1, 0, 0, ParseOtnReference },
576     { RULE_OPT__REVISION,         1, 1, 0, ParseOtnRevision },
577     { RULE_OPT__SID,              1, 1, 0, ParseOtnSid },
578     { RULE_OPT__TAG,              1, 1, 0, ParseOtnTag },
579     { RULE_OPT__THRESHOLD,        1, 1, 1, ParseOtnThreshold },
580 
581     { NULL, 0, 0, 0, NULL }   /* Marks end of array */
582 };
583 
584 #ifdef PERF_PROFILING
585 /* Internal prototypes used in lists below */
586 static void _ConfigProfilePreprocs(SnortConfig *, char *);
587 static void _ConfigProfileRules(SnortConfig *, char *);
588 #endif
589 
590 static const ConfigFunc config_opts[] =
591 {
592     { CONFIG_OPT__ALERT_FILE, 1, 1, 1, ConfigAlertFile },
593     { CONFIG_OPT__ALERT_WITH_IFACE_NAME, 0, 1, 1, ConfigAlertWithInterfaceName },
594     { CONFIG_OPT__AUTOGEN_PREPROC_DECODER_RULES, 0, 1, 0, ConfigAutogenPreprocDecoderRules },
595     { CONFIG_OPT__ASN1, 1, 1, 1, ConfigAsn1 },
596     { CONFIG_OPT__BINDING, 1, 0, 1, ConfigBinding },
597     { CONFIG_OPT__BPF_FILE, 1, 1, 1, ConfigBpfFile },
598     { CONFIG_OPT__CHECKSUM_DROP, 0, 0, 0, ConfigChecksumDrop },
599     { CONFIG_OPT__CHECKSUM_MODE, 0, 0, 0, ConfigChecksumMode },
600     { CONFIG_OPT__CHROOT_DIR, 1, 1, 1, ConfigChrootDir },
601     { CONFIG_OPT__CLASSIFICATION, 1, 0, 0, ConfigClassification },
602     { CONFIG_OPT__DAEMON, 0, 1, 1, ConfigDaemon },
603     { CONFIG_OPT__DECODE_DATA_LINK, 0, 1, 1, ConfigDecodeDataLink },
604     { CONFIG_OPT__DECODE_ESP, 0, 1, 1, ConfigEnableEspDecoding },
605     { CONFIG_OPT__DEFAULT_RULE_STATE, 0, 1, 1, ConfigDefaultRuleState },
606     { CONFIG_OPT__DETECTION, 1, 0, 1, ConfigDetection },  /* This is reconfigurable */
607     { CONFIG_OPT__DETECTION_FILTER, 1, 1, 1, ConfigDetectionFilter },
608     { CONFIG_OPT__DISABLE_DECODE_ALERTS, 0, 1, 0, ConfigDisableDecodeAlerts },
609     { CONFIG_OPT__DISABLE_DECODE_DROPS, 0, 1, 0, ConfigDisableDecodeDrops },
610 #ifdef INLINE_FAILOPEN
611     { CONFIG_OPT__DISABLE_INLINE_FAILOPEN, 0, 1, 1, ConfigDisableInlineFailopen },
612 #endif
613     { CONFIG_OPT__DISABLE_IP_OPT_ALERTS, 0, 1, 0, ConfigDisableIpOptAlerts },
614     { CONFIG_OPT__DISABLE_IP_OPT_DROPS, 0, 1, 0, ConfigDisableIpOptDrops },
615     { CONFIG_OPT__DISABLE_TCP_OPT_ALERTS, 0, 1, 0, ConfigDisableTcpOptAlerts },
616     { CONFIG_OPT__DISABLE_TCP_OPT_DROPS, 0, 1, 0, ConfigDisableTcpOptDrops },
617     { CONFIG_OPT__DISABLE_TCP_OPT_EXP_ALERTS, 0, 1, 0, ConfigDisableTcpOptExperimentalAlerts },
618     { CONFIG_OPT__DISABLE_TCP_OPT_EXP_DROPS, 0, 1, 0, ConfigDisableTcpOptExperimentalDrops },
619     { CONFIG_OPT__DISABLE_TCP_OPT_OBS_ALERTS, 0, 1, 0, ConfigDisableTcpOptObsoleteAlerts },
620     { CONFIG_OPT__DISABLE_TCP_OPT_OBS_DROPS, 0, 1, 0, ConfigDisableTcpOptObsoleteDrops },
621     { CONFIG_OPT__DISABLE_TTCP_ALERTS, 0, 1, 0, ConfigDisableTTcpAlerts },
622     { CONFIG_OPT__DISABLE_TCP_OPT_TTCP_ALERTS, 0, 1, 0, ConfigDisableTTcpAlerts },
623     { CONFIG_OPT__DISABLE_TTCP_DROPS, 0, 1, 0, ConfigDisableTTcpDrops },
624     { CONFIG_OPT__DUMP_CHARS_ONLY, 0, 1, 1, ConfigDumpCharsOnly },
625     { CONFIG_OPT__DUMP_PAYLOAD, 0, 1, 1, ConfigDumpPayload },
626     { CONFIG_OPT__DUMP_PAYLOAD_VERBOSE, 0, 1, 1, ConfigDumpPayloadVerbose },
627     { CONFIG_OPT__ENABLE_DECODE_DROPS, 0, 1, 0, ConfigEnableDecodeDrops },
628     { CONFIG_OPT__ENABLE_DECODE_OVERSIZED_ALERTS, 0, 1, 0, ConfigEnableDecodeOversizedAlerts },
629     { CONFIG_OPT__ENABLE_DECODE_OVERSIZED_DROPS, 0, 1, 0, ConfigEnableDecodeOversizedDrops },
630     { CONFIG_OPT__ENABLE_DEEP_TEREDO_INSPECTION, 0, 1, 1, ConfigEnableDeepTeredoInspection },
631     { CONFIG_OPT__ENABLE_GTP_DECODING, 0, 1, 1, ConfigEnableGTPDecoding },
632     { CONFIG_OPT__ENABLE_IP_OPT_DROPS, 0, 1, 1, ConfigEnableIpOptDrops },
633 #ifdef MPLS
634     { CONFIG_OPT__ENABLE_MPLS_MULTICAST, 0, 1, 1, ConfigEnableMplsMulticast },
635     { CONFIG_OPT__ENABLE_MPLS_OVERLAPPING_IP, 0, 1, 1, ConfigEnableMplsOverlappingIp },
636 #endif
637     { CONFIG_OPT__ENABLE_TCP_OPT_DROPS, 0, 1, 0, ConfigEnableTcpOptDrops },
638     { CONFIG_OPT__ENABLE_TCP_OPT_EXP_DROPS, 0, 1, 0, ConfigEnableTcpOptExperimentalDrops },
639     { CONFIG_OPT__ENABLE_TCP_OPT_OBS_DROPS, 0, 1, 0, ConfigEnableTcpOptObsoleteDrops },
640     { CONFIG_OPT__ENABLE_TTCP_DROPS, 0, 1, 0, ConfigEnableTTcpDrops },
641     { CONFIG_OPT__ENABLE_TCP_OPT_TTCP_DROPS, 0, 1, 0, ConfigEnableTTcpDrops },
642     { CONFIG_OPT__EVENT_FILTER, 1, 1, 1, ConfigEventFilter },
643     { CONFIG_OPT__EVENT_QUEUE, 1, 1, 1, ConfigEventQueue },
644     { CONFIG_OPT__EVENT_TRACE, 0, 1, 1, ConfigEventTrace },
645     { CONFIG_OPT__REACT, 1, 1, 1, ConfigReact },
646 #ifdef ENABLE_RESPONSE3
647     { CONFIG_OPT__FLEXRESP2_INTERFACE, 1, 1, 1, ConfigFlexresp2Interface },
648     { CONFIG_OPT__FLEXRESP2_ATTEMPTS, 1, 1, 1, ConfigFlexresp2Attempts },
649     { CONFIG_OPT__FLEXRESP2_MEMCAP, 1, 1, 1, ConfigFlexresp2Memcap },
650     { CONFIG_OPT__FLEXRESP2_ROWS, 1, 1, 1, ConfigFlexresp2Rows },
651 #endif
652 #ifdef ACTIVE_RESPONSE
653     { CONFIG_OPT__RESPONSE, 1, 1, 1, ConfigResponse },
654 #endif
655     { CONFIG_OPT__FLOWBITS_SIZE, 1, 1, 1, ConfigFlowbitsSize },
656     { CONFIG_OPT__IGNORE_PORTS, 1, 0, 1, ConfigIgnorePorts },
657     { CONFIG_OPT__ALERT_VLAN, 0, 1, 1, ConfigIncludeVlanInAlert },
658     { CONFIG_OPT__INTERFACE, 1, 1, 1, ConfigInterface },
659     { CONFIG_OPT__IPV6_FRAG, 1, 1, 1, ConfigIpv6Frag },
660     { CONFIG_OPT__LAYER2RESETS, 1, 1, 1, ConfigLayer2Resets },
661     { CONFIG_OPT__LOG_DIR, 1, 1, 1, ConfigLogDir },
662     { CONFIG_OPT__DAQ_TYPE, 1, 1, 1, ConfigDaqType },
663     { CONFIG_OPT__DAQ_MODE, 1, 1, 1, ConfigDaqMode },
664     { CONFIG_OPT__DAQ_VAR, 1, 0, 1, ConfigDaqVar },
665     { CONFIG_OPT__DAQ_DIR, 1, 0, 1, ConfigDaqDir },
666     { CONFIG_OPT__DIRTY_PIG, 0, 1, 1, ConfigDirtyPig },
667 #ifdef TARGET_BASED
668     { CONFIG_OPT__MAX_ATTRIBUTE_HOSTS, 1, 1, 1, ConfigMaxAttributeHosts },
669     { CONFIG_OPT__MAX_ATTRIBUTE_SERVICES_PER_HOST, 1, 1, 1, ConfigMaxAttributeServicesPerHost },
670     { CONFIG_OPT__MAX_METADATA_SERVICES, 1, 1, 1, ConfigMaxMetadataServices },
671     { CONFIG_OPT__DISABLE_ATTRIBUTE_RELOAD, 0, 1, 1, ConfigDisableAttributeReload },
672 #endif
673 #ifdef MPLS
674     { CONFIG_OPT__MAX_MPLS_LABELCHAIN_LEN, 0, 1, 1, ConfigMaxMplsLabelChain },
675     { CONFIG_OPT__MPLS_PAYLOAD_TYPE, 0, 1, 1, ConfigMplsPayloadType },
676 #endif
677     { CONFIG_OPT__MIN_TTL, 1, 1, 0, ConfigMinTTL },
678 #ifdef NORMALIZER
679     { CONFIG_OPT__NEW_TTL, 1, 1, 0, ConfigNewTTL },
680 #endif
681     { CONFIG_OPT__NO_LOG, 0, 1, 1, ConfigNoLog },
682     { CONFIG_OPT__NO_PCRE, 0, 1, 1, ConfigNoPcre },
683     { CONFIG_OPT__NO_PROMISCUOUS, 0, 1, 1, ConfigNoPromiscuous },
684     { CONFIG_OPT__OBFUSCATE, 0, 1, 1, ConfigObfuscate },
685     { CONFIG_OPT__ORDER, 1, 1, 1, ConfigRuleListOrder },
686     { CONFIG_OPT__PAF_MAX, 1, 1, 0, ConfigPafMax },
687     { CONFIG_OPT__PKT_COUNT, 1, 1, 1, ConfigPacketCount },
688     { CONFIG_OPT__PKT_SNAPLEN, 1, 1, 1, ConfigPacketSnaplen },
689     { CONFIG_OPT__PCRE_MATCH_LIMIT, 1, 1, 1, ConfigPcreMatchLimit },
690     { CONFIG_OPT__PCRE_MATCH_LIMIT_RECURSION, 1, 1, 1, ConfigPcreMatchLimitRecursion },
691     /* XXX We can configure this on the command line - why not in config file ??? */
692 #ifdef NOT_UNTIL_WE_DAEMONIZE_AFTER_READING_CONFFILE
693     { CONFIG_OPT__PID_PATH, 1, 1, 1, ConfigPidPath },
694 #endif
695     { CONFIG_OPT__POLICY, 1, 1, 0, ConfigPolicy },
696     { CONFIG_OPT__IPS_POLICY_MODE, 1, 1, 0, ConfigIpsPolicyMode },
697     { CONFIG_OPT__NAP_POLICY_MODE, 1, 1, 0, ConfigNapPolicyMode },
698     { CONFIG_OPT__POLICY_VERSION , 1, 0, 0, ConfigPolicyVersion },
699     { CONFIG_OPT__PROTECTED_CONTENT , 1, 0, 0, ConfigProtectedContent },
700 #ifdef PPM_MGR
701     { CONFIG_OPT__PPM, 1, 0, 1, ConfigPPM },
702 #endif
703 #ifdef PERF_PROFILING
704     { CONFIG_OPT__PROFILE_PREPROCS, 0, 1, 1, _ConfigProfilePreprocs },
705     { CONFIG_OPT__PROFILE_RULES, 0, 1, 1, _ConfigProfileRules },
706 #endif
707     { CONFIG_OPT__QUIET, 0, 1, 1, ConfigQuiet },
708     { CONFIG_OPT__RATE_FILTER, 1, 1, 1, ConfigRateFilter },
709     { CONFIG_OPT__REFERENCE, 1, 0, 1, ConfigReference },
710     { CONFIG_OPT__REFERENCE_NET, 1, 1, 1, ConfigReferenceNet },
711     { CONFIG_OPT__SET_GID, 1, 1, 1, ConfigSetGid },
712     { CONFIG_OPT__SET_UID, 1, 1, 1, ConfigSetUid },
713     { CONFIG_OPT__SHOW_YEAR, 0, 1, 1, ConfigShowYear },
714     { CONFIG_OPT__SO_RULE_MEMCAP, 1, 1, 1, ConfigSoRuleMemcap },
715     { CONFIG_OPT__STATEFUL, 0, 1, 1, ConfigStateful },
716     { CONFIG_OPT__TAGGED_PACKET_LIMIT, 1, 1, 1, ConfigTaggedPacketLimit },
717     { CONFIG_OPT__THRESHOLD, 1, 1, 1, ConfigThreshold },
718     { CONFIG_OPT__UMASK, 1, 1, 1, ConfigUmask },
719     { CONFIG_OPT__UTC, 0, 1, 1, ConfigUtc },
720     { CONFIG_OPT__VERBOSE, 0, 1, 1, ConfigVerbose },
721     { CONFIG_OPT__VLAN_AGNOSTIC, 0, 1, 1, ConfigVlanAgnostic },
722     { CONFIG_OPT__ADDRESSSPACE_AGNOSTIC, 0, 1, 1, ConfigAddressSpaceAgnostic },
723     { CONFIG_OPT__LOG_IPV6_EXTRA, 0, 1, 1, ConfigLogIPv6Extra },
724     { CONFIG_OPT__DUMP_DYNAMIC_RULES_PATH, 1, 1, 1, ConfigDumpDynamicRulesPath },
725     { CONFIG_OPT__CONTROL_SOCKET_DIR, 1, 1, 1, ConfigControlSocketDirectory },
726     { CONFIG_OPT__FILE, 1, 1, 1, ConfigFile },
727     { CONFIG_OPT__TUNNEL_BYPASS, 1, 1, 1, ConfigTunnelVerdicts },
728 #ifdef SIDE_CHANNEL
729     { CONFIG_OPT__SIDE_CHANNEL, 0, 1, 1, ConfigSideChannel },
730 #endif
731     { CONFIG_OPT__MAX_IP6_EXTENSIONS, 1, 1, 1, ConfigMaxIP6Extensions },
732     { CONFIG_OPT__DISABLE_REPLACE, 0, 1, 0, ConfigDisableReplace },
733 #ifdef DUMP_BUFFER
734     { CONFIG_OPT__BUFFER_DUMP, 1, 1, 1, ConfigBufferDump },
735     { CONFIG_OPT__BUFFER_DUMP_ALERT, 1, 1, 1, ConfigBufferDump },
736 #endif
737     { NULL, 0, 0, 0, NULL }   /* Marks end of array */
738 };
739 
740 /* Used to determine if a config option has already been configured
741  * Gets zeroed when initially parsing a configuration file, then each
742  * index gets set to 1 as an option is configured.  Maps to config_opts */
743 static uint8_t config_opt_configured[sizeof(config_opts) / sizeof(ConfigFunc)];
744 
745 
746 /* Private function prototypes ************************************************/
747 static void InitVarTables(SnortPolicy *);
748 static void InitPolicyMode(SnortPolicy *);
749 static void InitParser(void);
750 static int VarIsIpAddr(vartable_t *, char *);
751 static RuleType GetRuleType(char *);
752 static void CreateDefaultRules(SnortConfig *);
753 static void ParseConfigFile(SnortConfig *, SnortPolicy *, char *);
754 static int ValidateUserDefinedRuleType(SnortConfig *, char *);
755 static void IntegrityCheckRules(SnortConfig *);
756 static void ParseDynamicLibInfo(DynamicLibInfo *, char *);
757 static int GetRuleProtocol(char *);
758 static RuleTreeNode * ProcessHeadNode(SnortConfig *, RuleTreeNode *, ListHead *);
759 static int ContinuationCheck(char *);
760 static ListHead * CreateRuleType(SnortConfig *, char *, RuleType, int, ListHead *);
761 static int GetChecksumFlags(char *);
762 static int GetPolicyMode(char *,int );
763 static void OtnInit(SnortConfig *);
764 static void _ParseRuleTypeDeclaration(SnortConfig *, FILE *, char *, int);
765 static void printRuleListOrder(RuleListNode *);
766 static RuleListNode * addNodeToOrderedList(RuleListNode *, RuleListNode *, int);
767 static VarEntry * VarDefine(SnortConfig *, char *, char *);
768 static char * VarSearch(SnortConfig *, char *);
769 static char * ExpandVars(SnortConfig *, char *);
770 static VarEntry * VarAlloc(void);
771 static int ParsePort(SnortConfig *, char *, uint16_t *, uint16_t *, char *, int *);
772 static uint16_t ConvPort(char *, char *);
773 static char * ReadLine(FILE *);
774 static void DeleteVars(VarEntry *);
775 static int ValidateIPList(IpAddrSet *, char *);
776 static int PortVarDefine(SnortConfig *, char *, char *);
777 static void port_entry_free(port_entry_t *);
778 static int port_list_add_entry(port_list_t *, port_entry_t *);
779 #if 0
780 static port_entry_t * port_list_get(port_list_t *, int);
781 static void port_list_print(port_list_t *);
782 #endif
783 static void port_list_free(port_list_t *);
784 static void finish_portlist_table(FastPatternConfig *, char *, PortTable *);
785 static void PortTablesFinish(rule_port_tables_t *, FastPatternConfig *);
786 static rule_port_tables_t * PortTablesNew(void);
787 static int FinishPortListRule(rule_port_tables_t *, RuleTreeNode *, OptTreeNode *,
788                               int, port_entry_t *, FastPatternConfig *);
789 static PortObject * ParsePortListTcpUdpPort(PortVarTable *, PortTable *, char *);
790 static int ParsePortList(RuleTreeNode *, PortVarTable *, PortTable *, char *, int, int);
791 static void ParseRule(SnortConfig *, SnortPolicy *, char *, RuleType, ListHead *);
792 static void TransferOutputConfigs(OutputConfig *, OutputConfig **);
793 static OutputConfig * DupOutputConfig(OutputConfig *);
794 static void RemoveOutputConfigs(OutputConfig **, int);
795 static void XferHeader(RuleTreeNode *, RuleTreeNode *);
796 static OptTreeNode * ParseRuleOptions(SnortConfig *, RuleTreeNode **,
797                                       char *, RuleType, int);
798 #ifndef SOURCEFIRE
799 static void DefineAllIfaceVars(SnortConfig *);
800 static void DefineIfaceVar(SnortConfig *, char *, uint8_t *, uint8_t *);
801 #endif
802 
803 #ifdef DEBUG_MSGS
804 #if 0
805 static void DumpList(IpAddrNode *, int);
806 #endif
807 static void DumpChain(char *, int, int);
808 static void DumpRuleChains(RuleListNode *);
809 #endif
810 static int ProcessIP(SnortConfig *, char *, RuleTreeNode *, int, int);
811 static int TestHeader(RuleTreeNode *, RuleTreeNode *);
812 static void FreeRuleTreeNode(RuleTreeNode *rtn);
813 static void DestroyRuleTreeNode(RuleTreeNode *rtn);
814 static void AddrToFunc(RuleTreeNode *, int);
815 static void PortToFunc(RuleTreeNode *, int, int, int);
816 static void SetupRTNFuncList(RuleTreeNode *);
817 static void DisallowCrossTableDuplicateVars(SnortConfig *, char *, VarType);
818 static int mergeDuplicateOtn(SnortConfig *, OptTreeNode *, OptTreeNode *, RuleTreeNode *);
819 #if 0
820 #ifdef DEBUG_MSGS
821 static void PrintRtnPorts(RuleTreeNode *);
822 #endif
823 #endif
824 
825 static void FreeRuleTreeNodes(SnortConfig *);
826 static void FreeOutputLists(ListHead *list);
827 
828 static int ParseNetworkBindingLine(tSfPolicyConfig *, int, char **, char *);
829 static int ParseVlanBindingLine(tSfPolicyConfig *, int, char **, char *);
830 static int ParsePolicyIdBindingLine(tSfPolicyConfig *, int, char **, char *);
831 
832 static RuleTreeNode * findHeadNode(SnortConfig *, RuleTreeNode *, tSfPolicyId);
833 static inline RuleTreeNode * createDynamicRuleTypeRtn(SnortConfig *, RuleTreeNode *);
834 
835 // only keep drop rules
836 // if we are inline (and can actually drop),
837 // or we are going to just alert instead of drop,
838 // or we are going to ignore session data instead of drop.
839 // the alert case is tested for separately with ScTreatDropAsAlert().
ScKeepDropRules(SnortConfig * sc)840 static inline int ScKeepDropRules (SnortConfig * sc)
841 {
842     return ( ScIpsInlineModeNewConf(sc) || ScAdapterInlineModeNewConf(sc) || ScTreatDropAsIgnoreNewConf(sc) );
843 }
844 
ScLoadAsDropRules(SnortConfig * sc)845 static inline int ScLoadAsDropRules (SnortConfig * sc)
846 {
847     return ( ScIpsInlineTestModeNewConf(sc) || ScAdapterInlineTestModeNewConf(sc) );
848 }
849 
850 /****************************************************************************
851  * Function: ParseSnortConf()
852  *
853  * Read the rules file a line at a time and send each rule to the rule parser
854  * This is the first pass of the configuration file.  It parses everything
855  * except the rules.
856  *
857  * Arguments: None
858  *
859  * Returns:
860  *  SnortConfig *
861  *      An initialized and configured snort configuration struct.
862  *      This struct should be passed on the second pass of the
863  *      configuration file to parse the rules.
864  *
865  ***************************************************************************/
ParseSnortConf(void)866 SnortConfig * ParseSnortConf(void)
867 {
868     SnortConfig *sc = SnortConfNew();
869     VarNode *tmp = cmd_line_var_list;
870     tSfPolicyId policy_id;
871 
872     file_line = 0;
873     file_name = snort_conf_file ? snort_conf_file : NULL_CONF;
874 
875     InitParser();
876 
877     /* Setup the default rule action anchor points
878      * Need to do this now in case we get a user defined rule type */
879     CreateDefaultRules(sc);
880 
881     sc->port_tables = PortTablesNew();
882 
883     mpseInitSummary();
884     OtnInit(sc);
885 
886     /* Used to store "config" configurations */
887     sc->config_table = sfghash_new(20, 0, 0, free);
888     if (sc->config_table == NULL)
889     {
890         ParseError("%s(%d) No memory to create config table.\n",
891                    __FILE__, __LINE__);
892     }
893 
894     sc->fast_pattern_config = FastPatternConfigNew();
895     sc->event_queue_config = EventQueueConfigNew();
896     sc->threshold_config = ThresholdConfigNew();
897     sc->rate_filter_config = RateFilter_ConfigNew();
898     sc->detection_filter_config = DetectionFilterConfigNew();
899     sc->ip_proto_only_lists = (SF_LIST **)SnortAlloc(NUM_IP_PROTOS * sizeof(SF_LIST *));
900 
901     /* We're not going to parse rules on the first pass */
902     parse_rules = 0;
903 
904     sc->policy_config = sfPolicyInit();
905     if (sc->policy_config == NULL)
906     {
907         ParseError("No memory to create policy configuration.\n");
908     }
909 
910     /* Add the default policy */
911     policy_id = sfPolicyAdd(sc->policy_config, file_name);
912     sfSetDefaultPolicy(sc->policy_config, policy_id);
913     sfDynArrayCheckBounds((void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated);
914     sc->targeted_policies[policy_id] = SnortPolicyNew();
915     InitVarTables(sc->targeted_policies[policy_id]);
916     InitPolicyMode(sc->targeted_policies[policy_id]);
917     setParserPolicy(sc, policy_id);
918 
919 #ifndef SOURCEFIRE
920     /* If snort is not run with root privileges, no interfaces will be defined,
921      * so user beware if an iface_ADDRESS variable is used in snort.conf and
922      * snort is not run as root (even if just in read mode) */
923     DefineAllIfaceVars(sc);
924 #endif
925 
926     /* Add command line defined variables - duplicates will already
927      * have been resolved */
928     while (tmp != NULL)
929     {
930         AddVarToTable(sc, tmp->name, tmp->value);
931         tmp = tmp->next;
932     }
933 
934     /* Initialize storage space for preprocessor defined rule options */
935     sc->preproc_rule_options = PreprocessorRuleOptionsNew();
936     if (sc->preproc_rule_options == NULL)
937     {
938         ParseError("Could not allocate storage for preprocessor rule options.\n");
939     }
940 
941     if ( strcmp(file_name, NULL_CONF) )
942         ParseConfigFile(sc, sc->targeted_policies[policy_id], file_name);
943 
944     /* We've picked up any targeted policy configs at this point so
945      * it's probably okay to parse them here */
946     for (policy_id = 0;
947          policy_id < sfPolicyNumAllocated(sc->policy_config);
948          policy_id++)
949     {
950         char *fname = sfPolicyGet(sc->policy_config, policy_id);
951 
952         /* Already configured default policy */
953         if (policy_id == sfGetDefaultPolicy(sc->policy_config))
954             continue;
955 
956         if (fname != NULL)
957         {
958             sfDynArrayCheckBounds(
959                 (void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated);
960             sc->targeted_policies[policy_id] = SnortPolicyNew();
961 
962             InitVarTables(sc->targeted_policies[policy_id]);
963             InitPolicyMode(sc->targeted_policies[policy_id]);
964             setParserPolicy(sc, policy_id);
965 
966             /* Need to reset this for each targeted policy */
967             memset(config_opt_configured, 0, sizeof(config_opt_configured));
968 
969             /* Add command line defined variables - duplicates will already
970              * have been resolved */
971             tmp = cmd_line_var_list;
972             while (tmp != NULL)
973             {
974                 AddVarToTable(sc, tmp->name, tmp->value);
975                 tmp = tmp->next;
976             }
977 
978             /* Parse as include file so if the file is specified relative to
979              * the snort conf directory we'll pick it up */
980             ParseInclude(sc, sc->targeted_policies[policy_id], fname);
981         }
982     }
983 
984     /* This can be initialized now since we've picked up any user
985      * defined rules */
986     sc->omd = OtnXMatchDataNew(sc->num_rule_types);
987 
988     /* Reset these.  The only issue in not reseting would be if we were
989      * parsing a command line again, but do it anyway */
990     file_name = NULL;
991     file_line = 0;
992 
993     return sc;
994 }
995 
ParsePolicyIdBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)996 static int ParsePolicyIdBindingLine(
997         tSfPolicyConfig *config,
998         int num_toks,
999         char **toks,
1000         char *fileName
1001         )
1002 {
1003     int i;
1004     int parsedPolicyId;
1005 
1006     for (i = 0; i < num_toks; i++)
1007     {
1008         char *endp;
1009         if ( toks[i] )
1010         {
1011             errno = 0;
1012             parsedPolicyId = SnortStrtolRange(toks[i], &endp, 10, 0, USHRT_MAX);
1013             if ((errno == ERANGE) || (*endp != '\0'))
1014                 return -1;
1015 
1016             if ( sfPolicyIdAddBinding(config, parsedPolicyId, fileName) != 0)
1017             {
1018                 return -1;
1019                 //FatalError("Unable to add policy: policyId %d, file %s\n", parsedPolicyId, fileName);
1020             }
1021         }
1022         else
1023         {
1024             return -1;
1025             //FatalError("formating error in binding file: %s\n", aLine);
1026         }
1027     }
1028 
1029     return 0;
1030 }
1031 
ParseVlanBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)1032 static int ParseVlanBindingLine(
1033         tSfPolicyConfig *config,
1034         int num_toks,
1035         char **toks,
1036         char *fileName
1037         )
1038 {
1039     int i;
1040     int vlanId1=0, vlanId2=0;
1041 
1042 
1043     for (i = 0; i < num_toks; i++)
1044     {
1045         int  num_tok2;
1046         char **toks2;
1047         int vlanId;
1048         unsigned pos;
1049         char *findStr1, *findStr2;
1050         char *endp;
1051         findStr1 = strchr(toks[i], '-');
1052         if ( findStr1 )
1053         {
1054             pos = findStr1 - toks[i];
1055             if ( pos == 0 || pos == (strlen(toks[i]) - 1) )
1056             {
1057                 return -1;
1058             }
1059             findStr2 = strchr(findStr1+1, '-');
1060             if ( findStr2 )
1061             {
1062                 return -1;
1063             }
1064             toks2 = mSplit(toks[i], "-", 2, &num_tok2, 0);
1065             if (num_tok2 == 2)
1066             {
1067                 /* vlanId1 must be < SF_VLAN_BINDING_MAX -1
1068                    to allow for an actual range */
1069                 vlanId1 = SnortStrtolRange(toks2[0], &endp, 10, 0, SF_VLAN_BINDING_MAX-1);
1070                 if( *endp )
1071                 {
1072                     mSplitFree(&toks2, num_tok2);
1073                     return -1;
1074                 }
1075                 /* vlanId2 must be > vlanId1 */
1076                 vlanId2 = SnortStrtolRange(toks2[1], &endp, 10, vlanId1+1, SF_VLAN_BINDING_MAX);
1077                 if ( *endp )
1078                 {
1079                     mSplitFree(&toks2, num_tok2);
1080                     return -1;
1081                 }
1082                 if ( (vlanId1 < 0)
1083                     || (vlanId2 >= SF_VLAN_BINDING_MAX)
1084                     || (vlanId1 > vlanId2) )
1085                 {
1086                     mSplitFree(&toks2, num_tok2);
1087                     return -1;
1088                     //FatalError("Invalid range: %d:%d\n", vlanId1, vlanId2);
1089                 }
1090                 for (vlanId = vlanId1; vlanId <= vlanId2; vlanId++)
1091                 {
1092                     if ( sfVlanAddBinding(config, vlanId, fileName) != 0)
1093                     {
1094                         mSplitFree(&toks2, num_tok2);
1095                         return -1;
1096                         //FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1097                     }
1098                 }
1099             }
1100             else
1101             {
1102                 mSplitFree(&toks2, num_tok2);
1103                 return -1;
1104             }
1105             mSplitFree(&toks2, num_tok2);
1106         }
1107 
1108         else if ( toks[i] )
1109         {
1110             vlanId = SnortStrtolRange(toks[i], &endp, 10, 0, SF_VLAN_BINDING_MAX-1);
1111             if( *endp )
1112                 return -1;
1113             if ( (vlanId >= SF_VLAN_BINDING_MAX) ||  sfVlanAddBinding(config, vlanId, fileName) != 0)
1114             {
1115                 return -1;
1116                 //FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1117             }
1118         }
1119         else
1120         {
1121             return -1;
1122             //FatalError("formating error in binding file: %s\n", aLine);
1123         }
1124     }
1125 
1126     return 0;
1127 }
1128 
ParseNetworkBindingLine(tSfPolicyConfig * config,int num_toks,char ** toks,char * fileName)1129 static int ParseNetworkBindingLine(
1130         tSfPolicyConfig *config,
1131         int num_toks,
1132         char **toks,
1133         char *fileName
1134         )
1135 {
1136     int i;
1137 
1138     for (i = 0; i < num_toks; i++)
1139     {
1140         SFIP_RET status;
1141         sfcidr_t *sfip;
1142 
1143         if( (sfip = sfip_alloc(toks[i], &status)) == NULL )
1144         {
1145             return -1;
1146         }
1147         if (sfNetworkAddBinding(config, sfip, fileName) != 0)
1148         {
1149             sfip_free(sfip);
1150             return -1;
1151             // FatalError("Unable to add policy: vlan %d, file %s\n", vlanId, fileName);
1152         }
1153 
1154         sfip_free(sfip);
1155     }
1156 
1157     return 0;
1158 }
1159 
1160 #ifdef DEBUG_MSGS
DumpRuleChains(RuleListNode * rule_lists)1161 static void DumpRuleChains(RuleListNode *rule_lists)
1162 {
1163     RuleListNode *rule = rule_lists;
1164 
1165     if (rule_lists == NULL)
1166         return;
1167 
1168     while (rule != NULL)
1169     {
1170         DumpChain(rule->name, rule->mode, ETHERNET_TYPE_IP);
1171         DumpChain(rule->name, rule->mode, IPPROTO_TCP);
1172         DumpChain(rule->name, rule->mode, IPPROTO_UDP);
1173         DumpChain(rule->name, rule->mode, IPPROTO_ICMP);
1174 
1175         rule = rule->next;
1176     }
1177 }
1178 
1179 /****************************************************************************
1180  *
1181  * Function: DumpChain(RuleTreeNode *, char *, char *)
1182  *
1183  * Purpose: Iterate over RTNs calling DumpList on each
1184  *
1185  * Arguments: rtn_idx => the RTN index pointer
1186  *                       rulename => the name of the rule the list belongs to
1187  *            listname => the name of the list being printed out
1188  *
1189  * Returns: void function
1190  *
1191  ***************************************************************************/
DumpChain(char * name,int mode,int proto)1192 static void DumpChain(char *name, int mode, int proto)
1193 {
1194     // XXX Not yet implemented - Rule chain dumping
1195 }
1196 
1197 /****************************************************************************
1198  *
1199  * Function: DumpList(IpAddrNode*)
1200  *
1201  * Purpose: print out the chain lists by header block node group
1202  *
1203  * Arguments: node => the head node
1204  *
1205  * Returns: void function
1206  *
1207  ***************************************************************************/
1208 #if 0  // avoid warning: ‘DumpList’ defined but not used
1209 static void DumpList(IpAddrNode *idx, int negated)
1210 {
1211     DEBUG_WRAP(int i=0;);
1212     if(!idx)
1213         return;
1214 
1215     while(idx != NULL)
1216     {
1217        DEBUG_WRAP(DebugMessage(DEBUG_RULES,
1218                         "[%d]    %s",
1219                         i++, sfip_ntoa(idx->ip)););
1220 
1221        if(negated)
1222        {
1223            DEBUG_WRAP(DebugMessage(DEBUG_RULES,
1224                        "    (EXCEPTION_FLAG Active)\n"););
1225        }
1226        else
1227        {
1228            DEBUG_WRAP(DebugMessage(DEBUG_RULES, "\n"););
1229        }
1230 
1231        idx = idx->next;
1232     }
1233 }
1234 #endif  /* 0 */
1235 #endif  /* DEBUG */
1236 
1237 /*
1238  * Finish adding the rule to the port tables
1239  *
1240  * 1) find the table this rule should belong to (src/dst/any-any tcp,udp,icmp,ip or nocontent)
1241  * 2) find an index for the sid:gid pair
1242  * 3) add all no content rules to a single no content port object, the ports are irrelevant so
1243  *    make it a any-any port object.
1244  * 4) if it's an any-any rule with content, add to an any-any port object
1245  * 5) find if we have a port object with these ports defined, if so get it, otherwise create it.
1246  *    a)do this for src and dst port
1247  *    b)add the rule index/id to the portobject(s)
1248  *    c)if the rule is bidir add the rule and port-object to both src and dst tables
1249  *
1250  */
FinishPortListRule(rule_port_tables_t * port_tables,RuleTreeNode * rtn,OptTreeNode * otn,int proto,port_entry_t * pe,FastPatternConfig * fp)1251 static int FinishPortListRule(rule_port_tables_t *port_tables, RuleTreeNode *rtn, OptTreeNode *otn,
1252                               int proto, port_entry_t *pe, FastPatternConfig *fp)
1253 {
1254     int large_port_group = 0;
1255     int src_cnt = 0;
1256     int dst_cnt = 0;
1257     int rim_index;
1258     PortTable *dstTable;
1259     PortTable *srcTable;
1260 #ifdef TARGET_BASED
1261     PortTable *dstTable_noservice;
1262     PortTable *srcTable_noservice;
1263 #endif
1264     PortObject *aaObject;
1265     rule_count_t *prc;
1266 
1267 #ifdef TARGET_BASED
1268     ServiceOverride service_override = otn->sigInfo.service_override;
1269     int num_services = otn->sigInfo.num_services;
1270 
1271     if ( !IsAdaptiveConfigured() )
1272         otn->sigInfo.service_override = ServiceOverride_ElsePorts;
1273     else if ( service_override == ServiceOverride_Nil && num_services )
1274         otn->sigInfo.service_override = ServiceOverride_ElsePorts;
1275     else if ( service_override == ServiceOverride_Nil && !num_services )
1276         otn->sigInfo.service_override = ServiceOverride_OrPorts;
1277 #endif
1278     /* Select the Target PortTable for this rule, based on protocol, src/dst
1279      * dir, and if there is rule content */
1280     if (proto == IPPROTO_TCP)
1281     {
1282         dstTable = port_tables->tcp_dst;
1283         srcTable = port_tables->tcp_src;
1284         aaObject = port_tables->tcp_anyany;
1285         prc = &tcpCnt;
1286 #ifdef TARGET_BASED
1287         dstTable_noservice = port_tables->ns_tcp_dst;
1288         srcTable_noservice = port_tables->ns_tcp_src;
1289 #endif
1290     }
1291     else if (proto == IPPROTO_UDP)
1292     {
1293         dstTable = port_tables->udp_dst;
1294         srcTable = port_tables->udp_src;
1295         aaObject = port_tables->udp_anyany;
1296         prc = &udpCnt;
1297 #ifdef TARGET_BASED
1298         dstTable_noservice = port_tables->ns_udp_dst;
1299         srcTable_noservice = port_tables->ns_udp_src;
1300 #endif
1301     }
1302     else if (proto == IPPROTO_ICMP)
1303     {
1304         dstTable = port_tables->icmp_dst;
1305         srcTable = port_tables->icmp_src;
1306         aaObject = port_tables->icmp_anyany;
1307         prc = &icmpCnt;
1308 #ifdef TARGET_BASED
1309         dstTable_noservice = port_tables->ns_icmp_dst;
1310         srcTable_noservice = port_tables->ns_icmp_src;
1311 #endif
1312     }
1313     else if (proto == ETHERNET_TYPE_IP)
1314     {
1315         dstTable = port_tables->ip_dst;
1316         srcTable = port_tables->ip_src;
1317         aaObject = port_tables->ip_anyany;
1318         prc = &ipCnt;
1319 #ifdef TARGET_BASED
1320         dstTable_noservice = port_tables->ns_ip_dst;
1321         srcTable_noservice = port_tables->ns_ip_src;
1322 #endif
1323     }
1324     else
1325     {
1326         return -1;
1327     }
1328 
1329     /* Count rules with both src and dst specific ports */
1330     if (!(rtn->flags & ANY_DST_PORT) && !(rtn->flags & ANY_SRC_PORT))
1331     {
1332         DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1333                    "***\n***Info:  src & dst ports are both specific"
1334                    " >> gid=%u sid=%u src=%s dst=%s\n***\n",
1335                    otn->sigInfo.generator, otn->sigInfo.id,
1336                    pe->src_port, pe->dst_port););
1337 
1338         prc->sd++;
1339     }
1340 
1341     /* Create/find an index to store this rules sid and gid at,
1342      * and use as reference in Port Objects */
1343     rim_index = otn->ruleIndex;
1344 
1345     /* Add up the nocontent rules */
1346     if (!pe->content && !pe->uricontent)
1347         prc->nc++;
1348 
1349     /* If not an any-any rule test for port bleedover, if we are using a
1350      * single rule group, don't bother */
1351     if (!fpDetectGetSingleRuleGroup(fp) &&
1352         (rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) != (ANY_DST_PORT|ANY_SRC_PORT))
1353     {
1354         if (!(rtn->flags & ANY_SRC_PORT))
1355         {
1356             src_cnt = PortObjectPortCount(rtn->src_portobject);
1357             if (src_cnt >= fpDetectGetBleedOverPortLimit(fp))
1358                 large_port_group = 1;
1359         }
1360 
1361         if (!(rtn->flags & ANY_DST_PORT))
1362         {
1363             dst_cnt = PortObjectPortCount(rtn->dst_portobject);
1364             if (dst_cnt >= fpDetectGetBleedOverPortLimit(fp))
1365                 large_port_group = 1;
1366         }
1367 
1368         if (large_port_group && fpDetectGetBleedOverWarnings(fp))
1369         {
1370 
1371             LogMessage("***Bleedover Port Limit(%d) Exceeded for rule %u:%u "
1372                        "(%d)ports: ", fpDetectGetBleedOverPortLimit(fp),
1373                        otn->sigInfo.generator, otn->sigInfo.id,
1374                        (src_cnt > dst_cnt) ? src_cnt : dst_cnt);
1375 
1376             /* If logging to syslog, this will be all multiline */
1377             fflush(stdout); fflush(stderr);
1378             PortObjectPrintPortsRaw(rtn->src_portobject);
1379             LogMessage(" -> ");
1380             PortObjectPrintPortsRaw(rtn->dst_portobject);
1381             LogMessage(" adding to any-any group\n");
1382             fflush(stdout);fflush(stderr);
1383         }
1384     }
1385 
1386     /* If an any-any rule add rule index to any-any port object
1387      * both content and no-content type rules go here if they are
1388      * any-any port rules...
1389      * If we have an any-any rule or a large port group or
1390      * were using a single rule group we make it an any-any rule. */
1391     if (((rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) == (ANY_DST_PORT|ANY_SRC_PORT)) ||
1392         large_port_group || fpDetectGetSingleRuleGroup(fp))
1393     {
1394         if (proto == ETHERNET_TYPE_IP)
1395         {
1396             /* Add the IP rules to the higher level app protocol groups, if they apply
1397              * to those protocols.  All IP rules should have any-any port descriptors
1398              * and fall into this test.  IP rules that are not tcp/udp/icmp go only into the
1399              * IP table */
1400             DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1401                                     "Finishing IP any-any rule %u:%u\n",
1402                                     otn->sigInfo.generator,otn->sigInfo.id););
1403 
1404             switch (GetOtnIpProto(otn))
1405             {
1406                 case IPPROTO_TCP:
1407                     PortObjectAddRule(port_tables->tcp_anyany, rim_index);
1408                     tcpCnt.aa++;
1409                     break;
1410 
1411                 case IPPROTO_UDP:
1412                     PortObjectAddRule(port_tables->udp_anyany, rim_index);
1413                     udpCnt.aa++;
1414                     break;
1415 
1416                 case IPPROTO_ICMP:
1417                     PortObjectAddRule(port_tables->icmp_anyany, rim_index);
1418                     icmpCnt.aa++;
1419                     break;
1420 
1421                 case -1:  /* Add to all ip proto anyany port tables */
1422                     PortObjectAddRule(port_tables->tcp_anyany, rim_index);
1423                     tcpCnt.aa++;
1424 
1425                     PortObjectAddRule(port_tables->udp_anyany, rim_index);
1426                     udpCnt.aa++;
1427 
1428                     PortObjectAddRule(port_tables->icmp_anyany, rim_index);
1429                     icmpCnt.aa++;
1430 
1431                     break;
1432 
1433                 default:
1434                     break;
1435             }
1436 
1437             /* Add to the IP ANY ANY */
1438             PortObjectAddRule(aaObject, rim_index);
1439             prc->aa++;
1440         }
1441         else
1442         {
1443             /* For other protocols-tcp/udp/icmp add to the any any group */
1444             PortObjectAddRule(aaObject, rim_index);
1445             prc->aa++;
1446         }
1447 
1448         return 0; /* done */
1449     }
1450 
1451     /* add rule index to dst table if we have a specific dst port or port list */
1452     if (!(rtn->flags & ANY_DST_PORT))
1453     {
1454         PortObject *pox;
1455 
1456         prc->dst++;
1457 
1458         DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1459                                 "Finishing rule: dst port rule\n"););
1460 
1461         /* find the proper port object */
1462         pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
1463         if (pox == NULL)
1464         {
1465             /* Create a permanent port object */
1466             pox = PortObjectDupPorts(rtn->dst_portobject);
1467             if (pox == NULL)
1468             {
1469                 ParseError("Could not dup a port object - out of memory!\n");
1470             }
1471 
1472             /* Add the port object to the table, and add the rule to the port object */
1473             PortTableAddObject(dstTable, pox);
1474         }
1475 
1476         PortObjectAddRule(pox, rim_index);
1477 
1478         /* if bidir, add this rule and port group to the src table */
1479         if (rtn->flags & BIDIRECTIONAL)
1480         {
1481             pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
1482             if (pox == NULL)
1483             {
1484                 pox = PortObjectDupPorts(rtn->dst_portobject);
1485                 if (pox == NULL)
1486                 {
1487                     ParseError("Could not dup a bidir-port object - out of memory!\n");
1488                 }
1489 
1490                 PortTableAddObject(srcTable, pox);
1491             }
1492 
1493             PortObjectAddRule(pox, rim_index);
1494         }
1495 #ifdef TARGET_BASED
1496         // Add to the NOSERVICE group
1497         if (IsAdaptiveConfigured()
1498           && (otn->sigInfo.num_services == 0 || otn->sigInfo.service_override == ServiceOverride_OrPorts))
1499         {
1500 
1501             if ( otn->sigInfo.service_override == ServiceOverride_AndPorts )
1502                 ParseError("Service override \"and-ports\" specified on a port only rule.");
1503 
1504             pox = PortTableFindInputPortObjectPorts(dstTable_noservice, rtn->dst_portobject);
1505             if (pox == NULL)
1506             {
1507                 pox = PortObjectDupPorts(rtn->dst_portobject);
1508 
1509                 if (pox == NULL)
1510                     ParseError("Could not dup a port object - out of memory!");
1511 
1512                 PortTableAddObject(dstTable_noservice, pox);
1513             }
1514 
1515             PortObjectAddRule(pox, rim_index);
1516         }
1517 #endif // TARGET_BASED
1518     }
1519 
1520     /* add rule index to src table if we have a specific src port or port list */
1521     if (!(rtn->flags & ANY_SRC_PORT))
1522     {
1523         PortObject *pox;
1524 
1525         prc->src++;
1526 
1527         pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
1528         if (pox == NULL)
1529         {
1530             pox = PortObjectDupPorts(rtn->src_portobject);
1531             if (pox == NULL)
1532             {
1533                 ParseError("Could not dup a port object - out of memory!\n");
1534             }
1535 
1536             PortTableAddObject(srcTable, pox);
1537         }
1538 
1539         PortObjectAddRule(pox, rim_index);
1540 
1541         /* if bidir, add this rule and port group to the dst table */
1542         if (rtn->flags & BIDIRECTIONAL)
1543         {
1544             pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
1545             if (pox == NULL)
1546             {
1547                 pox = PortObjectDupPorts(rtn->src_portobject);
1548                 if (pox == NULL)
1549                 {
1550                     ParseError("Could not dup a bidir-port object - out "
1551                                "of memory!\n");
1552                 }
1553 
1554                 PortTableAddObject(dstTable, pox);
1555             }
1556 
1557             PortObjectAddRule(pox, rim_index);
1558         }
1559 
1560 #ifdef TARGET_BASED
1561         // Add to the NOSERVICE group
1562        if (IsAdaptiveConfigured()
1563         && (otn->sigInfo.num_services == 0 || otn->sigInfo.service_override == ServiceOverride_OrPorts))
1564         {
1565             if ( otn->sigInfo.service_override == ServiceOverride_AndPorts )
1566                 ParseError("Service override \"and-ports\" specified on a port only rule.");
1567 
1568             /* find the proper port object */
1569             pox = PortTableFindInputPortObjectPorts(srcTable_noservice, rtn->src_portobject);
1570             if (pox == NULL)
1571             {
1572                 pox = PortObjectDupPorts(rtn->src_portobject);
1573 
1574                 if (pox == NULL)
1575                     ParseError("Could not dup a port object - out of memory!\n");
1576 
1577                 PortTableAddObject(srcTable_noservice, pox);
1578             }
1579 
1580             PortObjectAddRule(pox, rim_index);
1581         }
1582 #endif // TARGET_BASED
1583     }
1584 
1585     return 0;
1586 }
1587 /*
1588 *  Parse a port string as a port var, and create or find a port object for it,
1589 *  and add it to the port var table. These are used by the rtn's
1590 *  as src and dst port lists for final rtn/otn processing.
1591 *
1592 *  These should not be confused with the port objects used to merge ports and rules
1593 *  to build PORT_GROUP objects. Those are generated after the otn processing.
1594 *
1595 */
ParsePortListTcpUdpPort(PortVarTable * pvt,PortTable * noname,char * port_str)1596 static PortObject * ParsePortListTcpUdpPort(PortVarTable *pvt,
1597                                             PortTable *noname, char *port_str)
1598 {
1599     PortObject * portobject;
1600     //PortObject * pox;
1601     char       * errstr=0;
1602     POParser     poparser;
1603 
1604     if ((pvt == NULL) || (noname == NULL) || (port_str == NULL))
1605         return NULL;
1606 
1607     /* 1st - check if we have an any port */
1608     if( strcasecmp(port_str,"any")== 0 )
1609     {
1610         portobject = PortVarTableFind(pvt, "any");
1611         if (portobject == NULL)
1612             ParseError("PortVarTable missing an 'any' variable.");
1613 
1614         return portobject;
1615     }
1616 
1617     /* 2nd - check if we have a PortVar */
1618     else if( port_str[0]=='$' )
1619     {
1620       /*||isalpha(port_str[0])*/ /*TODO: interferes with protocol names for ports*/
1621       char * name = port_str + 1;
1622 
1623       DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortVarTableFind: finding '%s'\n", port_str););
1624 
1625       /* look it up  in the port var table */
1626       portobject = PortVarTableFind(pvt, name);
1627       if (portobject == NULL)
1628           ParseError("***PortVar Lookup failed on '%s'.", port_str);
1629 
1630       DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortVarTableFind: '%s' found!\n", port_str););
1631     }
1632 
1633     /* 3rd -  and finally process a raw port list */
1634     else
1635     {
1636        /* port list = [p,p,p:p,p,...] or p or p:p , no embedded spaces due to tokenizer */
1637        PortObject * pox;
1638 
1639        DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1640                  "parser.c->PortObjectParseString: parsing '%s'\n",port_str););
1641 
1642        portobject = PortObjectParseString(pvt, &poparser, 0, port_str, 0);
1643 
1644        DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1645                  "parser.c->PortObjectParseString: '%s' done.\n",port_str););
1646 
1647        if( !portobject )
1648        {
1649           errstr = PortObjectParseError( &poparser );
1650           ParseError("***Rule--PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s\n",
1651                      poparser.pos,errstr,port_str,poparser.pos,"^");
1652        }
1653 
1654        /* check if we already have this port object in the un-named port var table  ... */
1655        pox = PortTableFindInputPortObjectPorts(noname, portobject);
1656        if( pox )
1657        {
1658          DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1659                     "parser.c: already have '%s' as a PortObject - "
1660                     "calling PortObjectFree(portbject) line=%d\n",port_str,__LINE__ ););
1661          PortObjectFree( portobject );
1662          portobject = pox;
1663        }
1664        else
1665        {
1666            DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1667                 "parser.c: adding '%s' as a PortObject line=%d\n",port_str,__LINE__ ););
1668            /* Add to the un-named port var table */
1669            if (PortTableAddObject(noname, portobject))
1670            {
1671                ParseError("Unable to add raw port object to unnamed "
1672                           "port var table, out of memory!\n");
1673            }
1674        }
1675     }
1676 
1677     return portobject;
1678 }
1679 #ifdef XXXXX
1680 /*
1681 * Extract the Icmp Type field to determine the PortGroup.
1682 */
GetPortListIcmpPortObject(OptTreeNode * otn,PortTable * rulesPortTable,PortObject * anyAnyPortObject)1683 PortObject * GetPortListIcmpPortObject( OptTreeNode * otn, PortTable *  rulesPortTable, PortObject * anyAnyPortObject )
1684 {
1685    PortObject        * portobject=0;
1686    int                 type;
1687    IcmpTypeCheckData * IcmpType;
1688 
1689    IcmpType = (IcmpTypeCheckData *)otn->ds_list[PLUGIN_ICMP_TYPE];
1690 
1691    if( IcmpType && (IcmpType->operator == ICMP_TYPE_TEST_EQ) )
1692    {
1693        type = IcmpType->icmp_type;
1694    }
1695    else
1696    {
1697        return anyAnyPortObject;
1698    }
1699 
1700    /* TODO: optimize */
1701    return anyAnyPortObject;
1702 }
1703 /*
1704  * Extract the IP Protocol field to determine the PortGroup.
1705 */
GetPortListIPPortObject(OptTreeNode * otn,PortTable * rulesPortTable,PortObject * anyAnyPortObject)1706 PortObject * GetPortListIPPortObject( OptTreeNode * otn,PortTable *  rulesPortTable, PortObject * anyAnyPortObject )
1707 {
1708    if (GetOtnIpProto(otn) == -1)
1709        return anyAnyPortObject;
1710 
1711    /* TODO: optimize */
1712    return anyAnyPortObject;
1713 }
1714 
1715 #if 0
1716 Not currently used
1717 /*
1718 * Extract the Icmp Type field to determine the PortGroup.
1719 */
1720 static
1721 int GetOtnIcmpType(OptTreeNode * otn )
1722 {
1723    int                 type;
1724    IcmpTypeCheckData * IcmpType;
1725 
1726    IcmpType = (IcmpTypeCheckData *)otn->ds_list[PLUGIN_ICMP_TYPE];
1727 
1728    if( IcmpType && (IcmpType->operator == ICMP_TYPE_TEST_EQ) )
1729    {
1730        type = IcmpType->icmp_type;
1731    }
1732    else
1733    {
1734        return -1;
1735    }
1736 
1737    return -1;
1738 }
1739 #endif
1740 
1741 #endif /*  XXXX - PORTLISTS */
1742 /*
1743  *   Process the rule, add it to the appropriate PortObject
1744  *   and add the PortObject to the rtn.
1745  *
1746  *   TCP/UDP rules use ports/portlists, icmp uses the icmp type field and ip uses the protocol
1747  *   field as a dst port for the purposes of looking up a rule group as packets are being
1748  *   processed.
1749  *
1750  *   TCP/UDP- use src/dst ports
1751  *   ICMP   - use icmp type as dst port,src=-1
1752  *   IP     - use protocol as dst port,src=-1
1753  *
1754  *   rtn - proto_node
1755  *   port_str - port list string or port var name
1756  *   proto - protocol
1757  *   dst_flag - dst or src port flag, true = dst, false = src
1758  *
1759  */
ParsePortList(RuleTreeNode * rtn,PortVarTable * pvt,PortTable * noname,char * port_str,int proto,int dst_flag)1760 static int ParsePortList(RuleTreeNode *rtn, PortVarTable *pvt, PortTable *noname,
1761                          char *port_str, int proto, int dst_flag)
1762 {
1763     PortObject *portobject = NULL;  /* src or dst */
1764 
1765     /* Get the protocol specific port object */
1766     if( proto == IPPROTO_TCP || proto == IPPROTO_UDP )
1767     {
1768         portobject = ParsePortListTcpUdpPort(pvt, noname, port_str);
1769     }
1770     else /* ICMP, IP  - no real ports just Type and Protocol */
1771     {
1772         portobject = PortVarTableFind(pvt, "any");
1773         if (portobject == NULL)
1774         {
1775             ParseError("PortVarTable missing an 'any' variable\n");
1776         }
1777     }
1778 
1779     DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Rule-PortVar Parsed: %s \n",port_str););
1780 
1781     /* !ports - port lists can be mixed 80:90,!82,
1782     * so the old NOT flag is depracated for port lists
1783     */
1784 
1785     /* set up any any flags */
1786     if( PortObjectHasAny(portobject) )
1787     {
1788          if( dst_flag )
1789              rtn->flags |= ANY_DST_PORT;
1790          else
1791              rtn->flags |= ANY_SRC_PORT;
1792     }
1793 
1794     /* check for a pure not rule - fatal if we find one */
1795     if( PortObjectIsPureNot( portobject ) )
1796     {
1797         ParseError("Pure NOT ports are not allowed!");
1798         /*
1799            if( dst_flag )
1800            rtn->flags |= EXCEPT_DST_PORT;
1801            else
1802            rtn->flags |= EXCEPT_SRC_PORT;
1803            */
1804     }
1805 
1806     /*
1807     * set to the port object for this rules src/dst port,
1808     * these are used during rtn/otn port verification of the rule.
1809     */
1810 
1811     if (dst_flag)
1812          rtn->dst_portobject = portobject;
1813     else
1814          rtn->src_portobject = portobject;
1815 
1816     return 0;
1817 }
1818 
1819 /*
1820  * ParseIpsPortList() will create portlist for portocol specific and only for IPS policy at the snort
1821  * process bringup, it will be used to enable/disable detection on packet.
1822  */
ParseIpsPortList(SnortConfig * sc,IpProto protocol)1823 IpsPortFilter** ParseIpsPortList (SnortConfig *sc, IpProto protocol)
1824 {
1825     tSfPolicyId policyId;
1826     IpsPortFilter *ips_portfilter;
1827     bool ignore_any = false;
1828 
1829     // Allocate memory for each policy to hold port filter list
1830     IpsPortFilter **ips_port_filter_list = ( IpsPortFilter** ) SnortAlloc( sizeof(IpsPortFilter*) * sfPolicyNumAllocated(sc->policy_config) );
1831 
1832     if ( !ips_port_filter_list )
1833     {
1834         ParseError("IPS portlist memory allocation failed\n");
1835         return NULL;
1836     }
1837 
1838     ignore_any = getStreamIgnoreAnyConfig(sc, protocol);
1839     for (policyId = 0; policyId < sfPolicyNumAllocated(sc->policy_config); policyId++)
1840     {
1841         ips_portfilter = NULL;
1842         // Create port filter list for default and IPS policy
1843         if ( (policyId == 0) || (!getStreamPolicyConfig(policyId, 0)) )
1844         {
1845             ips_portfilter = ( IpsPortFilter* ) SnortAlloc( sizeof(IpsPortFilter) );
1846             if ( ips_portfilter )
1847             {
1848                 ips_portfilter->parserPolicyId = policyId;
1849                 setPortFilterList(sc, ips_portfilter->port_filter, IPPROTO_UDP, ignore_any, policyId);
1850                 ips_port_filter_list[ policyId ] = ips_portfilter;
1851             } else
1852             {
1853                 ParseError("Failed to allocate memory for port filter list policy id :%d \n",policyId);
1854                 return NULL;
1855             }
1856         } else
1857         {
1858             // NAP policy port filter list is created in pre-processor check
1859             ips_port_filter_list[ policyId ] = NULL;
1860         }
1861     }
1862     return ips_port_filter_list;
1863 }
1864 
1865 /****************************************************************************
1866  *
1867  * Function: CheckForIPListConflicts
1868  *
1869  * Purpose:  Checks For IP List Conflicts in a RuleTreeNode.  Such as
1870  *           negations that are overlapping and more general are not allowed.
1871  *
1872  *             For example, the following is not allowed:
1873  *
1874  *                  [1.1.0.0/16,!1.0.0.0/8]
1875  *
1876  *             The following is allowed though (not overlapping):
1877  *
1878  *                  [1.1.0.0/16,!2.0.0.0/8]
1879  *
1880  * Arguments: addrset -- IpAddrSet pointer.
1881  *
1882  * Returns: -1 if IP is empty, 1 if a conflict exists and 0 otherwise.
1883  *
1884  ***************************************************************************/
CheckForIPListConflicts(IpAddrSet * addrset)1885 int CheckForIPListConflicts(IpAddrSet *addrset)
1886 {
1887     /* Conflict checking takes place inside the SFIP library */
1888     return 0;
1889 }
1890 
1891 /****************************************************************************
1892  *
1893  * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *)
1894  *
1895  * Purpose:  Adds RuleTreeNode associated detection functions to the
1896  *          current rule's function list
1897  *
1898  * Arguments: *func => function pointer to the detection function
1899  *            rtn   => pointer to the current rule
1900  *
1901  * Returns: void function
1902  *
1903  ***************************************************************************/
AddRuleFuncToList(int (* rfunc)(Packet *,struct _RuleTreeNode *,struct _RuleFpList *,int),RuleTreeNode * rtn)1904 void AddRuleFuncToList(int (*rfunc) (Packet *, struct _RuleTreeNode *, struct _RuleFpList *, int), RuleTreeNode * rtn)
1905 {
1906     RuleFpList *idx;
1907 
1908     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"););
1909 
1910     idx = rtn->rule_func;
1911     if(idx == NULL)
1912     {
1913         rtn->rule_func = (RuleFpList *)SnortAlloc(sizeof(RuleFpList));
1914 
1915         rtn->rule_func->RuleHeadFunc = rfunc;
1916     }
1917     else
1918     {
1919         while(idx->next != NULL)
1920             idx = idx->next;
1921 
1922         idx->next = (RuleFpList *)SnortAlloc(sizeof(RuleFpList));
1923         idx = idx->next;
1924         idx->RuleHeadFunc = rfunc;
1925     }
1926 }
1927 
1928 
1929 /****************************************************************************
1930  *
1931  * Function: SetupRTNFuncList(RuleTreeNode *)
1932  *
1933  * Purpose: Configures the function list for the rule header detection
1934  *          functions (addrs and ports)
1935  *
1936  * Arguments: rtn => the pointer to the current rules list entry to attach to
1937  *
1938  * Returns: void function
1939  *
1940  ***************************************************************************/
SetupRTNFuncList(RuleTreeNode * rtn)1941 static void SetupRTNFuncList(RuleTreeNode * rtn)
1942 {
1943     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n"););
1944     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Functions: "););
1945 
1946     if(rtn->flags & BIDIRECTIONAL)
1947     {
1948         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckBidirectional->\n"););
1949         AddRuleFuncToList(CheckBidirectional, rtn);
1950     }
1951     else
1952     {
1953         /* Attach the proper port checking function to the function list */
1954         /*
1955          * the in-line "if's" check to see if the "any" or "not" flags have
1956          * been set so the PortToFunc call can determine which port testing
1957          * function to attach to the list
1958          */
1959         PortToFunc(rtn, (rtn->flags & ANY_DST_PORT ? 1 : 0),
1960                    (rtn->flags & EXCEPT_DST_PORT ? 1 : 0), DST);
1961 
1962         /* as above */
1963         PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT ? 1 : 0),
1964                    (rtn->flags & EXCEPT_SRC_PORT ? 1 : 0), SRC);
1965 
1966         /* link in the proper IP address detection function */
1967         AddrToFunc(rtn, SRC);
1968 
1969         /* last verse, same as the first (but for dest IP) ;) */
1970         AddrToFunc(rtn, DST);
1971     }
1972 
1973     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleListEnd\n"););
1974 
1975     /* tack the end (success) function to the list */
1976     AddRuleFuncToList(RuleListEnd, rtn);
1977 }
1978 
1979 /****************************************************************************
1980  *
1981  * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int)
1982  *
1983  * Purpose: Links the proper IP address testing function to the current RTN
1984  *          based on the address, netmask, and addr flags
1985  *
1986  * Arguments: rtn => the pointer to the current rules list entry to attach to
1987  *            ip =>  IP address of the current rule
1988  *            mask => netmask of the current rule
1989  *            exception_flag => indicates that a "!" has been set for this
1990  *                              address
1991  *            mode => indicates whether this is a rule for the source
1992  *                    or destination IP for the rule
1993  *
1994  * Returns: void function
1995  *
1996  ***************************************************************************/
AddrToFunc(RuleTreeNode * rtn,int mode)1997 static void AddrToFunc(RuleTreeNode * rtn, int mode)
1998 {
1999     /*
2000      * if IP and mask are both 0, this is a "any" IP and we don't need to
2001      * check it
2002      */
2003     switch(mode)
2004     {
2005         case SRC:
2006             if((rtn->flags & ANY_SRC_IP) == 0)
2007             {
2008                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> "););
2009                 AddRuleFuncToList(CheckSrcIP, rtn);
2010             }
2011 
2012             break;
2013 
2014         case DST:
2015             if((rtn->flags & ANY_DST_IP) == 0)
2016             {
2017                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> "););
2018                 AddRuleFuncToList(CheckDstIP, rtn);
2019             }
2020 
2021             break;
2022     }
2023 }
2024 
2025 /****************************************************************************
2026  *
2027  * Function: PortToFunc(RuleTreeNode *, int, int, int)
2028  *
2029  * Purpose: Links in the port analysis function for the current rule
2030  *
2031  * Arguments: rtn => the pointer to the current rules list entry to attach to
2032  *            any_flag =>  accept any port if set
2033  *            except_flag => indicates negation (logical NOT) of the test
2034  *            mode => indicates whether this is a rule for the source
2035  *                    or destination port for the rule
2036  *
2037  * Returns: void function
2038  *
2039  ***************************************************************************/
PortToFunc(RuleTreeNode * rtn,int any_flag,int except_flag,int mode)2040 static void PortToFunc(RuleTreeNode * rtn, int any_flag, int except_flag, int mode)
2041 {
2042     /*
2043      * if the any flag is set we don't need to perform any test to match on
2044      * this port
2045      */
2046     if(any_flag)
2047         return;
2048 
2049     /* if the except_flag is up, test with the "NotEq" funcs */
2050     if(except_flag)
2051     {
2052         switch(mode)
2053         {
2054             case SRC:
2055                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortNotEq -> "););
2056                 AddRuleFuncToList(CheckSrcPortNotEq, rtn);
2057                 break;
2058 
2059 
2060             case DST:
2061                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortNotEq -> "););
2062                 AddRuleFuncToList(CheckDstPortNotEq, rtn);
2063                 break;
2064         }
2065 
2066         return;
2067     }
2068     /* default to setting the straight test function */
2069     switch(mode)
2070     {
2071         case SRC:
2072             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortEqual -> "););
2073             AddRuleFuncToList(CheckSrcPortEqual, rtn);
2074             break;
2075 
2076         case DST:
2077             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortEqual -> "););
2078             AddRuleFuncToList(CheckDstPortEqual, rtn);
2079             break;
2080     }
2081 
2082     return;
2083 }
2084 
2085 /****************************************************************************
2086  * Function: ParsePreprocessor()
2087  *
2088  * Saves the preprocessor configuration for loading later after dynamic
2089  * preprocessor keywords and configuration functions have been registered.
2090  * Configuration is also used later for configuration reload to check if
2091  * configuration has changed.
2092  *
2093  * Arguments:
2094  *  SnortConfig *
2095  *      Snort configuration to attach preprocessor configuration to.
2096  *  char *
2097  *      The preprocessor arguments.
2098  *
2099  * Returns: void function
2100  *
2101  ***************************************************************************/
ParsePreprocessor(SnortConfig * sc,SnortPolicy * p,char * args)2102 static void ParsePreprocessor(SnortConfig *sc, SnortPolicy *p, char *args)
2103 {
2104     char **toks;
2105     int num_toks;
2106     char *keyword;
2107     char *opts = NULL;
2108     PreprocConfig *config;
2109 
2110     if ((sc == NULL) || (p == NULL) || (args == NULL))
2111         return;
2112 
2113     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Preprocessor\n"););
2114 
2115     /* break out the arguments from the keywords */
2116     toks = mSplit(args, ":", 2, &num_toks, '\\');
2117     keyword = toks[0];
2118 
2119     if (num_toks > 1)
2120         opts = toks[1];
2121 
2122     /* Save the configuration and load later */
2123     config = (PreprocConfig *)SnortAlloc(sizeof(PreprocConfig));
2124 
2125     if (p->preproc_configs == NULL)
2126     {
2127         p->preproc_configs = config;
2128     }
2129     else
2130     {
2131         PreprocConfig *tmp = p->preproc_configs;
2132 
2133         while (tmp->next != NULL)
2134             tmp = tmp->next;
2135 
2136         tmp->next = config;
2137     }
2138 
2139     config->keyword = SnortStrdup(keyword);
2140     config->file_name = SnortStrdup(file_name);
2141     config->file_line = file_line;
2142 
2143     if (opts != NULL)
2144         config->opts = SnortStrdup(opts);
2145     else
2146         config->opts = NULL;
2147 
2148     mSplitFree(&toks, num_toks);
2149 }
2150 
ConfigurePreprocessors(SnortConfig * sc,int configure_dynamic)2151 void ConfigurePreprocessors(SnortConfig *sc, int configure_dynamic)
2152 {
2153     char *stored_file_name = file_name;
2154     int stored_file_line = file_line;
2155     tSfPolicyId i;
2156 #ifndef REG_TEST
2157     struct rusage ru;
2158 #endif
2159 
2160     if (sc == NULL)
2161         return;
2162 
2163     for (i = 0; i < sc->num_policies_allocated; i++)
2164     {
2165         PreprocConfig *config;
2166 
2167         setParserPolicy(sc, i);
2168 
2169         if (sc->targeted_policies[i] == NULL)
2170             continue;
2171 
2172         config = sc->targeted_policies[i]->preproc_configs;
2173 
2174         for (; config != NULL; config = config->next)
2175         {
2176             PreprocConfigFuncNode *node;
2177 
2178             if (config->configured)
2179                 continue;
2180 
2181             file_name = config->file_name;
2182             file_line = config->file_line;
2183 
2184             node = GetPreprocConfig(config->keyword);
2185             if ((node == NULL) && configure_dynamic)
2186                 ParseError("Unknown preprocessor: \"%s\".", config->keyword);
2187 
2188             if (node != NULL)
2189             {
2190 #ifdef SNORT_RELOAD
2191                 if (node->initialized)
2192                 {
2193                     if (node->reload_func != NULL)
2194                     {
2195                         PreprocessorSwapData *swapData;
2196                         PreprocessorSwapData **swapDataNode;
2197 
2198                         for (swapData = sc->preprocSwapData;
2199                              swapData && swapData->preprocNode != node;
2200                              swapData = swapData->next);
2201                         if (!swapData)
2202                         {
2203                             swapData = (PreprocessorSwapData *)SnortAlloc(sizeof(*swapData));
2204                             swapData->preprocNode = node;
2205                             for (swapDataNode = &sc->preprocSwapData; *swapDataNode; swapDataNode = &(*swapDataNode)->next);
2206                             *swapDataNode = swapData;
2207                         }
2208                         node->reload_func(sc, config->opts, &swapData->data);
2209                         if (!sc->streamReloadConfig && node->keyword && strcmp(node->keyword, "stream5_global") == 0)
2210                             sc->streamReloadConfig = swapData->data;
2211                     }
2212                 }
2213                 else
2214 #endif
2215                 {
2216                     if (node->config_func != NULL)
2217                         node->config_func(sc, config->opts);
2218                 }
2219 
2220                 config->configured = 1;
2221             }
2222         }
2223     }
2224 
2225 #ifdef SNORT_RELOAD
2226     for (i = 0; i < sc->num_policies_allocated; i++)
2227     {
2228         PreprocConfig *config;
2229 
2230         setParserPolicy(sc, i);
2231 
2232         if (sc->targeted_policies[i] == NULL)
2233             continue;
2234 
2235         setParserPolicy(sc, i);
2236 
2237         config = sc->targeted_policies[i]->preproc_configs;
2238 
2239         /* Set all configured preprocessors to intialized */
2240         for (; config != NULL; config = config->next)
2241         {
2242             if (config->configured)
2243             {
2244                 PreprocConfigFuncNode *node = GetPreprocConfig(config->keyword);
2245 
2246                 if (node != NULL)
2247                     node->initialized = 1;
2248             }
2249         }
2250     }
2251 #endif
2252 
2253     /* Reset these since we're done with configuring dynamic preprocessors */
2254     file_name = stored_file_name;
2255     file_line = stored_file_line;
2256 #ifndef REG_TEST
2257     if (ScTestMode())
2258     {
2259         if (configure_dynamic)
2260         {
2261             getrusage(RUSAGE_SELF, &ru);
2262             LogMessage("MaxRss at the end of dynamic preproc config:%li\n",  ru.ru_maxrss);
2263         }
2264         else
2265         {
2266             getrusage(RUSAGE_SELF, &ru);
2267             LogMessage("MaxRss at the end of static preproc config:%li\n", ru.ru_maxrss);
2268         }
2269     }
2270 #endif
2271 
2272 }
2273 
2274 #ifdef SIDE_CHANNEL
2275 
ParseSideChannelModule(SnortConfig * sc,SnortPolicy * p,char * args)2276 static void ParseSideChannelModule(SnortConfig *sc, SnortPolicy *p, char *args)
2277 {
2278     char **toks;
2279     int num_toks;
2280     char *opts = NULL;
2281     SideChannelModuleConfig *config;
2282 
2283     toks = mSplit(args, ":", 2, &num_toks, '\\');
2284 
2285     if (num_toks > 1)
2286         opts = toks[1];
2287 
2288     config = (SideChannelModuleConfig *) SnortAlloc(sizeof(SideChannelModuleConfig));
2289 
2290     if (sc->side_channel_config.module_configs == NULL)
2291     {
2292         sc->side_channel_config.module_configs = config;
2293     }
2294     else
2295     {
2296         SideChannelModuleConfig *tmp = sc->side_channel_config.module_configs;
2297 
2298         while (tmp->next != NULL)
2299             tmp = tmp->next;
2300 
2301         tmp->next = config;
2302     }
2303 
2304     config->keyword = SnortStrdup(toks[0]);
2305     if (opts != NULL)
2306         config->opts = SnortStrdup(opts);
2307 
2308     /* This could come from parsing the command line (No, actually, I don't think that it could...) */
2309     if (file_name != NULL)
2310     {
2311         config->file_name = SnortStrdup(file_name);
2312         config->file_line = file_line;
2313     }
2314 
2315     mSplitFree(&toks, num_toks);
2316 }
2317 
ConfigureSideChannelModules(SnortConfig * sc)2318 void ConfigureSideChannelModules(SnortConfig *sc)
2319 {
2320     SideChannelModuleConfig *config;
2321     char *stored_file_name = file_name;
2322     int stored_file_line = file_line;
2323     int rval;
2324 
2325     for (config = sc->side_channel_config.module_configs; config != NULL; config = config->next)
2326     {
2327         file_name = config->file_name;
2328         file_line = config->file_line;
2329 
2330         rval = ConfigureSideChannelModule(config->keyword, config->opts);
2331         if (rval == -ENOENT)
2332             ParseError("Unknown side channel plugin: \"%s\"", config->keyword);
2333     }
2334 
2335     /* Reset these since we're done with configuring side channels */
2336     file_name = stored_file_name;
2337     file_line = stored_file_line;
2338 }
2339 
2340 #endif /* SIDE_CHANNEL */
2341 
2342 /* Parses standalone rate_filter configuration.
2343  *
2344  * Parses rate_filter configuration in the following format and populates internal
2345  * structures:
2346  * @code
2347  * rate_filter gid <gen-id>, sid <sig-id>,
2348  *     track <by_src|by_dst|by_rule>,
2349  *     count <c> , seconds <s>,
2350  *     new_action <alert|drop|pass|drop|reject|sdrop>,
2351  *     timeout <t> [, apply_to <cidr>];
2352  * @endcode
2353  * And then adds it into pContext.
2354  *
2355  * @param rule - string containing rate_filter configuration from snort.conf file.
2356  *
2357  * @returns void
2358 */
ParseRateFilter(SnortConfig * sc,SnortPolicy * p,char * args)2359 static void ParseRateFilter(SnortConfig *sc, SnortPolicy *p, char *args)
2360 {
2361     char **toks;
2362     int num_toks;
2363     int count_flag = 0;
2364     int new_action_flag = 0;
2365     int timeout_flag = 0;
2366     int seconds_flag = 0;
2367     int tracking_flag = 0;
2368     int genid_flag = 0;
2369     int sigid_flag = 0;
2370     int apply_flag = 0;
2371     int i;
2372     const char* ERR_KEY = "rate_filter";
2373 
2374     tSFRFConfigNode thdx;
2375 
2376     memset( &thdx, 0, sizeof(thdx) );
2377 
2378     /* Potential IP list might be present so we can't split on commas
2379      * Change commas to semi-colons */
2380     args = FixSeparators(args, ';', "rate_filter");
2381     toks = mSplit(args, ";", 0, &num_toks, 0);  /* get rule option pairs */
2382 
2383     for (i = 0; i < num_toks; i++)
2384     {
2385         char **pairs;
2386         int num_pairs;
2387 
2388         pairs = mSplit(toks[i], " \t", 2, &num_pairs, 0);  /* get rule option pairs */
2389 
2390         if (num_pairs != 2)
2391         {
2392             ParseError(ERR_NOT_PAIRED);
2393         }
2394 
2395         if (!strcasecmp(pairs[0], "gen_id"))
2396         {
2397             if ( genid_flag++ )
2398             {
2399                 ParseError(ERR_EXTRA_OPTION);
2400             }
2401 
2402             thdx.gid = xatou(pairs[1], "rate_filter: gen_id");
2403         }
2404         else if (!strcasecmp(pairs[0], "sig_id"))
2405         {
2406             if ( sigid_flag++ )
2407             {
2408                 ParseError(ERR_EXTRA_OPTION);
2409             }
2410 
2411             thdx.sid = xatou(pairs[1], "rate_filter: sig_id");
2412         }
2413         else if (!strcasecmp(pairs[0], "track"))
2414         {
2415             if ( tracking_flag++ )
2416             {
2417                 ParseError(ERR_EXTRA_OPTION);
2418             }
2419 
2420             if (!strcasecmp(pairs[1], "by_src"))
2421             {
2422                 thdx.tracking = SFRF_TRACK_BY_SRC;
2423             }
2424             else if (!strcasecmp(pairs[1], "by_dst"))
2425             {
2426                 thdx.tracking = SFRF_TRACK_BY_DST;
2427             }
2428             else if (!strcasecmp(pairs[1], "by_rule"))
2429             {
2430                 thdx.tracking = SFRF_TRACK_BY_RULE;
2431             }
2432             else
2433             {
2434                 ParseError(ERR_BAD_VALUE);
2435             }
2436         }
2437         else if (!strcasecmp(pairs[0], "count"))
2438         {
2439             if ( count_flag++ )
2440             {
2441                 ParseError(ERR_EXTRA_OPTION);
2442             }
2443 
2444             thdx.count = xatoup(pairs[1], "rate_filter: count");
2445         }
2446         else if (!strcasecmp(pairs[0], "seconds"))
2447         {
2448             if ( seconds_flag++ )
2449             {
2450                 ParseError(ERR_EXTRA_OPTION);
2451             }
2452 
2453             thdx.seconds = xatou(pairs[1], "rate_filter: seconds");
2454         }
2455         else if (!strcasecmp(pairs[0], "new_action"))
2456         {
2457             if ( new_action_flag++ )
2458             {
2459                 ParseError(ERR_EXTRA_OPTION);
2460             }
2461 
2462             if (!strcasecmp(pairs[1], "alert"))
2463             {
2464                 thdx.newAction = RULE_TYPE__ALERT;
2465             }
2466             else if (!strcasecmp(pairs[1], "drop"))
2467             {
2468                 thdx.newAction = RULE_TYPE__DROP;
2469             }
2470             else if (!strcasecmp(pairs[1], "pass"))
2471             {
2472                 thdx.newAction = RULE_TYPE__PASS;
2473             }
2474             else if (!strcasecmp(pairs[1], "log"))
2475             {
2476                 thdx.newAction = RULE_TYPE__LOG;
2477             }
2478             else if (!strcasecmp(pairs[1], "reject"))
2479             {
2480                 thdx.newAction = RULE_TYPE__REJECT;
2481             }
2482             else if (!strcasecmp(pairs[1], "sdrop"))
2483             {
2484                 thdx.newAction = RULE_TYPE__SDROP;
2485             }
2486             else
2487             {
2488                 ParseError(ERR_BAD_VALUE);
2489             }
2490         }
2491         else if (!strcasecmp(pairs[0], "timeout"))
2492         {
2493             if ( timeout_flag++ )
2494             {
2495                 ParseError(ERR_EXTRA_OPTION);
2496             }
2497 
2498             thdx.timeout = xatou(pairs[1],"rate_filter: timeout");
2499         }
2500         else if (!strcasecmp(pairs[0], "apply_to"))
2501         {
2502             char *ip_list = pairs[1];
2503 
2504             if ( apply_flag++ )
2505             {
2506                 ParseError(ERR_EXTRA_OPTION);
2507             }
2508 
2509             thdx.applyTo = IpAddrSetParse(sc, ip_list);
2510         }
2511         else
2512         {
2513             ParseError(ERR_BAD_OPTION);
2514         }
2515 
2516         mSplitFree(&pairs, num_pairs);
2517     }
2518 
2519     if ( (genid_flag != 1) || (sigid_flag != 1) || (tracking_flag != 1)
2520       || (count_flag != 1) || (seconds_flag != 1) || (new_action_flag != 1)
2521       || (timeout_flag != 1) || (apply_flag > 1) )
2522     {
2523         ParseError(ERR_BAD_ARG_COUNT);
2524     }
2525     if ( !thdx.seconds
2526         && (thdx.gid != GENERATOR_INTERNAL
2527          || thdx.sid != INTERNAL_EVENT_SESSION_ADD) )
2528     {
2529         ParseError("rate_filter: seconds must be > 0");
2530     }
2531 
2532     if (RateFilter_Create(sc, sc->rate_filter_config,  &thdx))
2533     {
2534         ParseError(ERR_CREATE);
2535     }
2536 
2537     mSplitFree(&toks, num_toks);
2538 }
2539 
ParseRuleTypeOutput(SnortConfig * sc,char * args,ListHead * list)2540 static void ParseRuleTypeOutput(SnortConfig *sc, char *args, ListHead *list)
2541 {
2542     char **toks;
2543     int num_toks;
2544     char *opts = NULL;
2545     OutputConfig *config;
2546 
2547     toks = mSplit(args, ":", 2, &num_toks, '\\');
2548 
2549     if (num_toks > 1)
2550         opts = toks[1];
2551 
2552     config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2553 
2554     if (sc->rule_type_output_configs == NULL)
2555     {
2556         sc->rule_type_output_configs = config;
2557     }
2558     else
2559     {
2560         OutputConfig *tmp = sc->rule_type_output_configs;
2561 
2562         while (tmp->next != NULL)
2563             tmp = tmp->next;
2564 
2565         tmp->next = config;
2566     }
2567 
2568     config->keyword = SnortStrdup(toks[0]);
2569     if (opts != NULL)
2570         config->opts = SnortStrdup(opts);
2571     config->rule_list = list;
2572 
2573     if (file_name != NULL)
2574     {
2575         config->file_name = SnortStrdup(file_name);
2576         config->file_line = file_line;
2577     }
2578 
2579     mSplitFree(&toks, num_toks);
2580 }
2581 
ParseOutput(SnortConfig * sc,SnortPolicy * p,char * args)2582 void ParseOutput(SnortConfig *sc, SnortPolicy *p, char *args)
2583 {
2584     char **toks;
2585     int num_toks;
2586     char *opts = NULL;
2587     OutputConfig *config;
2588 
2589     toks = mSplit(args, ":", 2, &num_toks, '\\');
2590 
2591     if (num_toks > 1)
2592         opts = toks[1];
2593 
2594     config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2595 
2596     if (sc->output_configs == NULL)
2597     {
2598         sc->output_configs = config;
2599     }
2600     else
2601     {
2602         OutputConfig *tmp = sc->output_configs;
2603 
2604         while (tmp->next != NULL)
2605             tmp = tmp->next;
2606 
2607         tmp->next = config;
2608     }
2609 
2610     config->keyword = SnortStrdup(toks[0]);
2611     if (opts != NULL)
2612         config->opts = SnortStrdup(opts);
2613 
2614     /* This could come from parsing the command line */
2615     if (file_name != NULL)
2616     {
2617         config->file_name = SnortStrdup(file_name);
2618         config->file_line = file_line;
2619     }
2620 
2621     mSplitFree(&toks, num_toks);
2622 }
2623 
TransferOutputConfigs(OutputConfig * from_list,OutputConfig ** to_list)2624 static void TransferOutputConfigs(OutputConfig *from_list, OutputConfig **to_list)
2625 {
2626     if ((from_list == NULL) || (to_list == NULL))
2627         return;
2628 
2629     for (; from_list != NULL; from_list = from_list->next)
2630     {
2631         if (*to_list == NULL)
2632         {
2633             *to_list = DupOutputConfig(from_list);
2634         }
2635         else
2636         {
2637             OutputConfig *tmp = DupOutputConfig(from_list);
2638 
2639             if (tmp != NULL)
2640             {
2641                 tmp->next = *to_list;
2642                 *to_list = tmp;
2643             }
2644         }
2645     }
2646 }
2647 
DupOutputConfig(OutputConfig * dupme)2648 static OutputConfig * DupOutputConfig(OutputConfig *dupme)
2649 {
2650     OutputConfig *medup;
2651 
2652     if (dupme == NULL)
2653         return NULL;
2654 
2655     medup = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
2656 
2657     if (dupme->keyword != NULL)
2658         medup->keyword = SnortStrdup(dupme->keyword);
2659 
2660     if (dupme->opts != NULL)
2661         medup->opts = SnortStrdup(dupme->opts);
2662 
2663     if (dupme->file_name != NULL)
2664         medup->file_name = SnortStrdup(dupme->file_name);
2665 
2666     medup->file_line = dupme->file_line;
2667     medup->rule_list = dupme->rule_list;
2668 
2669     return medup;
2670 }
2671 
RemoveOutputConfigs(OutputConfig ** head,int remove_flags)2672 static void RemoveOutputConfigs(OutputConfig **head, int remove_flags)
2673 {
2674     OutputConfig *config;
2675     OutputConfig *last = NULL;
2676 
2677     if (head == NULL)
2678         return;
2679 
2680     config = *head;
2681 
2682     while (config != NULL)
2683     {
2684         int type_flags = GetOutputTypeFlags(config->keyword);
2685 
2686         if (type_flags & remove_flags)
2687         {
2688             OutputConfig *tmp = config;
2689 
2690             config = config->next;
2691 
2692             if (last == NULL)
2693                 *head = config;
2694             else
2695                 last->next = config;
2696 
2697             free(tmp->keyword);
2698 
2699             if (tmp->opts != NULL)
2700                 free(tmp->opts);
2701 
2702             if (tmp->file_name != NULL)
2703                 free(tmp->file_name);
2704 
2705             free(tmp);
2706         }
2707         else
2708         {
2709             last = config;
2710             config = config->next;
2711         }
2712     }
2713 }
2714 
ResolveOutputPlugins(SnortConfig * cmd_line,SnortConfig * config_file)2715 void ResolveOutputPlugins(SnortConfig *cmd_line, SnortConfig *config_file)
2716 {
2717     int cmd_line_type_flags = 0;
2718 
2719     if (cmd_line == NULL)
2720         return;
2721 
2722     if (cmd_line->no_log)
2723     {
2724         /* Free any log output plugins in both lists */
2725         RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__LOG);
2726 
2727         if (config_file != NULL)
2728         {
2729             RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
2730             RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
2731         }
2732     }
2733     else if ((config_file != NULL) && config_file->no_log)
2734     {
2735         /* Free any log output plugins in config list */
2736         RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
2737         RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
2738     }
2739 
2740     if (cmd_line->no_alert)
2741     {
2742         /* Free any alert output plugins in both lists */
2743         RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__ALERT);
2744 
2745         if (config_file != NULL)
2746         {
2747             RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
2748             RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
2749         }
2750     }
2751     else if ((config_file != NULL) && config_file->no_alert)
2752     {
2753         /* Free any alert output plugins in config list */
2754         RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
2755         RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
2756     }
2757 
2758     /* Command line overrides configuration file output */
2759     if (cmd_line->output_configs != NULL)
2760     {
2761         OutputConfig *config = cmd_line->output_configs;
2762 
2763         for (; config != NULL; config = config->next)
2764         {
2765             int type_flags = GetOutputTypeFlags(config->keyword);
2766 
2767             cmd_line_type_flags |= type_flags;
2768 
2769             if (config_file != NULL)
2770             {
2771                 RemoveOutputConfigs(&config_file->output_configs, type_flags);
2772                 RemoveOutputConfigs(&config_file->rule_type_output_configs, type_flags);
2773             }
2774         }
2775 
2776         /* Put what's in the command line output into the config file output */
2777         if (config_file != NULL)
2778             TransferOutputConfigs(cmd_line->output_configs, &config_file->output_configs);
2779     }
2780 
2781     if (config_file != NULL)
2782     {
2783         if (cmd_line->no_log)
2784             config_file->no_log = cmd_line->no_log;
2785 
2786         if (cmd_line->no_alert)
2787             config_file->no_alert = cmd_line->no_alert;
2788     }
2789 
2790     /* Don't try to configure defaults if running in test mode */
2791     if (!ScTestModeNewConf(cmd_line))
2792     {
2793         if (config_file == NULL)
2794         {
2795             if (!cmd_line->no_log && !(cmd_line_type_flags & OUTPUT_TYPE__LOG))
2796                 ParseOutput(cmd_line, NULL, "log_tcpdump");
2797 
2798             if (!cmd_line->no_alert && !(cmd_line_type_flags & OUTPUT_TYPE__ALERT))
2799                 ParseOutput(cmd_line, NULL, "alert_full");
2800         }
2801         else
2802         {
2803             int config_file_type_flags = 0;
2804             OutputConfig *config = config_file->output_configs;
2805 
2806             for (; config != NULL; config = config->next)
2807                 config_file_type_flags |= GetOutputTypeFlags(config->keyword);
2808 
2809             if (!config_file->no_log && !(config_file_type_flags & OUTPUT_TYPE__LOG))
2810                 ParseOutput(config_file, NULL, "log_tcpdump");
2811 
2812             if (!config_file->no_alert && !(config_file_type_flags & OUTPUT_TYPE__ALERT))
2813                 ParseOutput(config_file, NULL, "alert_full");
2814         }
2815     }
2816 }
2817 
ConfigureOutputPlugins(SnortConfig * sc)2818 void ConfigureOutputPlugins(SnortConfig *sc)
2819 {
2820     OutputConfig *config;
2821     char *stored_file_name = file_name;
2822     int stored_file_line = file_line;
2823 
2824     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n"););
2825 
2826     for (config = sc->output_configs; config != NULL; config = config->next)
2827     {
2828         OutputConfigFunc oc_func;
2829 
2830         file_name = config->file_name;
2831         file_line = config->file_line;
2832 
2833         oc_func = GetOutputConfigFunc(config->keyword);
2834         if (oc_func == NULL)
2835             ParseError("Unknown output plugin: \"%s\"", config->keyword);
2836 
2837         oc_func(sc, config->opts);
2838     }
2839 
2840     /* Configure output plugins for user defined rule types */
2841     for (config = sc->rule_type_output_configs; config != NULL; config = config->next)
2842     {
2843         OutputConfigFunc oc_func;
2844 
2845         file_name = config->file_name;
2846         file_line = config->file_line;
2847 
2848         oc_func = GetOutputConfigFunc(config->keyword);
2849         if (oc_func == NULL)
2850             ParseError("Unknown output plugin \"%s\"", config->keyword);
2851 
2852         /* Each user defined rule type has it's own rule list and output plugin is
2853          * attached to it's Alert and/or Log lists */
2854         sc->head_tmp = config->rule_list;
2855         oc_func(sc, config->opts);
2856         sc->head_tmp = NULL;
2857     }
2858 
2859     /* Reset these since we're done with configuring dynamic preprocessors */
2860     file_name = stored_file_name;
2861     file_line = stored_file_line;
2862 }
2863 
FreeRuleTreeNode(RuleTreeNode * rtn)2864 static void FreeRuleTreeNode(RuleTreeNode *rtn)
2865 {
2866     RuleFpList *idx, *tmp;
2867     if (!rtn)
2868         return;
2869 
2870     if (rtn->sip)
2871     {
2872         sfvar_free(rtn->sip);
2873     }
2874 
2875     if (rtn->dip)
2876     {
2877         sfvar_free(rtn->dip);
2878     }
2879 
2880     idx = rtn->rule_func;
2881     while (idx)
2882     {
2883         tmp = idx;
2884         idx = idx->next;
2885         free(tmp);
2886     }
2887 }
2888 
DestroyRuleTreeNode(RuleTreeNode * rtn)2889 static void DestroyRuleTreeNode(RuleTreeNode *rtn)
2890 {
2891     if (!rtn)
2892         return;
2893 
2894     rtn->otnRefCount--;
2895     if (rtn->otnRefCount != 0)
2896         return;
2897 
2898     FreeRuleTreeNode(rtn);
2899 
2900     free(rtn);
2901 }
2902 
2903 /****************************************************************************
2904  *
2905  * Function: mergeDuplicateOtn()
2906  *
2907  * Purpose:  Conditionally removes duplicate SID/GIDs. Keeps duplicate with
2908  *           higher revision.  If revision is the same, keeps newest rule.
2909  *
2910  * Arguments: otn_dup => The existing duplicate
2911  *            rtn => the RTN chain to check
2912  *            char => String describing the rule
2913  *            rule_type => enumerated rule type (alert, pass, log)
2914  *
2915  * Returns: 0 if original rule stays, 1 if new rule stays
2916  *
2917  ***************************************************************************/
mergeDuplicateOtn(SnortConfig * sc,OptTreeNode * otn_dup,OptTreeNode * otn_new,RuleTreeNode * rtn_new)2918 static int mergeDuplicateOtn(SnortConfig *sc, OptTreeNode *otn_dup,
2919                              OptTreeNode *otn_new, RuleTreeNode *rtn_new)
2920 {
2921     RuleTreeNode *rtn_dup = NULL;
2922     RuleTreeNode *rtnTmp2 = NULL;
2923     unsigned i;
2924 
2925     if (otn_dup->proto != otn_new->proto)
2926     {
2927         ParseError("GID %d SID %d in rule duplicates previous rule, with "
2928                    "different protocol.",
2929                    otn_new->sigInfo.generator, otn_new->sigInfo.id);
2930     }
2931 
2932     rtn_dup = getParserRtnFromOtn(sc, otn_dup);
2933 
2934     if((rtn_dup != NULL) && (rtn_dup->type != rtn_new->type))
2935     {
2936         ParseError("GID %d SID %d in rule duplicates previous rule, with "
2937                    "different type.",
2938                    otn_new->sigInfo.generator, otn_new->sigInfo.id);
2939     }
2940 
2941     if((otn_new->sigInfo.shared < otn_dup->sigInfo.shared)
2942         || ((otn_new->sigInfo.shared == otn_dup->sigInfo.shared)
2943             && (otn_new->sigInfo.rev < otn_dup->sigInfo.rev)))
2944     {
2945         //existing OTN is newer version. Keep existing and discard the new one.
2946         //OTN is for new policy group, salvage RTN
2947         deleteRtnFromOtn(sc, otn_new, getParserPolicy(sc));
2948 
2949         ParseMessage("GID %d SID %d duplicates previous rule. Using %s.",
2950                      otn_new->sigInfo.generator, otn_new->sigInfo.id,
2951                      otn_dup->sigInfo.shared ? "SO rule.":"higher revision");
2952 
2953         /* delete the data for each rule option in this OTN */
2954         OtnDeleteData(otn_new);
2955 
2956         /* Now free the OTN itself -- this function is also used
2957          * by the hash-table calls out of OtnRemove, so it cannot
2958          * be modified to delete data for rule options */
2959         OtnFree(otn_new);
2960 
2961         //Add rtn to existing otn for the first rule instance in a policy,
2962         //otherwise ignore it
2963         if (rtn_dup == NULL)
2964         {
2965             addRtnToOtn(sc, otn_dup, getParserPolicy(sc), rtn_new);
2966         }
2967         else
2968         {
2969             DestroyRuleTreeNode(rtn_new);
2970         }
2971 
2972         return 0;
2973     }
2974 
2975     //delete existing rule instance and keep the new one
2976 
2977     for (i = 0; i < otn_dup->proto_node_num; i++)
2978     {
2979         rtnTmp2 = deleteRtnFromOtn(sc, otn_dup, i);
2980 
2981         if ((rtnTmp2 && (i != getParserPolicy(sc))))
2982         {
2983             addRtnToOtn(sc, otn_new, i, rtnTmp2);
2984         }
2985     }
2986 
2987     if (rtn_dup)
2988     {
2989         if (ScConfErrorOutNewConf(sc))
2990         {
2991             ParseError("GID %d SID %d in rule duplicates previous rule.",
2992                     otn_new->sigInfo.generator, otn_new->sigInfo.id);
2993         }
2994         else
2995         {
2996             ParseWarning("GID %d SID %d in rule duplicates previous "
2997                     "rule. Ignoring old rule.\n",
2998                     otn_new->sigInfo.generator, otn_new->sigInfo.id);
2999         }
3000 
3001         switch (otn_new->sigInfo.rule_type)
3002         {
3003             case SI_RULE_TYPE_DETECT:
3004                 detect_rule_count--;
3005                 break;
3006             case SI_RULE_TYPE_DECODE:
3007                 decode_rule_count--;
3008                 break;
3009             case SI_RULE_TYPE_PREPROC:
3010                 preproc_rule_count--;
3011                 break;
3012             default:
3013                 break;
3014         }
3015     }
3016 
3017     otn_count--;
3018 
3019     OtnRemove(sc->otn_map, sc->so_rule_otn_map, otn_dup);
3020     DestroyRuleTreeNode(rtn_dup);
3021 
3022     return 1;
3023 }
3024 
3025 /* createDynamicRuleTypeRtn
3026  *
3027  * This api is only getting called whenever will see those
3028  * GID/SID pairs whose rule action type is getting modulated
3029  * from code depending upon few runtime parameters.
3030  *
3031  * In present scenario for
3032  * GID - GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE, rule action
3033  * type is getting modified depending upon file verdict.
3034  *
3035  * I/P - SnortConfig -
3036  *       old_rtn     -   This is the old RTN which has been created
3037  *                       irrespective of above mentioned scenario.
3038  *                       As a new RTN will be created with type NONE,
3039  *                       will destroy this old RTN.
3040  *
3041  * O/P - rtn         -   This is RTN which has been created with
3042  *                       RULE_TYPE_NONE specify that rule type will
3043  *                       be decided at the run time.
3044  */
createDynamicRuleTypeRtn(SnortConfig * sc,RuleTreeNode * old_rtn)3045 static inline RuleTreeNode * createDynamicRuleTypeRtn(SnortConfig *sc, RuleTreeNode *old_rtn)
3046 {
3047     RuleTreeNode test_rtn;
3048     RuleTreeNode *rtn;
3049     ListHead *list = old_rtn->listhead;
3050 
3051     memset(&test_rtn, 0, sizeof(RuleTreeNode));
3052 
3053     /* Making own key by changing the type to NONE */
3054     test_rtn.flags |= ANY_DST_PORT;
3055     test_rtn.flags |= ANY_SRC_PORT;
3056     test_rtn.flags |= ANY_DST_IP;
3057     test_rtn.flags |= ANY_SRC_IP;
3058     test_rtn.flags |= BIDIRECTIONAL;
3059 
3060     /*
3061      * Initialising the rule type as NONE since type value will be
3062      * dynamic for GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE
3063      */
3064     test_rtn.type = RULE_TYPE__NONE;
3065     test_rtn.listhead = list;
3066 
3067     DestroyRuleTreeNode(old_rtn);
3068 
3069     /* Creating the RTN node for File policy internal IPS rules(147:1/146)*/
3070     rtn = ProcessHeadNode(sc, &test_rtn, list);
3071     return rtn;
3072 }
3073 
3074 /****************************************************************************
3075  *
3076  * Function: ParseRuleOptions(char *, int)
3077  *
3078  * Purpose:  Process an individual rule's options and add it to the
3079  *           appropriate rule chain
3080  *
3081  * Arguments: rule => rule string
3082  *            rule_type => enumerated rule type (alert, pass, log)
3083  *            *conflicts => Identifies whether there was a conflict due to duplicate
3084  *                rule and whether existing otn was newer or not.
3085  *                0 - no conflict
3086  *                1 - existing otn is newer.
3087  *                -1 - existing otn is older.
3088  *
3089  * Returns:
3090  *  OptTreeNode *
3091  *      The new OptTreeNode on success or NULL on error.
3092  *
3093  ***************************************************************************/
ParseRuleOptions(SnortConfig * sc,RuleTreeNode ** rtn_addr,char * rule_opts,RuleType rule_type,int protocol)3094 OptTreeNode * ParseRuleOptions(SnortConfig *sc, RuleTreeNode **rtn_addr,
3095                                char *rule_opts, RuleType rule_type, int protocol)
3096 {
3097     OptTreeNode *otn;
3098     RuleOptOtnHandler otn_handler = NULL;
3099     int num_detection_opts = 0;
3100     char *dopt_keyword = NULL;
3101     OptFpList *fpl = NULL;
3102     int got_sid = 0;
3103     RuleTreeNode *rtn = *rtn_addr;
3104 
3105     otn = (OptTreeNode *)SnortAlloc(sizeof(OptTreeNode));
3106 
3107     otn->chain_node_number = otn_count;
3108     otn->proto = protocol;
3109     otn->event_data.sig_generator = GENERATOR_SNORT_ENGINE;
3110     otn->sigInfo.generator        = GENERATOR_SNORT_ENGINE;
3111     otn->sigInfo.rule_type        = SI_RULE_TYPE_DETECT; /* standard rule */
3112     otn->sigInfo.rule_flushing    = SI_RULE_FLUSHING_ON; /* usually just standard rules cause a flush*/
3113 #ifdef TARGET_BASED
3114     otn->sigInfo.service_override = ServiceOverride_Nil;
3115 #endif
3116 
3117     /* Set the default rule state */
3118     otn->rule_state = ScDefaultRuleStateNewConf(sc);
3119 
3120     if (rule_opts == NULL)
3121     {
3122         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "No rule options.\n"););
3123 
3124         if (ScRequireRuleSidNewConf(sc))
3125             ParseError("Each rule must contain a Rule-sid.");
3126 
3127         addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
3128 
3129         otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
3130                                          otn->sigInfo.generator,
3131                                          otn->sigInfo.id);
3132     }
3133     else
3134     {
3135         char **toks;
3136         int num_toks;
3137         char configured[sizeof(rule_options) / sizeof(RuleOptFunc)];
3138         int i;
3139         OptTreeNode *otn_dup;
3140 
3141         if ((rule_opts[0] != '(') || (rule_opts[strlen(rule_opts) - 1] != ')'))
3142         {
3143             ParseError("Rule options must be enclosed in '(' and ')'.");
3144         }
3145 
3146         /* Move past '(' and zero out ')' */
3147         rule_opts++;
3148         rule_opts[strlen(rule_opts) - 1] = '\0';
3149 
3150         /* Used to determine if a rule option has already been configured
3151          * in the rule.  Some can only be configured once */
3152         memset(configured, 0, sizeof(configured));
3153 
3154         toks = mSplit(rule_opts, ";", 0, &num_toks, '\\');
3155 
3156         for (i = 0; i < num_toks; i++)
3157         {
3158             char **opts;
3159             int num_opts;
3160             char *option_args = NULL;
3161             int j;
3162 
3163             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option: %s\n", toks[i]););
3164 
3165             /* break out the option name from its data */
3166             opts = mSplit(toks[i], ":", 2, &num_opts, '\\');
3167 
3168             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option name: %s\n", opts[0]););
3169 
3170             if (num_opts == 2)
3171             {
3172                 option_args = opts[1];
3173                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option args: %s\n", option_args););
3174             }
3175 
3176             for (j = 0; rule_options[j].name != NULL; j++)
3177             {
3178                 if (strcasecmp(opts[0], rule_options[j].name) == 0)
3179                 {
3180                     if (configured[j] && rule_options[j].only_once)
3181                     {
3182                         ParseError("Only one '%s' rule option per rule.",
3183                                    opts[0]);
3184                     }
3185 
3186                     if ((option_args == NULL) && rule_options[j].args_required)
3187                     {
3188                         ParseError("No argument passed to keyword \"%s\".  "
3189                                    "Make sure you didn't forget a ':' or the "
3190                                    "argument to this keyword.\n", opts[0]);
3191                     }
3192 
3193                     rule_options[j].parse_func(sc, rtn, otn, rule_type, option_args);
3194                     configured[j] = 1;
3195 
3196                     if ( !dopt_keyword && rule_options[j].detection )
3197                         dopt_keyword = SnortStrdup(opts[0]);
3198                     break;
3199                 }
3200             }
3201 
3202             /* Because we actually allow an sid of 0 */
3203             if ((rule_options[j].name != NULL) &&
3204                 (strcasecmp(rule_options[j].name, RULE_OPT__SID) == 0))
3205             {
3206                 got_sid = 1;
3207             }
3208 
3209             /* It's possibly a detection option plugin */
3210             if (rule_options[j].name == NULL)
3211             {
3212                 RuleOptConfigFuncNode *dopt = rule_opt_config_funcs;
3213 
3214                 for (; dopt != NULL; dopt = dopt->next)
3215                 {
3216                     if (strcasecmp(opts[0], dopt->keyword) == 0)
3217                     {
3218                         dopt->func(sc, option_args, otn, protocol);
3219 
3220                         /* If this option contains an OTN handler, save it for
3221                            use after the rule is done parsing. */
3222                         if (dopt->otn_handler != NULL)
3223                             otn_handler = dopt->otn_handler;
3224 
3225                         /* This is done so if we have a preprocessor/decoder
3226                          * rule, we can tell the user that detection options
3227                          * are not supported with those types of rules, and
3228                          * what the detection option is */
3229                         if ((dopt_keyword == NULL) &&
3230                             (dopt->type == OPT_TYPE_DETECTION))
3231                         {
3232                             dopt_keyword = SnortStrdup(opts[0]);
3233                         }
3234 
3235                         break;
3236                     }
3237                 }
3238 
3239                 if (dopt == NULL)
3240                 {
3241                     /* Maybe it's a preprocessor rule option */
3242                     PreprocOptionInit initFunc = NULL;
3243                     PreprocOptionEval evalFunc = NULL;
3244                     PreprocOptionFastPatternFunc fpFunc = NULL;
3245                     PreprocOptionOtnHandler preprocOtnHandler = NULL;
3246                     PreprocOptionCleanup cleanupFunc = NULL;
3247                     void *opt_data = NULL;
3248 
3249                     int ret = GetPreprocessorRuleOptionFuncs
3250                         (sc, opts[0], &initFunc, &evalFunc,
3251                          &preprocOtnHandler, &fpFunc, &cleanupFunc);
3252 
3253                     if (ret && (initFunc != NULL))
3254                     {
3255                         initFunc(sc, opts[0], option_args, &opt_data);
3256                         AddPreprocessorRuleOption(sc, opts[0], otn, opt_data, evalFunc);
3257                         if (preprocOtnHandler != NULL)
3258                             otn_handler = (RuleOptOtnHandler)preprocOtnHandler;
3259 
3260                         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "%s->", opts[0]););
3261                     }
3262                     else
3263                     {
3264                         /* Unrecognized rule option */
3265                         ParseError("Unknown rule option: '%s'.", opts[0]);
3266                     }
3267                 }
3268 
3269                 if (dopt_keyword == NULL)
3270                     dopt_keyword = SnortStrdup(opts[0]);
3271 
3272                 num_detection_opts++;
3273             }
3274 
3275             mSplitFree(&opts, num_opts);
3276         }
3277 
3278         if ((dopt_keyword != NULL) &&
3279             (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT))
3280         {
3281             /* Preprocessor and decoder rules can not have
3282              * detection options */
3283             ParseError("Preprocessor and decoder rules do not support "
3284                        "detection options: %s.", dopt_keyword);
3285         }
3286 
3287         if (dopt_keyword != NULL)
3288             free(dopt_keyword);
3289 
3290 		/* Each rule must have a sid irrespective of snort
3291 		 * in test mode or IPS/IDS mode.*/
3292         if (!got_sid)
3293             ParseError("Each rule must contain a rule sid.");
3294 
3295         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd\n"););
3296 
3297         if ((otn->sigInfo.generator == GENERATOR_FILE_SIGNATURE &&
3298             otn->sigInfo.id == FILE_SIGNATURE_SHA256) ||
3299             otn->sigInfo.generator == GENERATOR_FILE_TYPE)
3300         {
3301             rtn = createDynamicRuleTypeRtn(sc, rtn);
3302             *rtn_addr = rtn;
3303         }
3304         addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
3305 
3306         /* Check for duplicate SID */
3307         otn_dup = OtnLookup(sc->otn_map, otn->sigInfo.generator, otn->sigInfo.id);
3308         if (otn_dup != NULL)
3309         {
3310             otn->ruleIndex = otn_dup->ruleIndex;
3311 
3312             if (mergeDuplicateOtn(sc, otn_dup, otn, rtn) == 0)
3313             {
3314                 /* We are keeping the old/dup OTN and trashing the new one
3315                  * we just created - it's free'd in the remove dup function */
3316                 mSplitFree(&toks, num_toks);
3317                 return NULL;
3318             }
3319         }
3320         else
3321         {
3322             otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
3323                                              otn->sigInfo.generator,
3324                                              otn->sigInfo.id);
3325         }
3326 
3327         mSplitFree(&toks, num_toks);
3328     }
3329 
3330     otn->num_detection_opts += num_detection_opts;
3331     otn_count++;
3332 
3333     if (otn->sigInfo.rule_type == SI_RULE_TYPE_DETECT)
3334     {
3335         detect_rule_count++;
3336     }
3337     else if (otn->sigInfo.rule_type == SI_RULE_TYPE_DECODE)
3338     {
3339         //Set the bit if the decoder rule is enabled in the policies
3340         UpdateDecodeRulesArray(otn->sigInfo.id, ENABLE_RULE, ENABLE_ONE_RULE);
3341         decode_rule_count++;
3342     }
3343     else if (otn->sigInfo.rule_type == SI_RULE_TYPE_PREPROC)
3344     {
3345         preproc_rule_count++;
3346     }
3347 
3348     fpl = AddOptFuncToList(OptListEnd, otn);
3349     fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
3350 
3351     if (otn_handler != NULL)
3352     {
3353         otn_handler(sc, otn);
3354     }
3355 
3356     FinalizeContentUniqueness(sc, otn);
3357     ValidateFastPattern(otn);
3358 
3359     if ((thdx_tmp != NULL) && (otn->detection_filter != NULL))
3360     {
3361         ParseError("The \"detection_filter\" rule option and the \"threshold\" "
3362                    "rule option cannot be used in the same rule.\n");
3363     }
3364 
3365     if (thdx_tmp != NULL)
3366     {
3367         int rstat;
3368 
3369         thdx_tmp->sig_id = otn->sigInfo.id;
3370         thdx_tmp->gen_id = otn->sigInfo.generator;
3371         rstat = sfthreshold_create(sc, sc->threshold_config, thdx_tmp);
3372 
3373         if (rstat)
3374         {
3375             if (rstat == THD_TOO_MANY_THDOBJ)
3376             {
3377                 ParseError("threshold (in rule): could not create threshold - "
3378                            "only one per sig_id=%u.", thdx_tmp->sig_id);
3379             }
3380             else
3381             {
3382                 ParseError("threshold (in rule): could not add threshold "
3383                            "for sig_id=%u!\n", thdx_tmp->sig_id);
3384             }
3385         }
3386 
3387         thdx_tmp = NULL;
3388     }
3389 
3390     /* setup gid,sid->otn mapping */
3391     SoRuleOtnLookupAdd(sc->so_rule_otn_map, otn);
3392     OtnLookupAdd(sc->otn_map, otn);
3393 
3394     return otn;
3395 }
3396 
3397 /****************************************************************************
3398  *
3399  * Function: GetRuleProtocol(char *)
3400  *
3401  * Purpose: Figure out which protocol the current rule is talking about
3402  *
3403  * Arguments: proto_str => the protocol string
3404  *
3405  * Returns: The integer value of the protocol
3406  *
3407  ***************************************************************************/
GetRuleProtocol(char * proto_str)3408 static int GetRuleProtocol(char *proto_str)
3409 {
3410     if (strcasecmp(proto_str, RULE_PROTO_OPT__TCP) == 0)
3411     {
3412         return IPPROTO_TCP;
3413     }
3414     else if (strcasecmp(proto_str, RULE_PROTO_OPT__UDP) == 0)
3415     {
3416         return IPPROTO_UDP;
3417     }
3418     else if (strcasecmp(proto_str, RULE_PROTO_OPT__ICMP) == 0)
3419     {
3420         return IPPROTO_ICMP;
3421     }
3422     else if (strcasecmp(proto_str, RULE_PROTO_OPT__IP) == 0)
3423     {
3424         return ETHERNET_TYPE_IP;
3425     }
3426     else
3427     {
3428         /* If we've gotten here, we have a protocol string we didn't recognize
3429          * and should exit */
3430         ParseError("Bad protocol: %s.", proto_str);
3431     }
3432 
3433     return -1;
3434 }
3435 
3436 
ProcessIP(SnortConfig * sc,char * addr,RuleTreeNode * rtn,int mode,int neg_list)3437 static int ProcessIP(SnortConfig *sc, char *addr, RuleTreeNode *rtn, int mode, int neg_list)
3438 {
3439     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
3440 
3441     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got address string: %s\n",
3442                 addr););
3443     assert(rtn);
3444     /* If a rule has a variable in it, we want to copy that variable's
3445      * contents to the IP variable (IP list) stored with the rtn.
3446      * This code tries to look up the variable, and if found, will copy it
3447      * to the rtn->{sip,dip} */
3448     if(mode == SRC)
3449     {
3450         int ret;
3451 
3452         if (rtn->sip == NULL)
3453         {
3454             sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
3455             if (tmp != NULL)
3456             {
3457                 rtn->sip = sfvar_create_alias(tmp, tmp->name);
3458                 if (rtn->sip == NULL)
3459                     ret = SFIP_FAILURE;
3460                 else
3461                     ret = SFIP_SUCCESS;
3462             }
3463             else
3464             {
3465                 rtn->sip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
3466                 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
3467             }
3468         }
3469         else
3470         {
3471             ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
3472         }
3473 
3474         /* The function sfvt_add_to_var adds 'addr' to the variable 'rtn->sip' */
3475         if (ret != SFIP_SUCCESS)
3476         {
3477             if(ret == SFIP_LOOKUP_FAILURE)
3478             {
3479                 ParseError("Undefined variable in the string: %s.", addr);
3480             }
3481             else if(ret == SFIP_CONFLICT)
3482             {
3483                 ParseError("Negated IP ranges that are more general than "
3484                            "non-negated ranges are not allowed. Consider "
3485                            "inverting the logic: %s.", addr);
3486             }
3487             else if(ret == SFIP_NOT_ANY)
3488             {
3489                 ParseError("!any is not allowed: %s.", addr);
3490             }
3491             else
3492             {
3493                 ParseError("Unable to process the IP address: %s.", addr);
3494             }
3495         }
3496 
3497         if(rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
3498         {
3499             rtn->flags |= ANY_SRC_IP;
3500         }
3501     }
3502     /* mode == DST */
3503     else
3504     {
3505         int ret;
3506 
3507         if (rtn->dip == NULL)
3508         {
3509             sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
3510             if (tmp != NULL)
3511             {
3512                 rtn->dip = sfvar_create_alias(tmp, tmp->name);
3513                 if (rtn->dip == NULL)
3514                     ret = SFIP_FAILURE;
3515                 else
3516                     ret = SFIP_SUCCESS;
3517             }
3518             else
3519             {
3520                 rtn->dip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
3521                 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
3522             }
3523         }
3524         else
3525         {
3526             ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
3527         }
3528 
3529         if (ret != SFIP_SUCCESS)
3530         {
3531             if(ret == SFIP_LOOKUP_FAILURE)
3532             {
3533                 ParseError("Undefined variable in the string: %s.", addr);
3534             }
3535             else if(ret == SFIP_CONFLICT)
3536             {
3537                 ParseError("Negated IP ranges that are more general than "
3538                            "non-negated ranges are not allowed. Consider "
3539                            "inverting the logic: %s.", addr);
3540             }
3541             else if(ret == SFIP_NOT_ANY)
3542             {
3543                 ParseError("!any is not allowed: %s.", addr);
3544             }
3545             else
3546             {
3547                 ParseError("Unable to process the IP address: %s.", addr);
3548             }
3549         }
3550 
3551         if(rtn->dip->head && rtn->dip->head->flags & SFIP_ANY)
3552         {
3553             rtn->flags |= ANY_DST_IP;
3554         }
3555     }
3556 
3557     /* Make sure the IP lists provided by the user are valid */
3558     if (mode == SRC)
3559         ValidateIPList(rtn->sip, addr);
3560     else
3561         ValidateIPList(rtn->dip, addr);
3562 
3563     return 0;
3564 }
3565 
3566 
3567 /****************************************************************************
3568  *
3569  * Function: ParsePort(SnortConfig *, char *, u_short *)
3570  *
3571  * Purpose:  Convert the port string over to an integer value
3572  *
3573  * Arguments: prule_port => port rule string
3574  *            port => converted integer value of the port
3575  *
3576  * Returns: 0 for a normal port number, 1 for an "any" port
3577  *
3578  ***************************************************************************/
ParsePort(SnortConfig * sc,char * prule_port,uint16_t * hi_port,uint16_t * lo_port,char * proto,int * not_flag)3579 int ParsePort(SnortConfig *sc, char *prule_port, uint16_t *hi_port, uint16_t *lo_port, char *proto, int *not_flag)
3580 {
3581     char **toks;        /* token dbl buffer */
3582     int num_toks;       /* number of tokens found by mSplit() */
3583     char *rule_port;    /* port string */
3584 
3585     *not_flag = 0;
3586 
3587     /* check for variable */
3588     if(!strncmp(prule_port, "$", 1))
3589     {
3590         if((rule_port = VarGet(sc, prule_port + 1)) == NULL)
3591         {
3592             ParseError("Undefined variable %s.", prule_port);
3593         }
3594     }
3595     else
3596         rule_port = prule_port;
3597 
3598     if(rule_port[0] == '(')
3599     {
3600         /* user forgot to put a port number in for this rule */
3601         ParseError("Bad port number: \"%s\".", rule_port);
3602     }
3603 
3604 
3605     /* check for wildcards */
3606     if(!strcasecmp(rule_port, "any"))
3607     {
3608         *hi_port = 0;
3609         *lo_port = 0;
3610         return 1;
3611     }
3612 
3613     if(rule_port[0] == '!')
3614     {
3615         if(!strcasecmp(&rule_port[1], "any"))
3616         {
3617             ParseWarning("Negating \"any\" is invalid. Rule "
3618                          "will be ignored.");
3619             return -1;
3620         }
3621 
3622         *not_flag = 1;
3623         rule_port++;
3624     }
3625 
3626     if(rule_port[0] == ':')
3627     {
3628         *lo_port = 0;
3629     }
3630 
3631     toks = mSplit(rule_port, ":", 2, &num_toks, 0);
3632 
3633     switch(num_toks)
3634     {
3635         case 1:
3636             *hi_port = (u_short)ConvPort(toks[0], proto);
3637 
3638             if(rule_port[0] == ':')
3639             {
3640                 *lo_port = 0;
3641             }
3642             else
3643             {
3644                 *lo_port = *hi_port;
3645 
3646                 if(strchr(rule_port, ':') != NULL)
3647                 {
3648                     *hi_port = MAXPORTS-1;
3649                 }
3650             }
3651 
3652             break;
3653 
3654         case 2:
3655             *lo_port = (u_short)ConvPort(toks[0], proto);
3656 
3657             if(toks[1][0] == 0)
3658                 *hi_port = MAXPORTS-1;
3659             else
3660                 *hi_port = (u_short)ConvPort(toks[1], proto);
3661 
3662             break;
3663 
3664         default:
3665             ParseError("Port conversion failed on \"%s\".", rule_port);
3666     }
3667 
3668     mSplitFree(&toks, num_toks);
3669 
3670     return 0;
3671 }
3672 
3673 /****************************************************************************
3674  *
3675  * Function: ConvPort(char *, char *)
3676  *
3677  * Purpose:  Convert the port string over to an integer value
3678  *
3679  * Arguments: port => port string
3680  *            proto => converted integer value of the port
3681  *
3682  * Returns:  the port number
3683  *
3684  ***************************************************************************/
ConvPort(char * port,char * proto)3685 uint16_t ConvPort(char *port, char *proto)
3686 {
3687     int conv;           /* storage for the converted number */
3688     char *digit;      /* used to check for a number */
3689     struct servent *service_info;
3690 
3691     /*
3692      * convert a "word port" (http, ftp, imap, whatever) to its corresponding
3693      * numeric port value
3694      */
3695     if(isalpha((int) port[0]) != 0)
3696     {
3697         service_info = getservbyname(port, proto);
3698 
3699         if(service_info != NULL)
3700         {
3701             conv = ntohs(service_info->s_port);
3702             return conv;
3703         }
3704         else
3705         {
3706             ParseError("getservbyname() failed on \"%s\".", port);
3707         }
3708     }
3709     digit = port;
3710     while (*digit) {
3711 
3712         if(!isdigit((int) *digit))
3713         {
3714             ParseError("Invalid port: %s.", port);
3715         }
3716         digit++;
3717     }
3718     /* convert the value */
3719     conv = atoi(port);
3720 
3721     /* make sure it's in bounds */
3722     if ((conv < 0) || (conv > MAXPORTS-1))
3723     {
3724         ParseError("Bad port number: %s.", port);
3725     }
3726 
3727     return (uint16_t)conv;
3728 }
3729 
3730 /****************************************************************************
3731  *
3732  * Function: XferHeader(RuleTreeNode *, RuleTreeNode *)
3733  *
3734  * Purpose: Transfer the rule block header data from point A to point B
3735  *
3736  * Arguments: rule => the place to xfer from
3737  *            rtn => the place to xfer to
3738  *
3739  * Returns: void function
3740  *
3741  ***************************************************************************/
XferHeader(RuleTreeNode * test_node,RuleTreeNode * rtn)3742 static void XferHeader(RuleTreeNode *test_node, RuleTreeNode *rtn)
3743 {
3744     rtn->flags = test_node->flags;
3745     rtn->type = test_node->type;
3746     rtn->sip = test_node->sip;
3747     rtn->dip = test_node->dip;
3748 
3749     rtn->proto = test_node->proto;
3750 
3751     rtn->src_portobject = test_node->src_portobject;
3752     rtn->dst_portobject = test_node->dst_portobject;
3753 }
3754 
3755 /****************************************************************************
3756  *
3757  * Function: CompareIPNodes(RuleTreeNode *, RuleTreeNode *).  Support function
3758  *           for CompareIPLists.
3759  *
3760  * Purpose: Checks if the node's contents equal.
3761  *
3762  * Returns: 1 if they match, 0 if they don't
3763  *
3764  ***************************************************************************/
CompareIPNodes(IpAddrNode * one,IpAddrNode * two)3765 int CompareIPNodes(IpAddrNode *one, IpAddrNode *two)
3766 {
3767      if( (sfip_compare(&one->ip->addr, &two->ip->addr) != SFIP_EQUAL) ||
3768          (sfip_bits(one->ip) != sfip_bits(two->ip)) ||
3769          (sfvar_flags(one) != sfvar_flags(two)) )
3770          return 0;
3771     return 1;
3772 }
3773 
3774 
3775 /****************************************************************************
3776  *
3777  * Function: TestHeader(RuleTreeNode *, RuleTreeNode *)
3778  *
3779  * Purpose: Check to see if the two header blocks are identical
3780  *
3781  * Arguments: rule => uh
3782  *            rtn  => uuuuhhhhh....
3783  *
3784  * Returns: 1 if they match, 0 if they don't
3785  *
3786  ***************************************************************************/
TestHeader(RuleTreeNode * rule,RuleTreeNode * rtn)3787 static int TestHeader(RuleTreeNode * rule, RuleTreeNode * rtn)
3788 {
3789     if ((rule == NULL) || (rtn == NULL))
3790         return 0;
3791 
3792     if (rule->type != rtn->type)
3793         return 0;
3794 
3795     if (rule->proto != rtn->proto)
3796         return 0;
3797 
3798     /* For custom rule type declarations */
3799     if (rule->listhead != rtn->listhead)
3800         return 0;
3801 
3802     if (rule->flags != rtn->flags)
3803         return 0;
3804 
3805     if ((rule->sip != NULL) && (rtn->sip != NULL) &&
3806             (sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL))
3807     {
3808         return 0;
3809     }
3810 
3811     if ((rule->dip != NULL) && (rtn->dip != NULL) &&
3812             (sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL))
3813     {
3814         return 0;
3815     }
3816 
3817     /* compare the port group pointers - this prevents confusing src/dst port objects
3818      * with the same port set, and it's quicker. It does assume that we only have
3819      * one port object and pointer for each unique port set...this is handled by the
3820      * parsing and initial port object storage and lookup.  This must be consistent during
3821      * the rule parsing phase. - man */
3822     if ((rule->src_portobject != rtn->src_portobject)
3823             || (rule->dst_portobject != rtn->dst_portobject))
3824     {
3825         return 0;
3826     }
3827 
3828     return 1;
3829 }
3830 
3831 /*
3832  * PortVarDefine
3833  *
3834  *  name - portlist name, i.e. http, smtp, ...
3835  *  s    - port number, port range, or a list of numbers/ranges in brackets
3836  *
3837  *  examples:
3838  *  portvar http [80,8080,8138,8700:8800,!8711]
3839  *  portvar http $http_basic
3840  */
PortVarDefine(SnortConfig * sc,char * name,char * s)3841 static int PortVarDefine(SnortConfig *sc, char *name, char *s)
3842 {
3843     PortObject *po;
3844     POParser pop;
3845     char *errstr="unknown";
3846     int   rstat;
3847     PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
3848     char *end;
3849     bool invalidvar = true;
3850 
3851     DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__PORTVAR);
3852 
3853     for(end = name; *end && !isspace((int)*end) && *end != '\\'; end++)
3854     {
3855        if(isalpha((int)*end))
3856                invalidvar = false;
3857     }
3858 
3859     if(invalidvar)
3860 	ParseError("Can not define variable name - %s. Use different name", name);
3861 
3862     if( SnortStrcasestr(s,strlen(s),"any") ) /* this allows 'any' or '[any]' */
3863     {
3864         if(strstr(s,"!"))
3865         {
3866             ParseError("Illegal use of negation and 'any': %s.", s);
3867         }
3868 
3869         po = PortObjectNew();
3870         if( !po )
3871         {
3872             ParseError("PortVarTable missing an 'any' variable.\n");
3873         }
3874         PortObjectSetName( po, name );
3875         PortObjectAddPortAny( po );
3876     }
3877     else
3878     {
3879         /* Parse the Port List info into a PortObject  */
3880         po = PortObjectParseString(portVarTable, &pop, name, s, 0);
3881         if(!po)
3882         {
3883             errstr = PortObjectParseError( &pop );
3884             ParseError("*** PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s.",
3885                        pop.pos,errstr,s,pop.pos,"^");
3886         }
3887     }
3888 
3889     /* Add The PortObject to the PortList Table */
3890     rstat = PortVarTableAdd(portVarTable, po);
3891     if( rstat < 0 )
3892     {
3893         ParseError("***PortVarTableAdd failed with '%s', exiting.", po->name);
3894     }
3895     else if( rstat > 0 )
3896     {
3897         ParseMessage("PortVar '%s', already defined.", po->name);
3898     }
3899 
3900     /* Print the PortList - PortObjects */
3901     LogMessage("PortVar '%s' defined : ",po->name);
3902     PortObjectPrintPortsRaw(po);
3903     LogMessage("\n");
3904 
3905     return 0;
3906 }
3907 
3908 /****************************************************************************
3909  *
3910  * Function: VarAlloc()
3911  *
3912  * Purpose: allocates memory for a variable
3913  *
3914  * Arguments: none
3915  *
3916  * Returns: pointer to new VarEntry
3917  *
3918  ***************************************************************************/
VarAlloc()3919 VarEntry *VarAlloc()
3920 {
3921     VarEntry *new;
3922 
3923     new = (VarEntry *)SnortAlloc(sizeof(VarEntry));
3924 
3925     return(new);
3926 }
3927 
3928 /****************************************************************************
3929  *
3930  * Function: VarIsIpAddr(char *, char *)
3931  *
3932  * Purpose: Checks if a var is an IP address. Necessary since moving forward
3933  *          we want all IP addresses handled by the IP variable table.
3934  *          If a list is given, this checks each value.
3935  *
3936  * Arguments: value => the string to check
3937  *
3938  * Returns: 1 if IP address, 0 otherwise
3939  *
3940  ***************************************************************************/
VarIsIpAddr(vartable_t * ip_vartable,char * value)3941 static int VarIsIpAddr(vartable_t *ip_vartable, char *value)
3942 {
3943     char *tmp;
3944 
3945     /* empty list, consider this an IP address */
3946     if ((*value == '[') && (*(value+1) == ']'))
3947         return 1;
3948 
3949     while(*value == '!' || *value == '[') value++;
3950 
3951     /* Check for dotted-quad */
3952     if( isdigit((int)*value) &&
3953          ((tmp = strchr(value, (int)'.')) != NULL) &&
3954          ((tmp = strchr(tmp+1, (int)'.')) != NULL) &&
3955          (strchr(tmp+1, (int)'.') != NULL))
3956         return 1;
3957 
3958     /* IPv4 with a mask, and fewer than 4 fields */
3959     else if( isdigit((int)*value) &&
3960          (strchr(value+1, (int)':') == NULL) &&
3961          ((tmp = strchr(value+1, (int)'/')) != NULL) &&
3962          isdigit((int)(*(tmp+1))) )
3963         return 1;
3964 
3965     /* IPv6 */
3966     else if((tmp = strchr(value, (int)':')) != NULL)
3967     {
3968         char *tmp2;
3969 
3970         if((tmp2 = strchr(tmp+1, (int)':')) == NULL)
3971             return 0;
3972 
3973         for(tmp++; tmp < tmp2; tmp++)
3974             if(!isxdigit((int)*tmp))
3975                 return 0;
3976 
3977         return 1;
3978     }
3979 
3980     /* Any */
3981     else if(!strncmp(value, "any", 3))
3982         return 1;
3983 
3984     /* Check if it's a variable containing an IP */
3985     else if(sfvt_lookup_var(ip_vartable, value+1) || sfvt_lookup_var(ip_vartable, value))
3986         return 1;
3987 
3988     return 0;
3989 }
3990 
3991 /****************************************************************************
3992  *
3993  * Function: CheckBrackets(char *)
3994  *
3995  * Purpose: Check that the brackets match up in a string that
3996  *          represents a list.
3997  *
3998  * Arguments: value => the string to check
3999  *
4000  * Returns: 1 if the brackets match correctly, 0 otherwise
4001  *
4002  ***************************************************************************/
CheckBrackets(char * value)4003 static int CheckBrackets(char *value)
4004 {
4005     int num_brackets = 0;
4006 
4007     while (*value == '!')
4008         value++;
4009 
4010     if ((value[0] != '[') || value[strlen(value)-1] != ']')
4011     {
4012         /* List does not begin or end with a bracket. */
4013         return 0;
4014     }
4015 
4016     while ((*value != '\0') && (num_brackets >= 0))
4017     {
4018         if (*value == '[')
4019             num_brackets++;
4020         else if (*value == ']')
4021             num_brackets--;
4022         value++;
4023     }
4024     if (num_brackets != 0)
4025     {
4026         /* Mismatched brackets */
4027         return 0;
4028     }
4029 
4030     return 1;
4031 }
4032 
4033 /****************************************************************************
4034  *
4035  * Function: VarIsIpList(vartable_t *, char*)
4036  *
4037  * Purpose: Checks if a var is a list of IP addresses.
4038  *
4039  * Arguments: value => the string to check
4040  *
4041  * Returns: 1 if each item is an IP address, 0 otherwise
4042  *
4043  ***************************************************************************/
VarIsIpList(vartable_t * ip_vartable,char * value)4044 static int VarIsIpList(vartable_t *ip_vartable, char *value)
4045 {
4046     char *copy, *item;
4047     int item_is_ip = 1;
4048 
4049     copy = SnortStrdup((const char*)value);
4050 
4051     /* Ensure that the brackets are correct. */
4052     if (strchr((const char*)copy, ','))
4053     {
4054         /* This is a list! */
4055         if (CheckBrackets(copy) == 0)
4056         {
4057             free(copy);
4058             return 0;
4059         }
4060     }
4061 
4062     /* There's no need to worry about the list structure here.
4063      * We just strip out the IP delimiters and process each one. */
4064     item = strtok(copy, "[],!");
4065     while ((item != NULL) && item_is_ip)
4066     {
4067         item_is_ip = VarIsIpAddr(ip_vartable, item);
4068         item = strtok(NULL, "[],!");
4069     }
4070 
4071     free(copy);
4072     return item_is_ip;
4073 }
4074 
4075 /****************************************************************************
4076  *
4077  * Function: DisallowCrossTableDuplicateVars(char *, int)
4078  *
4079  * Purpose: FatalErrors if the a variable name is redefined across variable
4080  *          types.  Enforcing this mutual exclusion prevents the
4081  *          catatrophe where the variable lookup fall-through (see VarSearch)
4082  *          finds an unintended variable from the wrong table.  Note:  VarSearch
4083  *          is only necessary for ExpandVars.
4084  *
4085  * Arguments: name => The name of the variable
4086  *            var_type => The type of the variable that is about to be defined.
4087  *                        The corresponding variable table will not be searched.
4088  *
4089  * Returns: void function
4090  *
4091  ***************************************************************************/
DisallowCrossTableDuplicateVars(SnortConfig * sc,char * name,VarType var_type)4092 static void DisallowCrossTableDuplicateVars(SnortConfig *sc, char *name, VarType var_type)
4093 {
4094     VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4095     PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
4096     VarEntry *p = var_table;
4097     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4098 
4099     /* If this is a faked Portvar, treat as a portvar */
4100     if ((var_type == VAR_TYPE__DEFAULT) &&
4101         (strstr(name, "_PORT") || strstr(name, "PORT_")))
4102     {
4103         var_type = VAR_TYPE__PORTVAR;
4104     }
4105 
4106     switch (var_type)
4107     {
4108         case VAR_TYPE__DEFAULT:
4109             if (PortVarTableFind(portVarTable, name)
4110                     || sfvt_lookup_var(ip_vartable, name)
4111                )
4112             {
4113                 ParseError("Can not redefine variable name %s to be of type "
4114                            "'var'. Use a different name.", name);
4115             }
4116             break;
4117 
4118         case VAR_TYPE__PORTVAR:
4119             if (var_table != NULL)
4120             {
4121                 do
4122                 {
4123                     if(strcasecmp(p->name, name) == 0)
4124                     {
4125                         ParseError("Can not redefine variable name %s to be of "
4126                                    "type 'portvar'. Use a different name.", name);
4127                     }
4128                     p = p->next;
4129                 } while(p != var_table);
4130             }
4131 
4132             if(sfvt_lookup_var(ip_vartable, name))
4133             {
4134                 ParseError("Can not redefine variable name %s to be of type "
4135                            "'portvar'. Use a different name.", name);
4136             }
4137 
4138             break;
4139 
4140         case VAR_TYPE__IPVAR:
4141             if (var_table != NULL)
4142             {
4143                 do
4144                 {
4145                     if(strcasecmp(p->name, name) == 0)
4146                     {
4147                         ParseError("Can not redefine variable name %s to be of "
4148                                    "type 'ipvar'. Use a different name.", name);
4149                     }
4150 
4151                     p = p->next;
4152                 } while(p != var_table);
4153             }
4154 
4155             if(PortVarTableFind(portVarTable, name))
4156             {
4157                 ParseError("Can not redefine variable name %s to be of type "
4158                            "'ipvar'. Use a different name.", name);
4159             }
4160 
4161         default:
4162             /* Invalid function usage */
4163             break;
4164     }
4165 }
4166 
4167 /****************************************************************************
4168  *
4169  * Function: VarDefine(char *, char *)
4170  *
4171  * Purpose: define the contents of a variable
4172  *
4173  * Arguments: name => the name of the variable
4174  *            value => the contents of the variable
4175  *
4176  * Returns: void function
4177  *
4178  ***************************************************************************/
VarDefine(SnortConfig * sc,char * name,char * value)4179 VarEntry * VarDefine(SnortConfig *sc, char *name, char *value)
4180 {
4181     VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4182     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4183     VarEntry *p;
4184     uint32_t var_id = 0;
4185 
4186     if(value == NULL)
4187     {
4188         ParseError("Bad value in variable definition!  Make sure you don't "
4189                    "have a \"$\" in the var name.");
4190     }
4191 
4192     if(VarIsIpList(ip_vartable, value))
4193     {
4194         SFIP_RET ret;
4195 
4196         if (ip_vartable == NULL)
4197             return NULL;
4198 
4199         /* Verify a variable by this name is not already used as either a
4200          * portvar or regular var.  Enforcing this mutual exclusion prevents the
4201          * catatrophe where the variable lookup fall-through (see VarSearch)
4202          * finds an unintended variable from the wrong table.  Note:  VarSearch
4203          * is only necessary for ExpandVars. */
4204         DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__IPVAR);
4205 
4206         if((ret = sfvt_define(ip_vartable, name, value)) != SFIP_SUCCESS)
4207         {
4208             switch(ret) {
4209                 case SFIP_ARG_ERR:
4210                     ParseError("The following is not allowed: %s.", value);
4211                     break;
4212 
4213                 case SFIP_DUPLICATE:
4214                     ParseMessage("Var '%s' redefined.", name);
4215                     break;
4216 
4217                 case SFIP_CONFLICT:
4218                     ParseError("Negated IP ranges that are more general than "
4219                                "non-negated ranges are not allowed. Consider "
4220                                "inverting the logic in %s.", name);
4221                     break;
4222 
4223                 case SFIP_NOT_ANY:
4224                     ParseError("!any is not allowed in %s.", name);
4225                     break;
4226 
4227                 default:
4228                     ParseError("Failed to parse the IP address: %s.", value);
4229             }
4230         }
4231         return NULL;
4232     }
4233     /* Check if this is a variable that stores an IP */
4234     else if(*value == '$')
4235     {
4236         sfip_var_t *var;
4237         if((var = sfvt_lookup_var(ip_vartable, value)) != NULL)
4238         {
4239             sfvt_define(ip_vartable, name, value);
4240             return NULL;
4241         }
4242     }
4243 
4244 
4245     DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
4246                "VarDefine: name=%s value=%s\n",name,value););
4247 
4248     /* Check to see if this variable is just being aliased */
4249     if (var_table != NULL)
4250     {
4251         VarEntry *tmp = var_table;
4252 
4253         do
4254         {
4255             /* value+1 to move past $ */
4256             if (strcmp(tmp->name, value+1) == 0)
4257             {
4258                 var_id = tmp->id;
4259                 break;
4260             }
4261 
4262             tmp = tmp->next;
4263 
4264         } while (tmp != var_table);
4265     }
4266 
4267     value = ExpandVars(sc, value);
4268     if(!value)
4269     {
4270         ParseError("Could not expand var('%s').", name);
4271     }
4272 
4273     DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
4274                "VarDefine: name=%s value=%s (expanded)\n",name,value););
4275 
4276     DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__DEFAULT);
4277 
4278     if (var_table == NULL)
4279     {
4280         p = VarAlloc();
4281         p->name  = SnortStrdup(name);
4282         p->value = SnortStrdup(value);
4283 
4284         p->prev = p;
4285         p->next = p;
4286 
4287         sc->targeted_policies[getParserPolicy(sc)]->var_table = p;
4288 
4289         p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
4290 
4291         return p;
4292     }
4293 
4294     /* See if an existing variable is being redefined */
4295     p = var_table;
4296 
4297     do
4298     {
4299         if (strcasecmp(p->name, name) == 0)
4300         {
4301             if (p->value != NULL)
4302                 free(p->value);
4303 
4304             p->value = SnortStrdup(value);
4305             ParseWarning("Var '%s' redefined\n", p->name);
4306             return p;
4307         }
4308 
4309         p = p->next;
4310 
4311     } while (p != var_table);   /* List is circular */
4312 
4313     p = VarAlloc();
4314     p->name  = SnortStrdup(name);
4315     p->value = SnortStrdup(value);
4316     p->prev = var_table;
4317     p->next = var_table->next;
4318     p->next->prev = p;
4319     var_table->next = p;
4320 
4321     if (!var_id)
4322         p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
4323     else
4324         p->id = var_id;
4325 
4326 #ifdef XXXXXXX
4327     vlen = strlen(value);
4328     LogMessage("Var '%s' defined, value len = %d chars", p->name, vlen  );
4329 
4330     if( vlen < 64 )
4331     {
4332       LogMessage(", value = %s\n", value );
4333     }
4334     else
4335     {
4336       LogMessage("\n");
4337       n = 128;
4338       s = value;
4339       while(vlen)
4340       {
4341          if( n > vlen ) n = vlen;
4342          LogMessage("   %.*s\n", n, s );
4343          s    += n;
4344          vlen -= n;
4345       }
4346     }
4347 #endif
4348 
4349     return p;
4350 }
4351 
DeleteVars(VarEntry * var_table)4352 static void DeleteVars(VarEntry *var_table)
4353 {
4354     VarEntry *q, *p = var_table;
4355 
4356     while (p)
4357     {
4358         q = p->next;
4359         if (p->name)
4360             free(p->name);
4361         if (p->value)
4362             free(p->value);
4363         if (p->addrset)
4364         {
4365             IpAddrSetDestroy(p->addrset);
4366         }
4367         free(p);
4368         p = q;
4369         if (p == var_table)
4370             break;  /* Grumble, it's a friggin circular list */
4371     }
4372 }
4373 
4374 /****************************************************************************
4375  *
4376  * Function: VarGet(SnortConfig *, char *)
4377  *
4378  * Purpose: get the contents of a variable
4379  *
4380  * Arguments: name => the name of the variable
4381  *
4382  * Returns: char * to contents of variable or FatalErrors on an
4383  *          undefined variable name
4384  *
4385  ***************************************************************************/
VarGet(SnortConfig * sc,char * name)4386 char *VarGet(SnortConfig *sc, char *name)
4387 {
4388     SnortPolicy *policy;
4389     VarEntry *var_table;
4390     vartable_t *ip_vartable;
4391     sfip_var_t *var;
4392 
4393     if (sc == NULL)
4394         return NULL;
4395 
4396     policy = sc->targeted_policies[getParserPolicy(sc)];
4397     if (policy == NULL)
4398         return NULL;
4399 
4400     var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
4401 
4402 // XXX-IPv6 This function should never be used if IP6 support is enabled!
4403 // Infact it won't presently even work for IP variables since the raw ASCII
4404 // value is never stored, and is never meant to be used.
4405     ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
4406 
4407     if((var = sfvt_lookup_var(ip_vartable, name)) == NULL) {
4408         /* Do the old style lookup since it wasn't found in
4409          * the variable table */
4410         if(var_table != NULL)
4411         {
4412             VarEntry *p = var_table;
4413             do
4414             {
4415                 if(strcasecmp(p->name, name) == 0)
4416                     return p->value;
4417                 p = p->next;
4418             } while(p != var_table);
4419         }
4420 
4421         ParseError("Undefined variable name: %s.", name);
4422     }
4423 
4424     return name;
4425 
4426 }
4427 
4428 /****************************************************************************
4429  *
4430  * Function: ExpandVars()
4431  *
4432  * Purpose: expand all variables in a string
4433  *
4434  * Arguments:
4435  *  SnortConfig *
4436  *      The snort config that has the vartables.
4437  *  char *
4438  *      The name of the variable.
4439  *
4440  * Returns:
4441  *  char *
4442  *      The expanded string.  Note that the string is returned in a
4443  *      static variable and most likely needs to be string dup'ed.
4444  *
4445  ***************************************************************************/
ExpandVars(SnortConfig * sc,char * string)4446 static char * ExpandVars(SnortConfig *sc, char *string)
4447 {
4448     static char estring[ PARSERULE_SIZE ];
4449 
4450     char rawvarname[128], varname[128], varaux[128], varbuffer[128];
4451     char varmodifier, *varcontents;
4452     int varname_completed, c, i, j, iv, jv, l_string, name_only;
4453     int quote_toggle = 0;
4454 
4455     if(!string || !*string || !strchr(string, '$'))
4456         return(string);
4457 
4458     memset((char *) estring, 0, PARSERULE_SIZE);
4459 
4460     i = j = 0;
4461     l_string = strlen(string);
4462     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string););
4463 
4464     while(i < l_string && j < (int)sizeof(estring) - 1)
4465     {
4466         c = string[i++];
4467 
4468         if(c == '"')
4469         {
4470             /* added checks to make sure that we are inside a quoted string
4471              */
4472             quote_toggle ^= 1;
4473         }
4474 
4475         if(c == '$' && !quote_toggle)
4476         {
4477             memset((char *) rawvarname, 0, sizeof(rawvarname));
4478             varname_completed = 0;
4479             name_only = 1;
4480             iv = i;
4481             jv = 0;
4482 
4483             if(string[i] == '(')
4484             {
4485                 name_only = 0;
4486                 iv = i + 1;
4487             }
4488 
4489             while(!varname_completed
4490                   && iv < l_string
4491                   && jv < (int)sizeof(rawvarname) - 1)
4492             {
4493                 c = string[iv++];
4494 
4495                 if((name_only && !(isalnum(c) || c == '_'))
4496                    || (!name_only && c == ')'))
4497                 {
4498                     varname_completed = 1;
4499 
4500                     if(name_only)
4501                         iv--;
4502                 }
4503                 else
4504                 {
4505                     rawvarname[jv++] = (char)c;
4506                 }
4507             }
4508 
4509             if(varname_completed || iv == l_string)
4510             {
4511                 char *p;
4512 
4513                 i = iv;
4514 
4515                 varcontents = NULL;
4516 
4517                 memset((char *) varname, 0, sizeof(varname));
4518                 memset((char *) varaux, 0, sizeof(varaux));
4519                 varmodifier = ' ';
4520 
4521                 p = strchr(rawvarname, ':');
4522                 if (p)
4523                 {
4524                     SnortStrncpy(varname, rawvarname, p - rawvarname);
4525 
4526                     if(strlen(p) >= 2)
4527                     {
4528                         varmodifier = *(p + 1);
4529                         SnortStrncpy(varaux, p + 2, sizeof(varaux));
4530                     }
4531                 }
4532                 else
4533                     SnortStrncpy(varname, rawvarname, sizeof(varname));
4534 
4535                 memset((char *) varbuffer, 0, sizeof(varbuffer));
4536 
4537                 varcontents = VarSearch(sc, varname);
4538 
4539                 switch(varmodifier)
4540                 {
4541                     case '-':
4542                         if(!varcontents || !strlen(varcontents))
4543                             varcontents = varaux;
4544                         break;
4545 
4546                     case '?':
4547                         if(!varcontents || !strlen(varcontents))
4548                         {
4549                             ErrorMessage("%s(%d): ", file_name, file_line);
4550 
4551                             if(strlen(varaux))
4552                                 ParseError("%s", varaux);
4553                             else
4554                                 ParseError("Undefined variable \"%s\".", varname);
4555                         }
4556                         break;
4557                 }
4558 
4559                 /* If variable not defined now, we're toast */
4560                 if(!varcontents || !strlen(varcontents))
4561                     ParseError("Undefined variable name: %s.", varname);
4562 
4563                 if(varcontents)
4564                 {
4565                     int l_varcontents = strlen(varcontents);
4566 
4567                     iv = 0;
4568 
4569                     while(iv < l_varcontents && j < (int)sizeof(estring) - 1)
4570                         estring[j++] = varcontents[iv++];
4571                 }
4572             }
4573             else
4574             {
4575                 estring[j++] = '$';
4576             }
4577         }
4578         else
4579         {
4580             estring[j++] = (char)c;
4581         }
4582     }
4583 
4584     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring););
4585 
4586     return estring;
4587 }
4588 
ProcessFileOption(SnortConfig * sc,const char * filespec)4589 char * ProcessFileOption(SnortConfig *sc, const char *filespec)
4590 {
4591     char *filename = NULL;
4592     char buffer[STD_BUF];
4593 
4594     if (sc == NULL)
4595         sc = snort_conf;
4596 
4597     if(filespec == NULL)
4598     {
4599         ParseError("no argument in this file option, remove extra ':' at the end of the alert option\n");
4600     }
4601 
4602     /* look for ".." in the string and complain and exit if it is found */
4603     if(strstr(filespec, "..") != NULL)
4604     {
4605         ParseError("file definition contains \"..\".  Do not do that!\n");
4606     }
4607 
4608     if(filespec[0] == '/')
4609     {
4610         /* absolute filespecs are saved as is */
4611         filename = SnortStrdup(filespec);
4612     }
4613     else
4614     {
4615         /* relative filespec is considered relative to the log directory */
4616         /* or /var/log if the log directory has not been set */
4617         /* Make sure this function isn't called before log dir is set */
4618         if ((sc != NULL) && (sc->log_dir != NULL))
4619         {
4620             strlcpy(buffer, snort_conf->log_dir, STD_BUF);
4621         }
4622         else
4623         {
4624             strlcpy(buffer, "/var/log/snort", STD_BUF);
4625         }
4626 
4627         strlcat(buffer, "/", STD_BUF - strlen(buffer));
4628         strlcat(buffer, filespec, STD_BUF - strlen(buffer));
4629         buffer[sizeof(buffer) - 1] = '\0';
4630         filename = SnortStrdup(buffer);
4631     }
4632 
4633     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ProcessFileOption: %s\n", filename););
4634 
4635     return filename;
4636 }
4637 
4638 
4639 #ifdef TARGET_BASED
ParseAttributeTable(SnortConfig * sc,SnortPolicy * p,char * args)4640 static void ParseAttributeTable(SnortConfig *sc, SnortPolicy *p, char *args)
4641 {
4642     tSfPolicyId currentPolicyId = getParserPolicy(sc);
4643     tSfPolicyId defaultPolicyId = sfGetDefaultPolicy(sc->policy_config);
4644     TargetBasedConfig *defTbc = &sc->targeted_policies[defaultPolicyId]->target_based_config;
4645 
4646     /* Save for configuring after configuration is parsed in case
4647      * config max_attribute_hosts is configured after this */
4648     if ((currentPolicyId != defaultPolicyId)
4649             && ((defTbc->args == NULL) || (strcmp(args, defTbc->args) != 0)))
4650     {
4651         //arguments should be same as in default policy. Ignoring the arguments
4652         ParseError("Attribute table must be configured in default policy if "
4653                    "it is to be used in other policies and attribute table "
4654                    "filename must be the same across policies.");
4655     }
4656 
4657     if(p->target_based_config.args)
4658         free(p->target_based_config.args);
4659     p->target_based_config.args = SnortStrdup(args);
4660 
4661     if (file_name != NULL)
4662     {
4663         if(p->target_based_config.file_name)
4664             free(p->target_based_config.file_name);
4665         p->target_based_config.file_name = SnortStrdup(file_name);
4666         p->target_based_config.file_line = file_line;
4667     }
4668 }
4669 #endif
4670 
ParseConfig(SnortConfig * sc,SnortPolicy * p,char * args)4671 static void ParseConfig(SnortConfig *sc, SnortPolicy *p, char *args)
4672 {
4673     char **toks;
4674     int num_toks;
4675     char *opts = NULL;
4676     int i;
4677 
4678     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n"););
4679 
4680     toks = mSplit(args, ":", 2, &num_toks, 0);
4681 
4682     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Opt: %s\n", toks[0]););
4683 
4684     if (num_toks > 1)
4685     {
4686         /* Dup the opts because we're putting into hash table */
4687         opts = SnortStrdup(toks[1]);
4688         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Args: %s\n", opts););
4689     }
4690 
4691     switch (sfghash_add(sc->config_table, toks[0], opts))
4692     {
4693         case SFGHASH_NOMEM:
4694             ParseError("%s(%d) No memory to add entry to config table.\n",
4695                        __FILE__, __LINE__);
4696             break;
4697 
4698         case SFGHASH_INTABLE:
4699             /* Only reference and classifications are likely dup candidates
4700              * right now and we're not too worried about keeping track of
4701              * all of them */
4702             if (opts != NULL)
4703             {
4704                 free(opts);
4705                 opts = toks[1];
4706             }
4707 
4708             break;
4709 
4710         default:
4711             break;
4712     }
4713 
4714     for (i = 0; config_opts[i].name != NULL; i++)
4715     {
4716         if (strcasecmp(toks[0], config_opts[i].name) == 0)
4717         {
4718                 if ((getParserPolicy(sc) != getDefaultPolicy()) &&
4719                 config_opts[i].default_policy_only)
4720                 {
4721                         /* Config option configurable on by the default policy*/
4722                 /**Dont raise parse error, ignore any config that is not allowed in non-default
4723                  * policy.
4724                  */
4725                 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config option \"%s\" "
4726                     "configurable only by default policy. Ignoring it\n", toks[0]));
4727                 break;
4728                 }
4729 
4730             if (config_opts[i].only_once && config_opt_configured[i])
4731             {
4732                 /* Configured already and set to only configure once
4733                  * This array is reset for each policy read in so this is
4734                  * on a per policy basis */
4735                 ParseError("Config option \"%s\" can only be "
4736                            "configured once.", toks[0]);
4737             }
4738 
4739             if (config_opts[i].args_required && (opts == NULL))
4740             {
4741                 /* Need arguments and there are none */
4742                  ParseError("Config option \"%s\" requires arguments.", toks[0]);
4743             }
4744 
4745             config_opts[i].parse_func(sc, opts);
4746             config_opt_configured[i] = 1;
4747             break;
4748         }
4749     }
4750 
4751     if (config_opts[i].name == NULL)
4752     {
4753         /* Didn't find a matching config option */
4754         ParseError("Unknown config directive: %s.", toks[0]);
4755     }
4756 
4757     mSplitFree(&toks, num_toks);
4758 }
4759 
4760 /****************************************************************************
4761  *
4762  * Purpose: Check that special rules have an OTN.
4763  *          TODO: Free up memory associated with disabled rules.
4764  *
4765  * Arguments: list => Pointer for a list of rules
4766  *
4767  * Returns: void function
4768  *
4769  * Notes: man - modified to used .shared flag in otn sigInfo instead of specialGID
4770  *        sas - removed specialGID
4771  *
4772  *****************************************************************************/
CheckRuleStates(SnortConfig * sc)4773 int CheckRuleStates(SnortConfig *sc)
4774 {
4775     RuleTreeNode *rtn;
4776     OptTreeNode *otn;
4777     SFGHASH_NODE *hashNode;
4778     int oneErr = 0;
4779     tSfPolicyId policyId = 0;
4780 
4781     if (sc == NULL)
4782         return 0;
4783 
4784     for (hashNode = sfghash_findfirst(sc->otn_map);
4785          hashNode;
4786          hashNode = sfghash_findnext(sc->otn_map))
4787     {
4788         otn = (OptTreeNode *)hashNode->data;
4789         for (policyId = 0;
4790              policyId < otn->proto_node_num;
4791              policyId++)
4792         {
4793             rtn = otn->proto_nodes[policyId];
4794 
4795             if (!rtn)
4796             {
4797                 continue;
4798             }
4799 
4800             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP) ||
4801                 (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
4802             {
4803                 //do operation
4804                 if ( otn->sigInfo.shared )
4805                 {
4806                     if (otn->ds_list[PLUGIN_DYNAMIC] == NULL)
4807                     {
4808                         // Have a dynamic rule but no dynamic plugin
4809                         if (otn->sigInfo.id != otn->sigInfo.otnKey.sid)
4810                         {
4811                             // If its a different SID, but same soid metadata as something
4812                             // else, try to find it
4813                             OptTreeNode *otn_original;
4814                             otn_original = SoRuleOtnLookup(sc->so_rule_otn_map,
4815                                 otn->sigInfo.otnKey.gid, otn->sigInfo.otnKey.sid);
4816 
4817                             if ( otn_original && (otn != otn_original) &&
4818                                 !otn->sigInfo.dup_opt_func )
4819                             {
4820                                 OptFpList *opt_func = otn->opt_func;
4821                                 while (opt_func != NULL)
4822                                 {
4823                                     /* Delete the option functions that came from the
4824                                      * parsing -- this rule will be identical to its
4825                                      * "cloned" brother. */
4826                                     OptFpList *tmp = opt_func;
4827                                     opt_func = opt_func->next;
4828                                     free(tmp);
4829                                 }
4830                                 if (otn_original->sigInfo.shared)
4831                                 {
4832                                     /* Its still a shared object -- has its own detection function.  */
4833                                     otn->ds_list[PLUGIN_DYNAMIC] = otn_original->ds_list[PLUGIN_DYNAMIC];
4834                                 }
4835                                 else
4836                                 {
4837                                     /* It was back-converted from a shared object */
4838                                     int i;
4839                                     for (i=PLUGIN_CLIENTSERVER; i<PLUGIN_MAX; i++)
4840                                     {
4841                                         otn->ds_list[i] = otn_original->ds_list[i];
4842                                     }
4843                                     otn->sigInfo.shared = 0; /* no longer shared */
4844                                 }
4845                                 otn->opt_func = otn_original->opt_func;
4846                                 otn->sigInfo.dup_opt_func = 1;
4847                             }
4848                         }
4849                     }
4850 
4851                     if (otn->sigInfo.shared && (otn->ds_list[PLUGIN_DYNAMIC] == NULL))
4852                     {
4853                         /* If still shared... */
4854                         ErrorMessage("Encoded Rule Plugin SID: %d, GID: %d not "
4855                                    "registered properly.  Disabling this rule.\n",
4856                                    otn->sigInfo.id, otn->sigInfo.generator);
4857                         oneErr = 1;
4858                         otn->rule_state = RULE_STATE_DISABLED;
4859                     }
4860                 }
4861             }
4862         }
4863     }
4864 
4865     return oneErr;
4866 }
4867 
4868 /****************************************************************************
4869  *
4870  * Purpose: Adjust the information for a given rule
4871  *          relative to the Rule State list
4872  *
4873  * Arguments: None
4874  *
4875  * Returns: void function
4876  *
4877  * Notes:  specialGID is depracated, uses sigInfo.shared flag
4878  *
4879  *****************************************************************************/
SetRuleStates(SnortConfig * sc)4880 void SetRuleStates(SnortConfig *sc)
4881 {
4882     RuleState *rule_state;
4883 #if 0
4884     int oneErr = 0, err;
4885 #endif
4886 
4887     if (sc == NULL)
4888         return;
4889 
4890     /* First, cycle through the rule state list and update the
4891      * rule state for each one we find. */
4892     for (rule_state = sc->rule_state_list; rule_state != NULL; rule_state = rule_state->next)
4893     {
4894         /* Lookup the OTN by ruleState->sid, ruleState->gid */
4895         OptTreeNode *otn = OtnLookup(sc->otn_map, rule_state->gid, rule_state->sid);
4896 
4897         if (otn == NULL)
4898         {
4899             ParseError("Rule state specified for invalid SID: %d GID: %d\n",
4900                        rule_state->sid, rule_state->gid);
4901         }
4902 
4903         otn->rule_state = rule_state->state;
4904     }
4905 
4906     /* Check TCP/UDP/ICMP/IP in one iteration for all rulelists and for all policies*/
4907 #if 1
4908     CheckRuleStates(sc);
4909 #else
4910     err = CheckRuleStates(sc);
4911     if (err)
4912         oneErr = 1;
4913 
4914     if (oneErr)
4915     {
4916         FatalError("Misconfigured or unregistered encoded rule plugins\n");
4917     }
4918 #endif
4919 }
4920 
4921 /****************************************************************************
4922  *
4923  * Purpose: Parses a rule state line.
4924  *          Format is sid, gid, state, action.
4925  *          state should be "enabled" or "disabled"
4926  *          action should be "alert", "drop", "sdrop", "log", etc.
4927  *
4928  * Arguments: args => string containing a single rule state entry
4929  *
4930  * Returns: void function
4931  *
4932  *****************************************************************************/
ParseRuleState(SnortConfig * sc,SnortPolicy * p,char * args)4933 static void ParseRuleState(SnortConfig *sc, SnortPolicy *p, char *args)
4934 {
4935     char **toks;
4936     int num_toks;
4937     RuleState *state;
4938     char *endptr;
4939 
4940     if (sc == NULL)
4941         return;
4942 
4943     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleState\n"););
4944 
4945     toks = mSplit(args, ", ", 0, &num_toks, 0);
4946 
4947     if (num_toks != 4)
4948         ParseError("Config rule_state: Empty state info.");
4949 
4950     state = (RuleState *)SnortAlloc(sizeof(RuleState));
4951 
4952     state->sid = SnortStrtoul(toks[0], &endptr, 0);
4953     if ((errno == ERANGE) || (*endptr != '\0'))
4954     {
4955         ParseError("Invalid sid for rule state: %s.  Sid must be between 0 and "
4956                    "%u inclusive.", args, UINT32_MAX);
4957     }
4958 
4959     state->gid = SnortStrtoul(toks[1], &endptr, 0);
4960     if ((errno == ERANGE) || (*endptr != '\0'))
4961     {
4962         ParseError("Invalid gid for rule state: %s.  Gid must be between 0 and "
4963                    "%u inclusive.", args, UINT32_MAX);
4964     }
4965 
4966     if (strcasecmp(toks[2], RULE_STATE_OPT__DISABLED) == 0)
4967     {
4968         state->state = RULE_STATE_DISABLED;
4969     }
4970     else if (strcasecmp(toks[2], RULE_STATE_OPT__ENABLED) == 0)
4971     {
4972         state->state = RULE_STATE_ENABLED;
4973     }
4974     else
4975     {
4976         ParseError("Rule_state: Invalid state - must be either "
4977                    "'enabled' or 'disabled'.");
4978     }
4979 
4980     state->action = GetRuleType(toks[3]);
4981     if (state->action == RULE_TYPE__NONE)
4982     {
4983         ParseError("Rule_state: Invalid action - must be a valid "
4984                    "rule type.");
4985     }
4986 
4987     mSplitFree(&toks, num_toks);
4988 
4989     if (sc->rule_state_list == NULL)
4990     {
4991         sc->rule_state_list = state;
4992     }
4993     else
4994     {
4995         state->next = sc->rule_state_list;
4996         sc->rule_state_list = state;
4997     }
4998 }
4999 
ParseDynamicLibInfo(DynamicLibInfo * dylib_info,char * args)5000 static void ParseDynamicLibInfo(DynamicLibInfo *dylib_info, char *args)
5001 {
5002     char getcwd_path[PATH_MAX];
5003     char **toks = NULL;
5004     int num_toks = 0;
5005     char *path = NULL;
5006     PathType ptype = PATH_TYPE__FILE;
5007     DynamicLibPath *dylib_path;
5008     struct stat buf;
5009 
5010     if (dylib_info == NULL)
5011         return;
5012 
5013     if (dylib_info->count >= MAX_DYNAMIC_LIBS)
5014     {
5015         ParseError("Maximum number of loaded libriaries of this dynamic "
5016                    "library type exceeded: %d.", MAX_DYNAMIC_LIBS);
5017     }
5018 
5019     if (args == NULL)
5020     {
5021         if (getcwd(getcwd_path, sizeof(getcwd_path)) == NULL)
5022         {
5023             ParseError("Dynamic library path too long.  If you really "
5024                        "think your path needs to be as long as it is, please "
5025                        "submit a bug to bugs@snort.org.");
5026         }
5027 
5028         path = getcwd_path;
5029         ptype = PATH_TYPE__DIRECTORY;
5030     }
5031     else
5032     {
5033         toks = mSplit(args, " \t", 0, &num_toks, 0);
5034 
5035         if (num_toks == 1)
5036         {
5037             path = toks[0];
5038             ptype = PATH_TYPE__FILE;
5039         }
5040         else if (num_toks == 2)
5041         {
5042             if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
5043             {
5044                 ptype = PATH_TYPE__FILE;
5045             }
5046             else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
5047             {
5048                 ptype = PATH_TYPE__DIRECTORY;
5049             }
5050             else
5051             {
5052                 ParseError("Invalid specifier for Dynamic library specifier.  "
5053                            "Should be file|directory pathname.");
5054             }
5055 
5056             path = toks[1];
5057         }
5058         else
5059         {
5060             ParseError("Missing/incorrect dynamic engine lib specifier.");
5061         }
5062     }
5063 
5064     dylib_path = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath));
5065     dylib_path->ptype = ptype;
5066     dylib_path->path = SnortStrdup(path);
5067 
5068     dylib_info->lib_paths[dylib_info->count] = dylib_path;
5069     dylib_info->count++;
5070 
5071     if (toks != NULL)
5072         mSplitFree(&toks, num_toks);
5073 
5074     if (stat(dylib_path->path, &buf) == -1)
5075     {
5076         ParseError("Could not stat dynamic module path \"%s\": %s.\n",
5077                    dylib_path->path, strerror(errno));
5078     }
5079 
5080     dylib_path->last_mod_time = buf.st_mtime;
5081 }
5082 
5083 /****************************************************************************
5084  *
5085  * Purpose: Parses a dynamic engine line
5086  *          Format is full path of dynamic engine
5087  *
5088  * Arguments: args => string containing a single dynamic engine
5089  *
5090  * Returns: void function
5091  *
5092  *****************************************************************************/
ParseDynamicEngineInfo(SnortConfig * sc,SnortPolicy * p,char * args)5093 static void ParseDynamicEngineInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5094 {
5095     if (sc == NULL)
5096         return;
5097 
5098     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicEngine\n"););
5099 
5100     if (sc->dyn_engines == NULL)
5101     {
5102         sc->dyn_engines = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5103         sc->dyn_engines->type = DYNAMIC_TYPE__ENGINE;
5104     }
5105 
5106     ParseDynamicLibInfo(sc->dyn_engines, args);
5107 }
5108 
5109 /****************************************************************************
5110  *
5111  * Purpose: Parses a dynamic detection lib line
5112  *          Format is full path of dynamic engine
5113  *
5114  * Arguments: args => string containing a single dynamic engine
5115  *
5116  * Returns: void function
5117  *
5118  *****************************************************************************/
ParseDynamicDetectionInfo(SnortConfig * sc,SnortPolicy * p,char * args)5119 static void ParseDynamicDetectionInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5120 {
5121     if (sc == NULL)
5122         return;
5123 
5124     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicDetection\n"););
5125 
5126     if (sc->dyn_rules == NULL)
5127     {
5128         sc->dyn_rules = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5129         sc->dyn_rules->type = DYNAMIC_TYPE__DETECTION;
5130     }
5131 
5132     ParseDynamicLibInfo(sc->dyn_rules, args);
5133 }
5134 
5135 /****************************************************************************
5136  *
5137  * Purpose: Parses a dynamic preprocessor lib line
5138  *          Format is full path of dynamic engine
5139  *
5140  * Arguments: args => string containing a single dynamic engine
5141  *
5142  * Returns: void function
5143  *
5144  *****************************************************************************/
ParseDynamicPreprocessorInfo(SnortConfig * sc,SnortPolicy * p,char * args)5145 static void ParseDynamicPreprocessorInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5146 {
5147     if (sc == NULL)
5148         return;
5149 
5150     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicPreprocessor\n"););
5151 
5152     if (sc->dyn_preprocs == NULL)
5153     {
5154         sc->dyn_preprocs = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5155         sc->dyn_preprocs->type = DYNAMIC_TYPE__PREPROCESSOR;
5156     }
5157 
5158     ParseDynamicLibInfo(sc->dyn_preprocs, args);
5159 }
5160 
5161 # ifdef SIDE_CHANNEL
5162 
5163 /****************************************************************************
5164  *
5165  * Purpose: Parses a dynamic side channel lib line
5166  *          Format is full path of dynamic side channel
5167  *
5168  * Arguments: args => string containing a single dynamic side channel
5169  *
5170  * Returns: void function
5171  *
5172  *****************************************************************************/
ParseDynamicSideChannelInfo(SnortConfig * sc,SnortPolicy * p,char * args)5173 static void ParseDynamicSideChannelInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5174 {
5175     if (sc == NULL)
5176         return;
5177 
5178     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicSideChannel\n"););
5179 
5180     if (sc->dyn_side_channels == NULL)
5181     {
5182         sc->dyn_side_channels = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
5183         sc->dyn_side_channels->type = DYNAMIC_TYPE__SIDE_CHANNEL;
5184     }
5185 
5186     ParseDynamicLibInfo(sc->dyn_side_channels, args);
5187 }
5188 
5189 # endif /* SIDE_CHANNEL */
5190 
5191 /****************************************************************************
5192  *
5193  * Purpose: Parses a dynamic output lib line
5194  *          Format is full path of dynamic output
5195  *
5196  * Arguments: args => string containing a single dynamic output
5197  *
5198  * Returns: void function
5199  *
5200  *****************************************************************************/
ParseDynamicOutputInfo(SnortConfig * sc,SnortPolicy * p,char * args)5201 static void ParseDynamicOutputInfo(SnortConfig *sc, SnortPolicy *p, char *args)
5202 {
5203     char **toks = NULL;
5204     int num_toks = 0;
5205     char *path = NULL;
5206     PathType ptype = PATH_TYPE__FILE;
5207     if (sc == NULL)
5208         return;
5209 
5210     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicOutput\n"););
5211 
5212     if (args == NULL)
5213     {
5214         char *getcwd_path = SnortAlloc(PATH_MAX);
5215 
5216         if (getcwd(getcwd_path, PATH_MAX) == NULL)
5217         {
5218             ParseError("Dynamic library path too long.  If you really "
5219                     "think your path needs to be as long as it is, please "
5220                     "submit a bug to bugs@snort.org.");
5221         }
5222 
5223         path = getcwd_path;
5224         ptype = PATH_TYPE__DIRECTORY;
5225     }
5226     else
5227     {
5228         toks = mSplit(args, " \t", 0, &num_toks, 0);
5229 
5230         if (num_toks == 1)
5231         {
5232             path = SnortStrdup(toks[0]);
5233             ptype = PATH_TYPE__FILE;
5234         }
5235         else if (num_toks == 2)
5236         {
5237             if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
5238             {
5239                 ptype = PATH_TYPE__FILE;
5240             }
5241             else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
5242             {
5243                 ptype = PATH_TYPE__DIRECTORY;
5244             }
5245             else
5246             {
5247                 ParseError("Invalid specifier for Dynamic library specifier.  "
5248                         "Should be file|directory pathname.");
5249             }
5250 
5251             path = SnortStrdup(toks[1]);
5252         }
5253         else
5254         {
5255             ParseError("Missing/incorrect dynamic engine lib specifier.");
5256         }
5257         mSplitFree(&toks, num_toks);
5258     }
5259     if (ptype == PATH_TYPE__DIRECTORY)
5260         output_load(path);
5261     else if (ptype == PATH_TYPE__FILE)
5262         output_load_module(path);
5263     if (path)
5264         free(path);
5265 
5266 }
5267 
5268 /* verify that we are not reusing some other keyword */
ValidateUserDefinedRuleType(SnortConfig * sc,char * keyword)5269 static int ValidateUserDefinedRuleType(SnortConfig *sc, char *keyword)
5270 {
5271     RuleListNode *node;
5272 
5273     if ((sc == NULL) || (sc->rule_lists == NULL))
5274         return 0;
5275 
5276     node = sc->rule_lists;
5277 
5278     /* This keyword cannot match any of our predefined rule types */
5279     if (GetRuleType(keyword) != RULE_TYPE__NONE)
5280         return 0;
5281 
5282     /* Walk through the rule list to make sure the user didn't already
5283      * define this one */
5284     while (node != NULL)
5285     {
5286         if (strcasecmp(node->name, keyword) == 0)
5287             return 0;
5288 
5289         node = node->next;
5290     }
5291 
5292     return 1;
5293 }
5294 
5295 /* This function does nothing.  It is just a place holder in the snort conf
5296  * keyword array so the keyword can be matched.  Its's a special configuration
5297  * case in that multiple non-escaped lines need to be read and the current
5298  * file pointer needs to be passed in. */
ParseRuleTypeDeclaration(SnortConfig * sc,SnortPolicy * p,char * arg)5299 static void ParseRuleTypeDeclaration(SnortConfig *sc, SnortPolicy *p, char *arg)
5300 {
5301     return;
5302 }
5303 
_ParseRuleTypeDeclaration(SnortConfig * sc,FILE * fp,char * arg,int prules)5304 static void _ParseRuleTypeDeclaration(SnortConfig *sc, FILE *fp, char *arg, int prules)
5305 {
5306     char **toks;
5307     int num_toks;
5308     char *input;
5309     char *rule_type_name;
5310     RuleType type;
5311     int rval = 1;
5312     ListHead *listhead = NULL;
5313     int got_output = 0;
5314 
5315     if ((sc == NULL) || (fp == NULL) || (arg == NULL))
5316         return;
5317 
5318     /* Already parsed this or ignoring for any non-default policy, but need to move past
5319      * the rule declaration because it doesn't have continuation characters
5320      */
5321     if (prules  /* parsing rules */
5322             || (getParserPolicy(sc) != getDefaultPolicy()))
5323     {
5324         while (1)
5325         {
5326             input = ReadLine(fp);
5327             if (input == NULL)
5328                 ParseError("Rule type declaration syntax error: %s.", arg);
5329 
5330             toks = mSplit(input, " \t", 2, &num_toks, 0);
5331 
5332             /* Just continue for blank line */
5333             if (toks == NULL)
5334             {
5335                 free (input);
5336                 continue;
5337             }
5338 
5339             /* Got end of rule type */
5340             if ((num_toks == 1) && (strcmp(toks[0], "}") == 0))
5341             {
5342                 free(input);
5343                 mSplitFree(&toks, num_toks);
5344                 break;
5345             }
5346 
5347             free(input);
5348             mSplitFree(&toks, num_toks);
5349         }
5350 
5351         return;
5352     }
5353 
5354 
5355     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type declaration\n"););
5356 
5357     toks = mSplit(arg, " \t", 2, &num_toks, 0);
5358 
5359     /* Need rule type name for creating new node in rule list */
5360     rule_type_name = SnortStrdup(ExpandVars(sc, toks[0]));
5361 
5362     /* Verify keyword is unique */
5363     if (!ValidateUserDefinedRuleType(sc, rule_type_name))
5364     {
5365         ParseError("Duplicate rule type declaration found: %s.", rule_type_name);
5366     }
5367 
5368     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Declaring new rule type: %s\n",
5369                             rule_type_name););
5370 
5371     if (num_toks == 2)
5372     {
5373         /* User put '{' on the same line, which is okay */
5374         if ((toks[1] != NULL) && (strcmp(toks[1], "{") != 0))
5375         {
5376             ParseError("Rule type declaration syntax error: %s.", arg);
5377         }
5378     }
5379     else
5380     {
5381         /* Get next line.  It should only be '{' */
5382         input = ReadLine(fp);
5383         if ((input == NULL) || (strcmp(input, "{") != 0))
5384         {
5385             ParseError("Rule type declaration syntax error: %s.", arg);
5386         }
5387 
5388         free(input);
5389     }
5390 
5391     mSplitFree(&toks, num_toks);
5392 
5393     input = ReadLine(fp);
5394     if (input == NULL)
5395         ParseError("Rule type declaration syntax error: %s.", arg);
5396 
5397     toks = mSplit(input, " \t", 2, &num_toks, 0);
5398     if ((num_toks != 2) ||
5399         (strcasecmp(toks[0], RULE_TYPE_OPT__TYPE) != 0))
5400     {
5401         ParseError("Rule type declaration syntax error: %s.", arg);
5402     }
5403 
5404     type = GetRuleType(toks[1]);
5405     if (type == RULE_TYPE__NONE)
5406         ParseError("Invalid type for rule type declaration: %s.", toks[1]);
5407 
5408     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"\ttype(%i): %s\n", type, toks[1]););
5409 
5410     if (type == RULE_TYPE__PASS)
5411         rval = 0;
5412 
5413     listhead = CreateRuleType(sc, rule_type_name, type, rval, NULL);
5414 
5415     free(rule_type_name);
5416     free(input);
5417     mSplitFree(&toks, num_toks);
5418 
5419     /* Get output plugin declarations
5420      * This will break if '}' is found on the line and fatal error if not and
5421      * the line isn't an output configuration */
5422     while (1)
5423     {
5424         input = ReadLine(fp);
5425         if (input == NULL)
5426             ParseError("Rule type declaration syntax error: %s.", arg);
5427 
5428         toks = mSplit(input, " \t", 2, &num_toks, 0);
5429 
5430         /* Just continue for blank line */
5431         if (toks == NULL)
5432         {
5433             free(input);
5434             continue;
5435         }
5436 
5437         /* Got end of rule type */
5438         if ((num_toks == 1) && (strcmp(toks[0], "}") == 0))
5439         {
5440             free(input);
5441             mSplitFree(&toks, num_toks);
5442             break;
5443         }
5444 
5445         if ((num_toks != 2) ||
5446             (strcasecmp(toks[0], SNORT_CONF_KEYWORD__OUTPUT) != 0))
5447         {
5448             ParseError("Rule type declaration syntax error: %s.  This line "
5449                        "should contain an output declaration.", toks[0]);
5450         }
5451 
5452         ParseRuleTypeOutput(sc, toks[1], listhead);
5453 
5454         free(input);
5455         mSplitFree(&toks, num_toks);
5456 
5457         got_output = 1;
5458     }
5459 
5460     if (!got_output)
5461         ParseError("Rule type declaration requires an output configuration.");
5462 
5463     sc->num_rule_types++;
5464 }
5465 
5466 /* adapted from ParseRuleFile in rules.c
5467  * Returns NULL if the end of file is reached or some other strange file
5468  * reading error should occur
5469  * Will read lines until it finds one that isn't empty or commented
5470  * Returned string, if not NULL, needs to be freed */
ReadLine(FILE * file)5471 char * ReadLine(FILE * file)
5472 {
5473     char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1);
5474 
5475     /* Read a line from file and return it. Return NULL for lines that
5476      * are comment characters or empty */
5477     while ((fgets(buf, MAX_LINE_LENGTH, file)) != NULL)
5478     {
5479         int i;
5480         char *index;
5481         char *ret_line;
5482 
5483         file_line++;
5484         index = buf;
5485 
5486         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n",
5487                                 file_name, file_line, buf););
5488 
5489         /* advance through any whitespace at the beginning of the line */
5490         while (isspace((int)*index))
5491             index++;
5492 
5493         /* If it's an empty line or starts with a comment character */
5494         if ((strlen(index) == 0) || (*index == '#') || (*index == ';'))
5495             continue;
5496 
5497         /* Trim off any whitespace at the end of the line */
5498         for (i = strlen(index); i > 0; i--)
5499         {
5500             if (!isspace((int)index[i - 1]))
5501                 break;
5502         }
5503 
5504         index[i] = '\0';
5505 
5506         /* return a copy of the line */
5507         ret_line = SnortStrdup(index);
5508         free(buf);
5509         return ret_line;
5510     }
5511 
5512     free(buf);
5513     return NULL;
5514 }
5515 
5516 /*
5517  * Same as VarGet - but this does not Fatal out if a var is not found
5518  */
VarSearch(SnortConfig * sc,char * name)5519 static char * VarSearch(SnortConfig *sc, char *name)
5520 {
5521     VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
5522     PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
5523     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
5524     sfip_var_t *ipvar;
5525 
5526     if ((ipvar = sfvt_lookup_var(ip_vartable, name)) != NULL)
5527         return ExpandVars(sc, ipvar->value);
5528 
5529     /* XXX Return a string value */
5530     if (PortVarTableFind(portVarTable, name))
5531         return name;
5532 
5533     if (var_table != NULL)
5534     {
5535         VarEntry *p = var_table;
5536         do
5537         {
5538             if(strcasecmp(p->name, name) == 0)
5539                 return p->value;
5540             p = p->next;
5541 
5542         } while(p != var_table);
5543     }
5544 
5545     return NULL;
5546 }
5547 
5548 /*****************************************************************
5549  * Function: GetPcaps()
5550  *
5551  * This function takes a list of pcap types and arguments from
5552  * the command line, parses them depending on type and puts them
5553  * in a user supplied queue. The pcap object list will contain
5554  * PcapReadObject structures.  The returned queue contains
5555  * strings representing paths to pcaps.
5556  *
5557  * returns -1 on error and 0 on success
5558  *
5559  ****************************************************************/
GetPcaps(SF_LIST * pol,SF_QUEUE * pcap_queue)5560 int GetPcaps(SF_LIST *pol, SF_QUEUE *pcap_queue)
5561 {
5562     PcapReadObject *pro = NULL;
5563     int type = 0;
5564     char *arg = NULL;
5565     char *filter = NULL;
5566     int ret = 0;
5567 
5568     if ((pol == NULL) || (pcap_queue == NULL))
5569         return -1;
5570 
5571     for (pro = (PcapReadObject *)sflist_first(pol);
5572          pro != NULL;
5573          pro = (PcapReadObject *)sflist_next(pol))
5574     {
5575         type = pro->type;
5576         arg = pro->arg;
5577         filter = pro->filter;
5578 
5579         switch (type)
5580         {
5581             case PCAP_SINGLE:
5582                 {
5583                     char *pcap = NULL;
5584                     struct stat stat_buf;
5585 
5586                     /* Don't check file if reading from stdin */
5587                     if (strcmp(arg, "-") != 0)
5588                     {
5589                         /* do a quick check to make sure file exists */
5590                         if (stat(arg, &stat_buf) == -1)
5591                         {
5592                             ErrorMessage("Error getting stat on pcap file: %s: %s\n",
5593                                          arg, strerror(errno));
5594                             return -1;
5595                         }
5596                         else if (!(stat_buf.st_mode & (S_IFREG|S_IFIFO)))
5597                         {
5598                             ErrorMessage("Specified pcap is not a regular file: %s\n", arg);
5599                             return -1;
5600                         }
5601                     }
5602 
5603                     pcap = SnortStrdup(arg);
5604                     ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5605                     if (ret == -1)
5606                     {
5607                         ErrorMessage("Could not add pcap to pcap list\n");
5608                         free(pcap);
5609                         return -1;
5610                     }
5611                 }
5612 
5613                 break;
5614 
5615             case PCAP_FILE_LIST:
5616                 /* arg should be a file with a list of pcaps in it */
5617                 {
5618                     FILE *pcap_file = NULL;
5619                     char *pcap = NULL;
5620                     char path_buf[4096];   /* max chars we'll accept for a path */
5621 
5622                     pcap_file = fopen(arg, "r");
5623                     if (pcap_file == NULL)
5624                     {
5625                         ErrorMessage("Could not open pcap list file: %s: %s\n",
5626                                      arg, strerror(errno));
5627                         return -1;
5628                     }
5629 
5630                     while (fgets(path_buf, sizeof(path_buf), pcap_file) != NULL)
5631                     {
5632                         char *path_buf_ptr, *path_buf_end;
5633                         struct stat stat_buf;
5634 
5635                         path_buf[sizeof(path_buf) - 1] = '\0';
5636                         path_buf_ptr = &path_buf[0];
5637                         path_buf_end = path_buf_ptr + strlen(path_buf_ptr);
5638 
5639                         /* move past spaces if any */
5640                         while (isspace((int)*path_buf_ptr))
5641                             path_buf_ptr++;
5642 
5643                         /* if nothing but spaces on line, continue */
5644                         if (*path_buf_ptr == '\0')
5645                             continue;
5646 
5647                         /* get rid of trailing spaces */
5648                         while ((path_buf_end > path_buf_ptr) &&
5649                                (isspace((int)*(path_buf_end - 1))))
5650                             path_buf_end--;
5651 
5652                         *path_buf_end = '\0';
5653 
5654                         /* do a quick check to make sure file exists */
5655                         if (stat(path_buf_ptr, &stat_buf) == -1)
5656                         {
5657                             ErrorMessage("Error getting stat on pcap file: %s: %s\n",
5658                                          path_buf_ptr, strerror(errno));
5659                             fclose(pcap_file);
5660                             return -1;
5661                         }
5662 #ifndef WIN32
5663                         else if (stat_buf.st_mode & S_IFDIR)
5664                         {
5665                             ret = GetFilesUnderDir(path_buf_ptr, pcap_queue, filter);
5666                             if (ret == -1)
5667                             {
5668                                 ErrorMessage("Error getting pcaps under dir: %s\n", path_buf_ptr);
5669                                 fclose(pcap_file);
5670                                 return -1;
5671                             }
5672                         }
5673 #endif
5674                         else if (stat_buf.st_mode & S_IFREG)
5675                         {
5676 #ifndef WIN32
5677                             if ((filter == NULL) || (fnmatch(filter, path_buf_ptr, 0) == 0))
5678                             {
5679 #endif
5680                                 pcap = SnortStrdup(path_buf_ptr);
5681                                 ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5682                                 if (ret == -1)
5683                                 {
5684                                     ErrorMessage("Could not insert pcap into list: %s\n", pcap);
5685                                     free(pcap);
5686                                     fclose(pcap_file);
5687                                     return -1;
5688                                 }
5689 #ifndef WIN32
5690                             }
5691 #endif
5692                         }
5693                         else
5694                         {
5695 #ifdef WIN32
5696                             ErrorMessage("Specified entry in \'%s\' is not a regular file: %s\n",
5697                                          arg, path_buf_ptr);
5698 #else
5699                             ErrorMessage("Specified entry in \'%s\' is not a regular file or directory: %s\n",
5700                                          arg, path_buf_ptr);
5701 #endif
5702                             fclose(pcap_file);
5703                             return -1;
5704                         }
5705                     }
5706 
5707                     fclose(pcap_file);
5708                 }
5709 
5710                 break;
5711 
5712             case PCAP_LIST:
5713                 /* arg should be a space separated list of pcaps */
5714                 {
5715                     char *tmp = NULL;
5716                     char *pcap = NULL;
5717                     struct stat stat_buf;
5718 
5719                     tmp = strtok_r(arg, " ", &arg);
5720                     if (tmp == NULL)
5721                     {
5722                         ErrorMessage("No pcaps specified in pcap list\n");
5723                         return -1;
5724                     }
5725 
5726                     do
5727                     {
5728                         /* do a quick check to make sure file exists */
5729                         if (stat(tmp, &stat_buf) == -1)
5730                         {
5731                             ErrorMessage("Error getting stat on file: %s: %s\n",
5732                                        tmp, strerror(errno));
5733                             return -1;
5734                         }
5735                         else if (!(stat_buf.st_mode & (S_IFREG|S_IFIFO)))
5736                         {
5737                             ErrorMessage("Specified pcap is not a regular file: %s\n", tmp);
5738                             return -1;
5739                         }
5740 
5741                         pcap = SnortStrdup(tmp);
5742                         ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap);
5743                         if (ret == -1)
5744                         {
5745                             ErrorMessage("Could not insert pcap into list: %s\n", pcap);
5746                             free(pcap);
5747                             return -1;
5748                         }
5749 
5750                     } while ((tmp = strtok_r(NULL, " ", &arg)) != NULL);
5751                 }
5752 
5753                 break;
5754 
5755 #ifndef WIN32
5756             case PCAP_DIR:
5757                 /* arg should be a directory name */
5758                 ret = GetFilesUnderDir(arg, pcap_queue, filter);
5759                 if (ret == -1)
5760                 {
5761                     ErrorMessage("Error getting pcaps under dir: %s\n", arg);
5762                     return -1;
5763                 }
5764 
5765                 break;
5766 #endif
5767 
5768             default:
5769                 ParseError("Bad read multiple pcaps type\n");
5770                 break;
5771         }
5772     }
5773 
5774     return 0;
5775 }
5776 
ValidateIPList(IpAddrSet * addrset,char * token)5777 int ValidateIPList(IpAddrSet *addrset, char *token)
5778 {
5779     if(!addrset || !(addrset->head||addrset->neg_head))
5780     {
5781         ParseError("Empty IP used either as source IP or as "
5782             "destination IP in a rule. IP list: %s.", token);
5783     }
5784 
5785     return 0;
5786 }
5787 
ParserCleanup(void)5788 void ParserCleanup(void)
5789 {
5790     port_list_free(&port_list);
5791 
5792     if (ruleIndexMap != NULL)
5793     {
5794         RuleIndexMapFree(&ruleIndexMap);
5795         ruleIndexMap = NULL;
5796     }
5797 }
5798 
InitVarTables(SnortPolicy * p)5799 static void InitVarTables(SnortPolicy *p)
5800 {
5801     if (p == NULL)
5802         return;
5803 
5804     if (p->var_table != NULL)
5805         DeleteVars(p->var_table);
5806     p->var_id = 1;
5807 
5808     if (p->ip_vartable != NULL)
5809         sfvt_free_table(p->ip_vartable);
5810     p->ip_vartable = sfvt_alloc_table();
5811 
5812     if (p->portVarTable != NULL)
5813         PortVarTableFree(p->portVarTable);
5814     p->portVarTable = PortVarTableCreate();
5815 
5816     if (p->nonamePortVarTable != NULL)
5817         PortTableFree(p->nonamePortVarTable);
5818     p->nonamePortVarTable = PortTableNew();
5819 
5820     if ((p->portVarTable == NULL) || (p->nonamePortVarTable == NULL))
5821     {
5822         ParseError("Failed to create port variable tables.\n");
5823     }
5824 }
5825 
InitPolicyMode(SnortPolicy * p)5826 static void InitPolicyMode(SnortPolicy *p)
5827 {
5828     if (!ScAdapterInlineMode() && !ScAdapterInlineTestMode())
5829     {
5830         p->ips_policy_mode = POLICY_MODE__PASSIVE;
5831         p->nap_policy_mode = POLICY_MODE__PASSIVE;
5832     }
5833     else if (ScAdapterInlineTestMode())
5834     {
5835         p->ips_policy_mode =  POLICY_MODE__INLINE_TEST;
5836         p->nap_policy_mode =  POLICY_MODE__INLINE_TEST;
5837      }
5838     else
5839     {
5840         p->ips_policy_mode = POLICY_MODE__INLINE;
5841         p->nap_policy_mode = POLICY_MODE__INLINE;
5842      }
5843 }
5844 
InitParser(void)5845 static void InitParser(void)
5846 {
5847     rule_count = 0;
5848     detect_rule_count = 0;
5849     decode_rule_count = 0;
5850     preproc_rule_count = 0;
5851     head_count = 0;
5852     otn_count = 0;
5853 
5854     memset(&tcpCnt, 0, sizeof(tcpCnt));
5855     memset(&udpCnt, 0, sizeof(udpCnt));
5856     memset(&ipCnt, 0, sizeof(ipCnt));
5857     memset(&icmpCnt, 0, sizeof(icmpCnt));
5858 
5859     port_list_free(&port_list);
5860     memset(&port_list, 0, sizeof(port_list));
5861     port_list.pl_max = MAX_RULE_COUNT;
5862 
5863     if (ruleIndexMap != NULL)
5864         RuleIndexMapFree(&ruleIndexMap);
5865     ruleIndexMap = RuleIndexMapCreate(MAX_RULE_COUNT);
5866     if (ruleIndexMap == NULL)
5867     {
5868         ParseError("Failed to create rule index map.\n");
5869     }
5870 
5871     /* This is for determining if a config option has already been
5872      * configured.  Most can only be configured once */
5873     memset(config_opt_configured, 0, sizeof(config_opt_configured));
5874 }
5875 
ParseRules(SnortConfig * sc)5876 void ParseRules(SnortConfig *sc)
5877 {
5878     tSfPolicyId policy_id;
5879 
5880     if ((sc == NULL) || (snort_conf_file == NULL))
5881         return;
5882 
5883     file_line = 0;
5884     file_name = snort_conf_file;
5885 
5886     LogMessage("\n");
5887     LogMessage("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
5888     LogMessage("Initializing rule chains...\n");
5889 
5890     /* Global set for parsing a configuration file to tell it whether
5891      * we're parsing rules or not - see ParseConfigFile */
5892     parse_rules = 1;
5893 
5894     /* Set to default policy */
5895     policy_id = sfGetDefaultPolicy(sc->policy_config);
5896     setParserPolicy(sc, policy_id);
5897 
5898     ParseConfigFile(sc, sc->targeted_policies[policy_id], snort_conf_file);
5899 
5900     /* Parse rules in targeted policies */
5901     for (policy_id = 0;
5902          policy_id < sfPolicyNumAllocated(sc->policy_config);
5903          policy_id++)
5904     {
5905         char *fname = sfPolicyGet(sc->policy_config, policy_id);
5906 
5907         if (policy_id == sfGetDefaultPolicy(sc->policy_config))
5908             continue;
5909 
5910         if (fname != NULL)
5911         {
5912             setParserPolicy(sc, policy_id);
5913             ParseInclude(sc, sc->targeted_policies[policy_id], fname);
5914         }
5915     }
5916 
5917     LogMessage("%d Snort rules read\n", rule_count);
5918     LogMessage("    %d detection rules\n", detect_rule_count);
5919     LogMessage("    %d decoder rules\n", decode_rule_count);
5920     LogMessage("    %d preprocessor rules\n", preproc_rule_count);
5921     LogMessage("%d Option Chains linked into %d Chain Headers\n", otn_count, head_count);
5922     LogMessage("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
5923     LogMessage("\n");
5924 
5925 
5926 #ifdef DEBUG_MSGS
5927     DumpRuleChains(sc->rule_lists);
5928 #endif
5929 
5930     IntegrityCheckRules(sc);
5931     /*FindMaxSegSize();*/
5932 
5933     /* Compile/Finish and Print the PortList Tables */
5934     PortTablesFinish(sc->port_tables, sc->fast_pattern_config);
5935 
5936     LogMessage("+-------------------[Rule Port Counts]---------------------------------------\n");
5937     LogMessage("|%8s%8s%8s%8s%8s\n", " ", "tcp", "udp", "icmp", "ip");
5938     LogMessage("|%8s%8u%8u%8u%8u\n", "src", tcpCnt.src, udpCnt.src, icmpCnt.src, ipCnt.src);
5939     LogMessage("|%8s%8u%8u%8u%8u\n", "dst", tcpCnt.dst, udpCnt.dst, icmpCnt.dst, ipCnt.dst);
5940     LogMessage("|%8s%8u%8u%8u%8u\n", "any", tcpCnt.aa, udpCnt.aa, icmpCnt.aa, ipCnt.aa);
5941     LogMessage("|%8s%8u%8u%8u%8u\n", "nc", tcpCnt.nc, udpCnt.nc, icmpCnt.nc, ipCnt.nc);
5942     LogMessage("|%8s%8u%8u%8u%8u\n", "s+d", tcpCnt.sd, udpCnt.sd, icmpCnt.sd, ipCnt.sd);
5943     LogMessage("+----------------------------------------------------------------------------\n");
5944 
5945     ///print_rule_index_map( ruleIndexMap );
5946     ///port_list_print( &port_list );
5947 
5948     /* Reset these.  The only issue in not reseting would be if we were
5949      * parsing a command line again, but do it anyway */
5950     file_name = NULL;
5951     file_line = 0;
5952 }
5953 
ParseInclude(SnortConfig * sc,SnortPolicy * p,char * arg)5954 static void ParseInclude(SnortConfig *sc, SnortPolicy *p, char *arg)
5955 {
5956     struct stat file_stat;  /* for include path testing */
5957     /* Save place in previous file */
5958     char *stored_file_name = file_name;
5959     int stored_file_line = file_line;
5960 
5961     /* Including top level snort conf file */
5962     if (strcmp(arg, snort_conf_file) == 0)
5963     {
5964         ParseError("Cannot include \"%s\" in an include directive.",
5965                    snort_conf_file);
5966     }
5967 
5968     /* XXX Maybe not allow an include in an included file to avoid
5969      * potential recursion issues */
5970 
5971     file_line = 0;
5972     file_name = SnortStrdup(arg);
5973 
5974     /* Stat the file.  If that fails, stat it relative to the directory
5975      * that the top level snort configuration file was in */
5976     if (stat(file_name, &file_stat) == -1)
5977     {
5978         int path_len = strlen(snort_conf_dir) + strlen(arg) + 1;
5979 
5980         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: stat "
5981                                 "on %s failed - going to config_dir\n", file_name););
5982 
5983         free(file_name);
5984 
5985         file_name = (char *)SnortAlloc(path_len);
5986         snprintf(file_name, path_len, "%s%s", snort_conf_dir, arg);
5987 
5988         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: Opening "
5989                                 "and parsing %s\n", file_name););
5990     }
5991 
5992     ParseConfigFile(sc, p, file_name);
5993 
5994     free(file_name);
5995 
5996     file_name = stored_file_name;
5997     file_line = stored_file_line;
5998 }
5999 
ParseConfigFile(SnortConfig * sc,SnortPolicy * p,char * fname)6000 static void ParseConfigFile(SnortConfig *sc, SnortPolicy *p, char *fname)
6001 {
6002     /* Used for line continuation */
6003     int continuation = 0;
6004     char *saved_line = NULL;
6005     char *new_line = NULL;
6006     char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1);
6007     FILE *fp = fopen(fname, "r");
6008 
6009     /* open the rules file */
6010     if (fp == NULL)
6011     {
6012         ParseError("Unable to open rules file \"%s\": %s.\n",
6013                    fname, strerror(errno));
6014     }
6015 
6016     /* loop thru each file line and send it to the rule parser */
6017     while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL)
6018     {
6019         /* buffer indexing pointer */
6020         char *index = buf;
6021 
6022         /* Increment the line counter so the error messages know which
6023          * line to bitch about */
6024         file_line++;
6025 
6026         /* fgets always appends a null, so doing a strlen should be safe */
6027         if ((strlen(buf) + 1) == MAX_LINE_LENGTH)
6028         {
6029             ParseError("Line greater than or equal to %u characters which is "
6030                        "more than the parser is willing to handle.  Try "
6031                        "splitting it up on multiple lines if possible.",
6032                        MAX_LINE_LENGTH);
6033         }
6034 
6035         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n",
6036                                 fname, file_line, buf););
6037 
6038         /* advance through any whitespace at the beginning of the line */
6039         while (isspace((int)*index))
6040             index++;
6041 
6042         /* If it's an empty line or starts with a comment character */
6043         if ((strlen(index) == 0) || (*index == '#') || (*index == ';'))
6044             continue;
6045 
6046         if (continuation)
6047         {
6048             int new_line_len = strlen(saved_line) + strlen(index) + 1;
6049 
6050             if (new_line_len >= PARSERULE_SIZE)
6051             {
6052                 ParseError("Rule greater than or equal to %u characters which "
6053                            "is more than the parser is willing to handle.  "
6054                            "Submit a bug to bugs@snort.org if you legitimately "
6055                            "feel like your rule or keyword configuration needs "
6056                            "more than this amount of space.", PARSERULE_SIZE);
6057             }
6058 
6059             new_line = (char *)SnortAlloc(new_line_len);
6060             snprintf(new_line, new_line_len, "%s%s", saved_line, index);
6061 
6062             free(saved_line);
6063             saved_line = NULL;
6064             index = new_line;
6065 
6066             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n",
6067                                     new_line););
6068         }
6069 
6070         /* check for a '\' continuation character at the end of the line
6071          * if it's there we need to get the next line in the file */
6072         if (ContinuationCheck(index) == 0)
6073         {
6074             char **toks;
6075             int num_toks;
6076             char *keyword;
6077             char *args;
6078             int i;
6079 
6080             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
6081                                     "[*] Processing keyword: %s\n", index););
6082 
6083             /* Get the keyword and args */
6084             toks = mSplit(index, " \t", 2, &num_toks, 0);
6085             if (num_toks != 2)
6086                 ParseError("Invalid configuration line: %s", index);
6087 
6088             keyword = SnortStrdup(ExpandVars(sc, toks[0]));
6089             args = toks[1];
6090 
6091             for (i = 0; snort_conf_keywords[i].name != NULL; i++)
6092             {
6093                 if (strcasecmp(keyword, snort_conf_keywords[i].name) == 0)
6094                 {
6095                     if ((getParserPolicy(sc) != getDefaultPolicy()) &&
6096                         snort_conf_keywords[i].default_policy_only)
6097                     {
6098                         /* Keyword only configurable in the default policy*/
6099                         DEBUG_WRAP(DebugMessage(DEBUG_INIT,
6100                             "Config option \"%s\" configurable only by default policy. Ignoring it", toks[0]));
6101                         break;
6102                     }
6103 
6104                     if (((snort_conf_keywords[i].type == KEYWORD_TYPE__RULE) &&
6105                          !parse_rules) ||
6106                         ((snort_conf_keywords[i].type == KEYWORD_TYPE__MAIN) &&
6107                          parse_rules))
6108                     {
6109                         break;
6110                     }
6111 
6112                     if (snort_conf_keywords[i].expand_vars)
6113                         args = SnortStrdup(ExpandVars(sc, toks[1]));
6114 
6115                     /* Special parsing case is ruletype.
6116                      * Need to send the file pointer so it can parse what's
6117                      * between '{' and '}' which can span multiple lines
6118                      * without a line continuation character */
6119                     if (strcasecmp(keyword, SNORT_CONF_KEYWORD__RULE_TYPE) == 0)
6120                         _ParseRuleTypeDeclaration(sc, fp, args, parse_rules);
6121                     else
6122                         snort_conf_keywords[i].parse_func(sc, p, args);
6123 
6124                     break;
6125                 }
6126             }
6127 
6128             /* Didn't find any pre-defined snort_conf_keywords.  Look for a user defined
6129              * rule type */
6130 
6131             if ((snort_conf_keywords[i].name == NULL) && parse_rules)
6132             {
6133                 RuleListNode *node;
6134 
6135                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Unknown rule type, "
6136                                         "might be declared\n"););
6137 
6138                 for (node = sc->rule_lists; node != NULL; node = node->next)
6139                 {
6140                     if (strcasecmp(node->name, keyword) == 0)
6141                         break;
6142                 }
6143 
6144                 if (node == NULL)
6145                     ParseError("Unknown rule type: %s.", toks[0]);
6146 
6147                 if ( node->mode == RULE_TYPE__DROP )
6148                 {
6149                     if ( ScTreatDropAsAlertNewConf(sc) )
6150                         ParseRule(sc, p, args, RULE_TYPE__ALERT, node->RuleList);
6151 
6152                     else if ( ScKeepDropRules(sc) ||  ScLoadAsDropRules(sc) )
6153                         ParseRule(sc, p, args, node->mode, node->RuleList);
6154                 }
6155                 else if ( node->mode == RULE_TYPE__SDROP )
6156                 {
6157                     if ( ScKeepDropRules(sc) && !ScTreatDropAsAlertNewConf(sc) )
6158                         ParseRule(sc, p, args, node->mode, node->RuleList);
6159 
6160                     else if ( ScLoadAsDropRules(sc) )
6161                         ParseRule(sc, p, args, RULE_TYPE__DROP, node->RuleList);
6162                 }
6163                 else
6164                 {
6165                     ParseRule(sc, p, args, node->mode, node->RuleList);
6166                 }
6167             }
6168 
6169             if (args != toks[1])
6170                 free(args);
6171 
6172             free(keyword);
6173             mSplitFree(&toks, num_toks);
6174 
6175             if(new_line != NULL)
6176             {
6177                 free(new_line);
6178                 new_line = NULL;
6179                 continuation = 0;
6180             }
6181         }
6182         else
6183         {
6184             /* save the current line */
6185             saved_line = SnortStrdup(index);
6186 
6187             /* current line was a continuation itself... */
6188             if (new_line != NULL)
6189             {
6190                 free(new_line);
6191                 new_line = NULL;
6192             }
6193 
6194             /* set the flag to let us know the next line is
6195              * a continuation line */
6196             continuation = 1;
6197         }
6198     }
6199 
6200     if (saved_line != NULL)
6201         free(saved_line);
6202 
6203     fclose(fp);
6204     free(buf);
6205 }
6206 
ContinuationCheck(char * rule)6207 static int ContinuationCheck(char *rule)
6208 {
6209     char *idx;  /* indexing var for moving around on the string */
6210 
6211     idx = rule + strlen(rule) - 1;
6212 
6213     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n",
6214                 *idx););
6215 
6216     while(isspace((int)*idx))
6217     {
6218         idx--;
6219     }
6220 
6221     if(*idx == '\\')
6222     {
6223         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, "
6224                     "clearing char and returning 1\n"););
6225 
6226         /* clear the '\' so there isn't a problem on the appended string */
6227         *idx = '\x0';
6228         return 1;
6229     }
6230 
6231     return 0;
6232 }
6233 
ConfigAlertBeforePass(SnortConfig * sc,char * args)6234 void ConfigAlertBeforePass(SnortConfig *sc, char *args)
6235 {
6236     if (sc == NULL)
6237         return;
6238 
6239     sc->run_flags |= RUN_FLAG__ALERT_BEFORE_PASS;
6240 }
6241 
ConfigAlertFile(SnortConfig * sc,char * args)6242 void ConfigAlertFile(SnortConfig *sc, char *args)
6243 {
6244     if ((args == NULL) || (sc == NULL) || (sc->alert_file != NULL))
6245         return;
6246 
6247     sc->alert_file = SnortStrdup(args);
6248 
6249     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"alertfile set to: %s\n",
6250                             sc->alert_file););
6251 }
6252 
ConfigAlertWithInterfaceName(SnortConfig * sc,char * args)6253 void ConfigAlertWithInterfaceName(SnortConfig *sc, char *args)
6254 {
6255     if (sc == NULL)
6256         return;
6257 
6258     sc->output_flags |= OUTPUT_FLAG__ALERT_IFACE;
6259 }
6260 
ConfigAsn1(SnortConfig * sc,char * args)6261 void ConfigAsn1(SnortConfig *sc, char *args)
6262 {
6263     long int num_nodes;
6264     char *endptr;
6265 
6266     if ((sc == NULL) || (args == NULL))
6267         return;
6268 
6269     num_nodes = SnortStrtol(args, &endptr, 0);
6270     if ((errno == ERANGE) || (*endptr != '\0') || (num_nodes <= 0))
6271     {
6272         ParseError("Invalid argument to 'asn1' configuration.  "
6273                    "Must be a positive integer.");
6274     }
6275 
6276     sc->asn1_mem = num_nodes;
6277 }
6278 
ConfigAutogenPreprocDecoderRules(SnortConfig * sc,char * args)6279 void ConfigAutogenPreprocDecoderRules(SnortConfig *sc, char *args)
6280 {
6281     SnortPolicy* policy;
6282 
6283     if (sc == NULL)
6284         return;
6285 
6286     /* config autogenerate_preprocessor_decoder_rules */
6287     UpdateDecodeRulesArray(0, ENABLE_RULE, ENABLE_ALL_RULES);
6288     policy = sc->targeted_policies[getParserPolicy(sc)];
6289     policy->policy_flags |= POLICY_FLAG__AUTO_OTN;
6290     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Autogenerating Preprocessor and Decoder OTNs\n"););
6291 }
6292 
ConfigBinding(SnortConfig * sc,char * args)6293 void ConfigBinding(SnortConfig *sc, char *args)
6294 {
6295     int num_toks;
6296     int num_toks1;
6297     char **toks;
6298     char **toks1;
6299     char *fileName;
6300     int bindingType;
6301     toks1 = mSplit(args, " \t", 3, &num_toks1, 0);
6302     if(num_toks1 < 3)
6303     {
6304         mSplitFree(&toks1, num_toks1);
6305         ParseError("Need at least two arguments to 'config binding'");
6306         return;
6307     }
6308 
6309     if (!strcmp("policy_id", toks1[1]))
6310     {
6311         bindingType = SF_BINDING_TYPE_POLICY_ID;
6312     }
6313 #ifndef POLICY_BY_ID_ONLY
6314     else if (!strcmp("vlan", toks1[1]))
6315     {
6316         bindingType = SF_BINDING_TYPE_VLAN;
6317     }
6318     else if (!strcmp("net", toks1[1]))
6319     {
6320         bindingType = SF_BINDING_TYPE_NETWORK;
6321     }
6322 #endif
6323     else
6324     {
6325         mSplitFree(&toks1, num_toks1);
6326         ParseError("Invalid binding type in 'config binding'");
6327         return;
6328     }
6329     fileName = toks1[0];
6330     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Policy File: %s\n", fileName););
6331 
6332 #define MAX_BOUND_ADDRS_PER_LINE 512
6333     toks = mSplit(toks1[2], ",", MAX_BOUND_ADDRS_PER_LINE + 1, &num_toks, 0);
6334 
6335     if (num_toks < 1)
6336     {
6337         mSplitFree(&toks1, num_toks1);
6338         mSplitFree(&toks, num_toks);
6339         ParseError(" Invalid arguments to 'config binding'");
6340         return;
6341     }
6342 
6343     if (num_toks >= 512)
6344     {
6345         mSplitFree(&toks1, num_toks1);
6346         mSplitFree(&toks, num_toks);
6347         ParseError(" Too many network addresses specified in 'config binding'. "
6348                    " Maximum is %d.\n", MAX_BOUND_ADDRS_PER_LINE);
6349         return;
6350     }
6351 
6352     if (bindingType == SF_BINDING_TYPE_POLICY_ID)
6353     {
6354         if (ParsePolicyIdBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6355         {
6356             FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6357         }
6358     }
6359     else if (bindingType == SF_BINDING_TYPE_VLAN)
6360     {
6361         if (ParseVlanBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6362         {
6363             FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6364         }
6365     }
6366     else
6367     {
6368         if (ParseNetworkBindingLine(sc->policy_config, num_toks, &toks[0], fileName))
6369         {
6370             FatalError("%s(%d) Formatting error in binding config for %s\n", file_name, file_line, fileName);
6371         }
6372     }
6373     mSplitFree(&toks1, num_toks1);
6374     mSplitFree(&toks, num_toks);
6375 }
6376 
ConfigBpfFile(SnortConfig * sc,char * args)6377 void ConfigBpfFile(SnortConfig *sc, char *args)
6378 {
6379     if ((args == NULL) || (sc == NULL) || (sc->bpf_file != NULL))
6380         return;
6381 
6382     sc->bpf_file = SnortStrdup(args);
6383 }
6384 
ConfigChecksumDrop(SnortConfig * sc,char * args)6385 void ConfigChecksumDrop(SnortConfig *sc, char *args)
6386 {
6387     if (sc == NULL)
6388         return;
6389 
6390     if (sc->targeted_policies == NULL)
6391     {
6392         //This is the case for command line argument
6393         sc->checksum_drop_flags = GetChecksumFlags(args);
6394         sc->checksum_drop_flags_modified = 1;
6395     }
6396     else
6397     {
6398         SnortPolicy *pPolicy = sc->targeted_policies[getParserPolicy(sc)];
6399 
6400         pPolicy->checksum_drop_flags = GetChecksumFlags(args);
6401         pPolicy->checksum_drop_flags_modified = 1;
6402     }
6403 }
6404 
ConfigChecksumMode(SnortConfig * sc,char * args)6405 void ConfigChecksumMode(SnortConfig *sc, char *args)
6406 {
6407     if (sc == NULL)
6408         return;
6409 
6410     if (sc->targeted_policies == NULL)
6411     {
6412         //This is the case for command line argument
6413         sc->checksum_flags = GetChecksumFlags(args);
6414         sc->checksum_flags_modified = 1;
6415     }
6416     else
6417     {
6418         SnortPolicy *pPolicy = sc->targeted_policies[getParserPolicy(sc)];
6419 
6420         pPolicy->checksum_flags = GetChecksumFlags(args);
6421         pPolicy->checksum_flags_modified = 1;
6422     }
6423 
6424 }
6425 
GetChecksumFlags(char * args)6426 static int GetChecksumFlags(char *args)
6427 {
6428     char **toks;
6429     int num_toks;
6430     int i;
6431     int negative_flags = 0;
6432     int positive_flags = 0;
6433     int got_positive_flag = 0;
6434     int got_negative_flag = 0;
6435     int ret_flags = 0;
6436 
6437     if (args == NULL)
6438         return CHECKSUM_FLAG__ALL;
6439 
6440     toks = mSplit(args, " \t", 10, &num_toks, 0);
6441     for (i = 0; i < num_toks; i++)
6442     {
6443         if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__ALL) == 0)
6444         {
6445             positive_flags = CHECKSUM_FLAG__ALL;
6446             negative_flags = 0;
6447             got_positive_flag = 1;
6448         }
6449         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NONE) == 0)
6450         {
6451             positive_flags = 0;
6452             negative_flags = CHECKSUM_FLAG__ALL;
6453             got_negative_flag = 1;
6454         }
6455         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__IP) == 0)
6456         {
6457             positive_flags |= CHECKSUM_FLAG__IP;
6458             negative_flags &= ~CHECKSUM_FLAG__IP;
6459             got_positive_flag = 1;
6460         }
6461         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_IP) == 0)
6462         {
6463             positive_flags &= ~CHECKSUM_FLAG__IP;
6464             negative_flags |= CHECKSUM_FLAG__IP;
6465             got_negative_flag = 1;
6466         }
6467         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__TCP) == 0)
6468         {
6469             positive_flags |= CHECKSUM_FLAG__TCP;
6470             negative_flags &= ~CHECKSUM_FLAG__TCP;
6471             got_positive_flag = 1;
6472         }
6473         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_TCP) == 0)
6474         {
6475             positive_flags &= ~CHECKSUM_FLAG__TCP;
6476             negative_flags |= CHECKSUM_FLAG__TCP;
6477             got_negative_flag = 1;
6478         }
6479         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__UDP) == 0)
6480         {
6481             positive_flags |= CHECKSUM_FLAG__UDP;
6482             negative_flags &= ~CHECKSUM_FLAG__UDP;
6483             got_positive_flag = 1;
6484         }
6485         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_UDP) == 0)
6486         {
6487             positive_flags &= ~CHECKSUM_FLAG__UDP;
6488             negative_flags |= CHECKSUM_FLAG__UDP;
6489             got_negative_flag = 1;
6490         }
6491         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__ICMP) == 0)
6492         {
6493             positive_flags |= CHECKSUM_FLAG__ICMP;
6494             negative_flags &= ~CHECKSUM_FLAG__ICMP;
6495             got_positive_flag = 1;
6496         }
6497         else if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__NO_ICMP) == 0)
6498         {
6499             positive_flags &= ~CHECKSUM_FLAG__ICMP;
6500             negative_flags |= CHECKSUM_FLAG__ICMP;
6501             got_negative_flag = 1;
6502         }
6503         else
6504         {
6505             ParseError("Unknown command line checksum option: %s.", toks[i]);
6506         }
6507     }
6508 
6509     /* Invert the negative flags with all checksums */
6510     negative_flags ^= CHECKSUM_FLAG__ALL;
6511     negative_flags &= CHECKSUM_FLAG__ALL;
6512 
6513     if (got_positive_flag && got_negative_flag)
6514     {
6515         /* If we got both positive and negative flags just take the
6516          * combination of the two */
6517         ret_flags = positive_flags & negative_flags;
6518     }
6519     else if (got_positive_flag)
6520     {
6521         /* If we got a positive flag assume the user wants checksums
6522          * to be cleared */
6523         ret_flags = positive_flags;
6524     }
6525     else  /* got a negative flag */
6526     {
6527         /* If we got a negative flag assume the user thinks all
6528          * checksums are on */
6529         ret_flags = negative_flags;
6530     }
6531 
6532     mSplitFree(&toks, num_toks);
6533     return ret_flags;
6534 }
6535 
ConfigChrootDir(SnortConfig * sc,char * args)6536 void ConfigChrootDir(SnortConfig *sc, char *args)
6537 {
6538 #ifdef WIN32
6539     ParseError("Setting the chroot directory is not supported in "
6540                "the WIN32 port of snort!");
6541 #else
6542     if ((args == NULL) || (sc == NULL) || (sc->chroot_dir != NULL))
6543         return;
6544 
6545     sc->chroot_dir = SnortStrdup(args);
6546 #endif
6547 }
6548 
ConfigClassification(SnortConfig * sc,char * args)6549 void ConfigClassification(SnortConfig *sc, char *args)
6550 {
6551     char **toks;
6552     int num_toks;
6553     char *endptr;
6554     ClassType *new_node, *current;
6555     int max_id = 0;
6556 
6557     if ((args == NULL) || (sc == NULL))
6558         return;
6559 
6560     toks = mSplit(args, ",", 0, &num_toks, '\\');
6561     if (num_toks != 3)
6562         ParseError("Invalid classification config: %s.", args);
6563 
6564     /* create the new node */
6565     new_node = (ClassType *)SnortAlloc(sizeof(ClassType));
6566 
6567     new_node->type = SnortStrdup(toks[0]);
6568     new_node->name = SnortStrdup(toks[1]);
6569 
6570     new_node->priority = SnortStrtol(toks[2], &endptr, 0);
6571     if ((errno == ERANGE) || (*endptr != '\0') || (new_node->priority <= 0))
6572     {
6573         ParseError("Invalid argument for classification priority "
6574                    "configuration: %s.  Must be a positive integer.", toks[2]);
6575     }
6576 
6577     current = sc->classifications;
6578     while (current != NULL)
6579     {
6580         /* dup check */
6581         if (strcasecmp(current->type, new_node->type) == 0)
6582         {
6583             if (getParserPolicy(sc) == getDefaultPolicy())
6584             {
6585                 ParseWarning("Duplicate classification \"%s\""
6586                         "found, ignoring this line\n", new_node->type);
6587             }
6588 
6589             break;
6590         }
6591 
6592         if (current->id > max_id)
6593             max_id = current->id;
6594 
6595         current = current->next;
6596     }
6597 
6598     /* Got a dup */
6599     if (current != NULL)
6600     {
6601         free(new_node->name);
6602         free(new_node->type);
6603         free(new_node);
6604         mSplitFree(&toks, num_toks);
6605         return;
6606     }
6607 
6608     /* insert node */
6609     new_node->id = max_id + 1;
6610     new_node->next = sc->classifications;
6611     sc->classifications = new_node;
6612 
6613     mSplitFree(&toks, num_toks);
6614 }
6615 
ConfigCreatePidFile(SnortConfig * sc,char * args)6616 void ConfigCreatePidFile(SnortConfig *sc, char *args)
6617 {
6618     if (sc == NULL)
6619         return;
6620 
6621     sc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
6622 }
6623 
ConfigDaemon(SnortConfig * sc,char * args)6624 void ConfigDaemon(SnortConfig *sc, char *args)
6625 {
6626 #ifdef WIN32
6627     ParseError("Setting the Daemon mode is not supported in the "
6628                "WIN32 port of snort!  Use 'snort /SERVICE ...' instead.");
6629 #else
6630     if (sc == NULL)
6631         return;
6632 
6633     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Daemon mode flag set\n"););
6634     sc->run_flags |= RUN_FLAG__DAEMON;
6635     sc->logging_flags |= LOGGING_FLAG__QUIET;
6636 #endif
6637 }
6638 
ConfigDecodeDataLink(SnortConfig * sc,char * args)6639 void ConfigDecodeDataLink(SnortConfig *sc, char *args)
6640 {
6641     if (sc == NULL)
6642         return;
6643 
6644     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Decode DLL set\n"););
6645     sc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK;
6646 }
6647 
ConfigDefaultRuleState(SnortConfig * sc,char * args)6648 void ConfigDefaultRuleState(SnortConfig *sc, char *args)
6649 {
6650     if (sc == NULL)
6651         return;
6652 
6653     LogMessage("Found rule_state config directive\n");
6654 
6655     if (args == NULL)
6656     {
6657         sc->default_rule_state = RULE_STATE_ENABLED;
6658     }
6659     else if (strcasecmp(args, RULE_STATE_OPT__DISABLED) == 0)
6660     {
6661         sc->default_rule_state = RULE_STATE_DISABLED;
6662     }
6663     else
6664     {
6665         /* Any other word and just call it enabled */
6666         sc->default_rule_state = RULE_STATE_ENABLED;
6667     }
6668 }
6669 
ConfigDetection(SnortConfig * sc,char * args)6670 void ConfigDetection(SnortConfig *sc, char *args)
6671 {
6672     int i;
6673     char **toks;
6674     int num_toks;
6675     FastPatternConfig *fp;
6676     int old_stream_inserts = -1;
6677     int old_max_queue_events = -1;
6678 
6679     if ((sc == NULL) || (args == NULL))
6680         return;
6681 
6682     fp = sc->fast_pattern_config;
6683 
6684     if (fp->configured)
6685     {
6686         ParseWarning("Reconfiguring detection options.");
6687 
6688         /* Save max queue events and stream inserts in case they are
6689          * not configured again - these will carry over into the new
6690          * configuration */
6691         old_max_queue_events = fp->max_queue_events;
6692         old_stream_inserts = fp->inspect_stream_insert;
6693 
6694         fpSetDefaults(fp);
6695     }
6696 
6697     toks = mSplit(args, ", ", 20, &num_toks, 0);
6698 
6699     for (i = 0; i < num_toks; i++)
6700     {
6701         if (strcasecmp(toks[i], DETECTION_OPT__SEARCH_OPTIMIZE) == 0)
6702         {
6703             fpSetDetectSearchOpt(fp, 1);
6704         }
6705         else if (strcasecmp(toks[i], DETECTION_OPT__ENABLE_SINGLE_RULE_GROUP) == 0)
6706         {
6707             fpDetectSetSingleRuleGroup(fp);
6708             LogMessage("Using Single-Rule-Group Detection\n");
6709         }
6710         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_NOCONTENT_RULE_TESTS) == 0)
6711         {
6712             fpDetectSetDebugPrintNcRules(fp);
6713         }
6714         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUP_BUILD_DETAILS) == 0)
6715         {
6716             fpDetectSetDebugPrintRuleGroupBuildDetails(fp);
6717         }
6718         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_UNCOMPILED) == 0)
6719         {
6720             fpDetectSetDebugPrintRuleGroupsUnCompiled(fp);
6721         }
6722         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_RULE_GROUPS_COMPILED) == 0)
6723         {
6724             fpDetectSetDebugPrintRuleGroupsCompiled(fp);
6725         }
6726         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG) == 0)
6727         {
6728             fpSetDebugMode(fp);
6729         }
6730         else if (strcasecmp(toks[i], DETECTION_OPT__NO_STREAM_INSERTS) == 0)
6731         {
6732             fpSetStreamInsert(fp);
6733             old_stream_inserts = -1;  /* Don't reset to old value */
6734         }
6735         else if (strcasecmp(toks[i], DETECTION_OPT__BLEEDOVER_WARNINGS_ENABLED) == 0)
6736         {
6737             fpDetectSetBleedOverWarnings(fp);
6738         }
6739         else if (strcasecmp(toks[i], DETECTION_OPT__SEARCH_METHOD) == 0)
6740         {
6741             i++;
6742             if (i < num_toks)
6743             {
6744                 if (fpSetDetectSearchMethod(fp, toks[i]) == -1)
6745                 {
6746                     ParseError("Invalid argument to 'search-method': %s.", toks[i]);
6747                 }
6748             }
6749             else
6750             {
6751                 ParseError("Need an argument to 'search-method'.");
6752             }
6753         }
6754         else if (strcasecmp(toks[i], DETECTION_OPT__BLEEDOVER_PORT_LIMIT) == 0)
6755         {
6756             i++;
6757             if (i < num_toks)
6758             {
6759                 char *endptr;
6760                 int n = SnortStrtol(toks[i], &endptr, 0);
6761 
6762                 if ((errno == ERANGE) || (*endptr != '\0') || (n <= 0))
6763                 {
6764                     ParseError("Invalid argument for bleedover limit: %s.  "
6765                                "Need a non-negative integer.", toks[i]);
6766                 }
6767 
6768                 fpDetectSetBleedOverPortLimit(fp, n);
6769                 LogMessage("Bleedover Port Limit : %d\n",n);
6770             }
6771             else
6772             {
6773                 ParseError("Missing port-count argument to 'bleedover_port_limit'.");
6774             }
6775         }
6776         else if (strcasecmp(toks[i], DETECTION_OPT__MAX_QUEUE_EVENTS) == 0)
6777         {
6778             i++;
6779             if (i < num_toks)
6780             {
6781                 char *endptr;
6782                 int n = SnortStrtol(toks[i], &endptr, 0);
6783 
6784                 if ((errno == ERANGE) || (*endptr != '\0') || (n <= 0))
6785                 {
6786                     ParseError("Invalid argument for max_queue_events: %s.  "
6787                                "Need a non-negative integer.", toks[i]);
6788                 }
6789 
6790                 fpSetMaxQueueEvents(fp, n);
6791                 old_max_queue_events = -1;  /* Don't reset to old value */
6792             }
6793             else
6794             {
6795                 ParseError("Missing argument to 'max_queue_events'.");
6796             }
6797         }
6798         else if (strcasecmp(toks[i], DETECTION_OPT__SPLIT_ANY_ANY) == 0)
6799         {
6800             fpDetectSetSplitAnyAny(fp, 1);
6801         }
6802         else if (strcasecmp(toks[i], DETECTION_OPT__MAX_PATTERN_LEN) == 0)
6803         {
6804             i++;
6805             if (i < num_toks)
6806             {
6807                 char *endptr;
6808                 int n = SnortStrtol(toks[i], &endptr, 0);
6809 
6810                 if ((errno == ERANGE) || (*endptr != '\0') || (n < 0))
6811                 {
6812                     ParseError("Invalid argument for max-pattern-len: %s.  "
6813                                "Need a non-negative integer.", toks[i]);
6814                 }
6815 
6816                 fpSetMaxPatternLen(fp, n);
6817             }
6818             else
6819             {
6820                 ParseError("Missing argument to 'max-pattern-len'.");
6821             }
6822         }
6823         else if (strcasecmp(toks[i], DETECTION_OPT__DEBUG_PRINT_FAST_PATTERN) == 0)
6824         {
6825             fpDetectSetDebugPrintFastPatterns(fp, 1);
6826         }
6827         else
6828         {
6829             ParseError("'%s' is an invalid option to the 'config detection' "
6830                        "configuration.", toks[i]);
6831         }
6832     }
6833 
6834     mSplitFree(&toks, num_toks);
6835 
6836     if (old_max_queue_events != -1)
6837         fp->max_queue_events = old_max_queue_events;
6838     if (old_stream_inserts != -1)
6839         fp->inspect_stream_insert = old_stream_inserts;
6840 
6841     fp->configured = 1;
6842 }
6843 
ConfigDetectionFilter(SnortConfig * sc,char * args)6844 void ConfigDetectionFilter(SnortConfig *sc, char *args)
6845 {
6846     char **toks;
6847     int num_toks;
6848 
6849     if ((sc == NULL) || (args == NULL))
6850         return;
6851 
6852     if (!sc->detection_filter_config->enabled)
6853         return;
6854 
6855     toks = mSplit(args, " \t", 2, &num_toks, 0);
6856     if (num_toks != 2)
6857     {
6858         ParseError("Detection filter memcap requires a positive "
6859                    "integer argument.");
6860     }
6861 
6862     if (strcasecmp(toks[0], THRESHOLD_OPT__MEMCAP) == 0)
6863     {
6864         char *endptr;
6865 
6866         sc->detection_filter_config->memcap = SnortStrtol(toks[1], &endptr, 0);
6867         if ((errno == ERANGE) || (*endptr != '\0') ||
6868             (sc->detection_filter_config->memcap < 0))
6869         {
6870             ParseError("Invalid detection filter memcap: %s.  Must be a "
6871                        "positive integer.", toks[1]);
6872         }
6873     }
6874     else
6875     {
6876         ParseError("Unknown argument to threshold configuration: %s.", toks[0]);
6877     }
6878 
6879     mSplitFree(&toks, num_toks);
6880 
6881 }
6882 
ConfigDisableDecodeAlerts(SnortConfig * sc,char * args)6883 void ConfigDisableDecodeAlerts(SnortConfig *sc, char *args)
6884 {
6885     if (sc == NULL)
6886         return;
6887 
6888     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the decoder alerts\n"););
6889     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__DEFAULT;
6890 }
6891 
ConfigDisableDecodeDrops(SnortConfig * sc,char * args)6892 void ConfigDisableDecodeDrops(SnortConfig *sc, char *args)
6893 {
6894     if (sc == NULL)
6895         return;
6896 
6897     /* OBSOLETE -- default is disabled */
6898     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of decoder alerts\n"););
6899     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__DEFAULT;
6900 }
6901 
6902 #ifdef INLINE_FAILOPEN
ConfigDisableInlineFailopen(SnortConfig * sc,char * args)6903 void ConfigDisableInlineFailopen(SnortConfig *sc, char *args)
6904 {
6905     if (sc == NULL)
6906         return;
6907 
6908     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Inline Init Failopen disabled\n"););
6909     sc->run_flags |= RUN_FLAG__DISABLE_FAILOPEN;
6910 }
6911 #endif
6912 
ConfigDisableIpOptAlerts(SnortConfig * sc,char * args)6913 void ConfigDisableIpOptAlerts(SnortConfig *sc, char *args)
6914 {
6915     if (sc == NULL)
6916         return;
6917 
6918     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the alert of all the ipopt alerts\n"););
6919     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
6920 }
6921 
ConfigDisableIpOptDrops(SnortConfig * sc,char * args)6922 void ConfigDisableIpOptDrops(SnortConfig *sc, char *args)
6923 {
6924     if (sc == NULL)
6925         return;
6926 
6927     /* OBSOLETE -- default is disabled */
6928     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all the ipopt alerts\n"););
6929     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
6930 }
6931 
ConfigDisableTcpOptAlerts(SnortConfig * sc,char * args)6932 void ConfigDisableTcpOptAlerts(SnortConfig *sc, char *args)
6933 {
6934     if (sc == NULL)
6935         return;
6936 
6937     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the all the other tcpopt alerts\n"););
6938     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
6939 }
6940 
ConfigDisableTcpOptDrops(SnortConfig * sc,char * args)6941 void ConfigDisableTcpOptDrops(SnortConfig *sc, char *args)
6942 {
6943     if (sc == NULL)
6944         return;
6945 
6946     /* OBSOLETE -- default is disabled */
6947     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all other tcpopt alerts\n"););
6948     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
6949 }
6950 
ConfigDisableTcpOptExperimentalAlerts(SnortConfig * sc,char * args)6951 void ConfigDisableTcpOptExperimentalAlerts(SnortConfig *sc, char *args)
6952 {
6953     if (sc == NULL)
6954         return;
6955 
6956     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt experimental alerts\n"););
6957     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_EXP_OPT;
6958 }
6959 
ConfigDisableTcpOptExperimentalDrops(SnortConfig * sc,char * args)6960 void ConfigDisableTcpOptExperimentalDrops(SnortConfig *sc, char *args)
6961 {
6962     if (sc == NULL)
6963         return;
6964 
6965     /* OBSOLETE -- default is disabled */
6966     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt exprimental alerts\n"););
6967     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_EXP_OPT;
6968 }
6969 
ConfigDisableTcpOptObsoleteAlerts(SnortConfig * sc,char * args)6970 void ConfigDisableTcpOptObsoleteAlerts(SnortConfig *sc, char *args)
6971 {
6972     if (sc == NULL)
6973         return;
6974 
6975     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the tcpopt obsolete alerts\n"););
6976     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_OBS_OPT;
6977 }
6978 
ConfigDisableTcpOptObsoleteDrops(SnortConfig * sc,char * args)6979 void ConfigDisableTcpOptObsoleteDrops(SnortConfig *sc, char *args)
6980 {
6981     if (sc == NULL)
6982         return;
6983 
6984     /* OBSOLETE -- default is disabled */
6985     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt obsolete alerts\n"););
6986     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_OBS_OPT;
6987 }
6988 
ConfigDisableTTcpAlerts(SnortConfig * sc,char * args)6989 void ConfigDisableTTcpAlerts(SnortConfig *sc, char *args)
6990 {
6991     if (sc == NULL)
6992         return;
6993 
6994     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the ttcp alerts\n"););
6995     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
6996 }
6997 
ConfigDisableTTcpDrops(SnortConfig * sc,char * args)6998 void ConfigDisableTTcpDrops(SnortConfig *sc, char *args)
6999 {
7000     if (sc == NULL)
7001         return;
7002 
7003     /* OBSOLETE -- default is disabled */
7004     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of ttcp alerts\n"););
7005     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
7006 }
7007 
ConfigDumpCharsOnly(SnortConfig * sc,char * args)7008 void ConfigDumpCharsOnly(SnortConfig *sc, char *args)
7009 {
7010     if (sc == NULL)
7011         return;
7012 
7013     /* dump the application layer as text only */
7014     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Character payload dump set\n"););
7015     sc->output_flags |= OUTPUT_FLAG__CHAR_DATA;
7016 }
7017 
ConfigDumpPayload(SnortConfig * sc,char * args)7018 void ConfigDumpPayload(SnortConfig *sc, char *args)
7019 {
7020     if (sc == NULL)
7021         return;
7022 
7023     /* dump the application layer */
7024     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Payload dump set\n"););
7025     sc->output_flags |= OUTPUT_FLAG__APP_DATA;
7026 }
7027 
ConfigDumpPayloadVerbose(SnortConfig * sc,char * args)7028 void ConfigDumpPayloadVerbose(SnortConfig *sc, char *args)
7029 {
7030     if (sc == NULL)
7031         return;
7032 
7033     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose packet bytecode dumps enabled\n"););
7034     sc->output_flags |= OUTPUT_FLAG__VERBOSE_DUMP;
7035 }
7036 
ConfigEnableDecodeDrops(SnortConfig * sc,char * args)7037 void ConfigEnableDecodeDrops(SnortConfig *sc, char *args)
7038 {
7039     if (sc == NULL)
7040         return;
7041 
7042     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the drop of decoder alerts\n"););
7043     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__DEFAULT;
7044 }
7045 
ConfigEnableDecodeOversizedAlerts(SnortConfig * sc,char * args)7046 void ConfigEnableDecodeOversizedAlerts(SnortConfig *sc, char *args)
7047 {
7048     if (sc == NULL)
7049         return;
7050 
7051     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the decoder oversized packet alerts\n"););
7052     sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags |= DECODE_EVENT_FLAG__OVERSIZED;
7053 }
7054 
ConfigEnableDecodeOversizedDrops(SnortConfig * sc,char * args)7055 void ConfigEnableDecodeOversizedDrops(SnortConfig *sc, char *args)
7056 {
7057     if (sc == NULL)
7058         return;
7059 
7060     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling the drop of decoder oversized packets\n"););
7061     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__OVERSIZED;
7062 }
7063 
ConfigEnableDeepTeredoInspection(SnortConfig * sc,char * args)7064 void ConfigEnableDeepTeredoInspection(SnortConfig *sc, char *args)
7065 {
7066     if (sc == NULL)
7067         return;
7068 
7069     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling deep Teredo inspection\n"););
7070     sc->enable_teredo = 1; /* TODO: add this to some existing flag bitfield? */
7071 }
7072 
7073 #define GTP_U_PORT 2152
7074 #define GTP_U_PORT_V0 3386
ConfigEnableGTPDecoding(SnortConfig * sc,char * args)7075 void ConfigEnableGTPDecoding(SnortConfig *sc, char *args)
7076 {
7077     PortObject *portObject;
7078     int numberOfPorts = 0;
7079 
7080     if (sc == NULL)
7081         return;
7082 
7083     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling GTP decoding\n"););
7084     sc->enable_gtp = 1;
7085 
7086     /*Set the ports*/
7087 
7088     portObject = PortVarTableFind( sc->targeted_policies[getParserPolicy(sc)]->portVarTable, "GTP_PORTS");
7089     if (portObject)
7090     {
7091        sc->gtp_ports =  PortObjectCharPortArray(sc->gtp_ports,portObject, &numberOfPorts);
7092     }
7093 
7094     if (!sc->gtp_ports || (0 == numberOfPorts))
7095     {
7096         /*No ports defined, use default GTP ports*/
7097         sc->gtp_ports = (char *)SnortAlloc(UINT16_MAX);
7098         sc->gtp_ports[GTP_U_PORT] = 1;
7099         sc->gtp_ports[GTP_U_PORT_V0] = 1;
7100 
7101     }
7102 }
7103 
ConfigEnableEspDecoding(SnortConfig * sc,char * args)7104 void ConfigEnableEspDecoding(SnortConfig *sc, char *args)
7105 {
7106     int ret;
7107     if (sc == NULL)
7108         return;
7109 
7110     if (args)
7111     {
7112         ret = ParseBool(args);
7113         if (ret == -1)
7114         {
7115             ParseError("Invalid argument to ESP decoder argument: %s\n"
7116                        "Please specify \"enable\" or \"disable\".", args);
7117         }
7118 
7119         sc->enable_esp = ret;
7120     }
7121 
7122     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Changing ESP decoding\n"););
7123 }
7124 
ConfigEnableIpOptDrops(SnortConfig * sc,char * args)7125 void ConfigEnableIpOptDrops(SnortConfig *sc, char *args)
7126 {
7127     if (sc == NULL)
7128         return;
7129 
7130     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all the ipopt alerts\n"););
7131     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
7132 }
7133 
7134 #ifdef MPLS
ConfigEnableMplsMulticast(SnortConfig * sc,char * args)7135 void ConfigEnableMplsMulticast(SnortConfig *sc, char *args)
7136 {
7137     if (sc == NULL)
7138         return;
7139 
7140     sc->run_flags |= RUN_FLAG__MPLS_MULTICAST;
7141 }
7142 
ConfigEnableMplsOverlappingIp(SnortConfig * sc,char * args)7143 void ConfigEnableMplsOverlappingIp(SnortConfig *sc, char *args)
7144 {
7145     if (sc == NULL)
7146         return;
7147 
7148     sc->run_flags |= RUN_FLAG__MPLS_OVERLAPPING_IP;
7149 }
7150 #endif
7151 
ConfigEnableTcpOptDrops(SnortConfig * sc,char * args)7152 void ConfigEnableTcpOptDrops(SnortConfig *sc, char *args)
7153 {
7154     if (sc == NULL)
7155         return;
7156 
7157     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of all other tcpopt alerts\n"););
7158     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
7159 }
7160 
ConfigEnableTcpOptExperimentalDrops(SnortConfig * sc,char * args)7161 void ConfigEnableTcpOptExperimentalDrops(SnortConfig *sc, char *args)
7162 {
7163     if (sc == NULL)
7164         return;
7165 
7166     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "enabling the drop of tcpopt exprimental alerts\n"););
7167     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_EXP_OPT;
7168 }
7169 
ConfigEnableTcpOptObsoleteDrops(SnortConfig * sc,char * args)7170 void ConfigEnableTcpOptObsoleteDrops(SnortConfig *sc, char *args)
7171 {
7172     if (sc == NULL)
7173         return;
7174 
7175     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of tcpopt obsolete alerts\n"););
7176     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags |= DECODE_EVENT_FLAG__TCP_OBS_OPT;
7177 }
7178 
ConfigEnableTTcpDrops(SnortConfig * sc,char * args)7179 void ConfigEnableTTcpDrops(SnortConfig *sc, char *args)
7180 {
7181     if (sc == NULL)
7182         return;
7183 
7184     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "disabling the drop of ttcp alerts\n"););
7185     sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__TCP_TTCP_OPT;
7186 }
7187 
ConfigEventFilter(SnortConfig * sc,char * args)7188 void ConfigEventFilter(SnortConfig *sc, char *args)
7189 {
7190     char **toks;
7191     int num_toks;
7192 
7193     if ((sc == NULL) || (args == NULL))
7194         return;
7195 
7196     if (!sc->threshold_config->enabled)
7197         return;
7198 
7199     toks = mSplit(args, " \t", 2, &num_toks, 0);
7200     if (num_toks != 2)
7201     {
7202         ParseError("Threshold memcap requires a positive integer argument.");
7203     }
7204 
7205     if (strcasecmp(toks[0], THRESHOLD_OPT__MEMCAP) == 0)
7206     {
7207         char *endptr;
7208 
7209         sc->threshold_config->memcap = SnortStrtol(toks[1], &endptr, 0);
7210         if ((errno == ERANGE) || (*endptr != '\0') ||
7211             (sc->threshold_config->memcap < 0))
7212         {
7213             ParseError("Invalid threshold memcap: %s.  Must be a "
7214                        "positive integer.", toks[1]);
7215         }
7216     }
7217     else
7218     {
7219         ParseError("Unknown argument to threshold configuration: %s.", toks[0]);
7220     }
7221 
7222     mSplitFree(&toks, num_toks);
7223 }
7224 
ConfigEventQueue(SnortConfig * sc,char * args)7225 void ConfigEventQueue(SnortConfig *sc, char *args)
7226 {
7227     char **toks;
7228     int num_toks;
7229     int i;
7230     EventQueueConfig *eq;
7231 
7232     if ((sc == NULL) || (args == NULL))
7233         return;
7234 
7235     eq = sc->event_queue_config;
7236 
7237     toks = mSplit(args, ", ", 0, &num_toks, 0);
7238 
7239     for (i = 0; i < num_toks; i++)
7240     {
7241         if (strcasecmp(toks[i], EVENT_QUEUE_OPT__MAX_QUEUE) == 0)
7242         {
7243             i++;
7244             if (i < num_toks)
7245             {
7246                 char *endptr;
7247 
7248                 eq->max_events = SnortStrtol(toks[i], &endptr, 0);
7249                 if ((errno == ERANGE) || (*endptr != '\0') ||
7250                     (eq->max_events <= 0))
7251                 {
7252                     ParseError("Invalid argument for max_queue: %s.  Must "
7253                                "be a positive integer.", toks[i]);
7254                 }
7255             }
7256             else
7257             {
7258                 ParseError("No argument to 'max_queue'.  Argument must "
7259                            "be a positive integer.");
7260             }
7261         }
7262         else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__LOG) == 0)
7263         {
7264             i++;
7265             if (i < num_toks)
7266             {
7267                 char *endptr;
7268 
7269                 eq->log_events = SnortStrtol(toks[i], &endptr, 0);
7270                 if ((errno == ERANGE) || (*endptr != '\0') ||
7271                     (eq->log_events <= 0))
7272                 {
7273                     ParseError("Invalid argument for 'log': %s.  Must be "
7274                                "a positive integer.", toks[i]);
7275                 }
7276             }
7277             else
7278             {
7279                 ParseError("No argument to 'log'.  Argument must be a "
7280                            "positive integer.");
7281             }
7282         }
7283         else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__ORDER_EVENTS) == 0)
7284         {
7285             i++;
7286             if(i < num_toks)
7287             {
7288                 if (strcasecmp(toks[i], ORDER_EVENTS_OPT__PRIORITY) == 0)
7289                 {
7290                     eq->order = SNORT_EVENTQ_PRIORITY;
7291                 }
7292                 else if (strcasecmp(toks[i], ORDER_EVENTS_OPT__CONTENT_LENGTH) == 0)
7293                 {
7294                     eq->order = SNORT_EVENTQ_CONTENT_LEN;
7295                 }
7296                 else
7297                 {
7298                     ParseError("Invalid argument to 'order_events': %s.  "
7299                                "Arguments may be either 'priority' or "
7300                                "content_length.", toks[i]);
7301                 }
7302             }
7303             else
7304             {
7305                 ParseError("No argument to 'order_events'.  Arguments may be "
7306                            "either 'priority' or content_length.");
7307             }
7308         }
7309         else if (strcasecmp(toks[i], EVENT_QUEUE_OPT__PROCESS_ALL_EVENTS) == 0)
7310         {
7311             eq->process_all_events = 1;
7312         }
7313         else
7314         {
7315             ParseError("Invalid argument to 'event_queue'.  To configure "
7316                        "event_queue, the options 'max_queue', 'log', and "
7317                        "'order_events' must be configured.");
7318         }
7319     }
7320 
7321     if (eq->max_events < eq->log_events )
7322         eq->max_events = eq->log_events;
7323 
7324     mSplitFree(&toks, num_toks);
7325 }
7326 
ConfigEventTrace(SnortConfig * sc,char * args)7327 void ConfigEventTrace(SnortConfig *sc, char *args)
7328 {
7329     char **toks;
7330     int num_toks = 0;
7331     int i;
7332 
7333     if ( !sc )
7334         return;
7335 
7336     sc->event_trace_file = EVENT_TRACE_OPT__FILE_DEFAULT;
7337     sc->event_trace_max = EVENT_TRACE_OPT__MAX_DATA_DEFAULT;
7338 
7339     if ( args )
7340         toks = mSplit(args, ", ", 0, &num_toks, 0);
7341 
7342     for (i = 0; i < num_toks; i++)
7343     {
7344         if (strcasecmp(toks[i], EVENT_TRACE_OPT__MAX_DATA) == 0)
7345         {
7346             i++;
7347             if (i < num_toks)
7348             {
7349                 char* endptr;
7350                 long max = SnortStrtol(toks[i], &endptr, 0);
7351 
7352                 if ( (errno == ERANGE) || (*endptr != '\0') ||
7353                     (max <= 0) || (max > 65535) )
7354                 {
7355                     ParseError("Invalid argument for %s: %s.  Must be a positive "
7356                         "integer < 65536.", EVENT_TRACE_OPT__MAX_DATA, toks[i]);
7357                 }
7358                 sc->event_trace_max = (uint16_t)max;
7359             }
7360             else
7361             {
7362                 ParseError("No argument to %s.  Argument must be a positive "
7363                     "integer < 65536.", EVENT_TRACE_OPT__MAX_DATA);
7364             }
7365         }
7366         else if (strcasecmp(toks[i], EVENT_TRACE_OPT__FILE) == 0)
7367         {
7368             i++;
7369             if(i < num_toks)
7370                 sc->event_trace_file = toks[i];
7371             else
7372             {
7373                 ParseError("No argument to %s.  Argument must be a string."
7374                     EVENT_TRACE_OPT__FILE);
7375             }
7376         }
7377         else
7378         {
7379             ParseError("Invalid argument to 'event_trace'.  To configure "
7380                 "event_trace, only the options 'file' and 'max_data' can "
7381                 "can be specified.  Defaults are %s and %d.",
7382                 EVENT_TRACE_OPT__FILE_DEFAULT, EVENT_TRACE_OPT__MAX_DATA_DEFAULT);
7383         }
7384     }
7385     sc->event_trace_file = SnortStrdup(sc->event_trace_file);
7386 
7387     mSplitFree(&toks, num_toks);
7388 }
7389 
ConfigReact(SnortConfig * sc,char * args)7390 void ConfigReact (SnortConfig *sc, char *args)
7391 {
7392     if ((sc == NULL) || (args == NULL))
7393         return;
7394 
7395     sc->react_page = SnortStrdup(args);
7396 
7397     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7398         "react: page is %s\n", sc->react_page););
7399 }
7400 
7401 #ifdef ENABLE_RESPONSE3
ConfigFlexresp2Interface(SnortConfig * sc,char * args)7402 void ConfigFlexresp2Interface(SnortConfig *sc, char *args)
7403 {
7404     ParseWarning("flexresp2_interface is no longer supported.\n");
7405 }
7406 
ConfigFlexresp2Attempts(SnortConfig * sc,char * args)7407 void ConfigFlexresp2Attempts(SnortConfig *sc, char *args)
7408 {
7409     ParseWarning("flexresp2_attempts is no longer supported; "
7410         "you must use config response: attempts <#> instead.\n");
7411 }
7412 
ConfigFlexresp2Memcap(SnortConfig * sc,char * args)7413 void ConfigFlexresp2Memcap(SnortConfig *sc, char *args)
7414 {
7415     ParseWarning("flexresp2_memcap is no longer supported.\n");
7416 }
7417 
ConfigFlexresp2Rows(SnortConfig * sc,char * args)7418 void ConfigFlexresp2Rows(SnortConfig *sc, char *args)
7419 {
7420     ParseWarning("flexresp2_rows is no longer supported.\n");
7421 }
7422 #endif
7423 
7424 #ifdef ACTIVE_RESPONSE
7425 // TBD:  once code can be checked in, move all config funcs
7426 // from parser.[ch] to [parser-]config.[ch] *or* at least move
7427 // Config* declarations from parser.h to parser.c or parser-config.h.
ConfigResponse(SnortConfig * sc,char * args)7428 void ConfigResponse (SnortConfig *sc, char *args)
7429 {
7430     char **toks;
7431     int num_toks;
7432     int i;
7433 
7434     if ((sc == NULL) || (args == NULL))
7435         return;
7436 
7437     toks = mSplit(args, ", ", 0, &num_toks, 0);
7438 
7439     for (i = 0; i < num_toks; i++)
7440     {
7441         if ( !strcasecmp(toks[i], RESPONSE_OPT__ATTEMPTS) )
7442         {
7443             if ( ++i < num_toks )
7444             {
7445                 char *endptr;
7446                 long int value = strtol(toks[i], &endptr, 0);
7447 
7448                 if ((errno == ERANGE) || (*endptr != '\0') ||
7449                     (value < 1) || (value > 20))
7450                 {
7451                     ParseError("Invalid argument for attempts: %s.  "
7452                         "Argument must be between 1 and 20 inclusive.", toks[i]);
7453                 }
7454                 sc->respond_attempts = (uint8_t)value;
7455             }
7456             else
7457             {
7458                 ParseError("No argument to 'attempts'.  "
7459                     "Argument must be between 1 and 20 inclusive.");
7460             }
7461         }
7462         else if ( !strcasecmp(toks[i], RESPONSE_OPT__DEVICE) )
7463         {
7464             if ( ++i < num_toks )
7465             {
7466                 sc->respond_device = SnortStrdup(toks[i]);
7467             }
7468             else
7469             {
7470                 ParseError("No argument to 'device'.  Use 'ip' for network "
7471                     "layer responses or 'eth0' etc. for link layer responses.");
7472             }
7473         }
7474         else if ( !strcasecmp(toks[i], RESPONSE_OPT__DST_MAC) )
7475         {
7476             if ( ++i < num_toks )
7477             {
7478                 eth_addr_t dst;
7479                 if (eth_pton( toks[i], &dst) < 0)
7480                 {
7481                     ParseError("Format check failed: %s,  Use format like 12:34:56:78:90:1a", toks[i]);
7482                 }
7483                 sc->eth_dst = SnortAlloc (sizeof(dst.data));
7484                 memcpy(sc->eth_dst, dst.data, sizeof(dst.data));
7485             }
7486             else
7487             {
7488                 ParseError("No argument to 'dst_mac'.  Use format 12:34:56:78:90:1a");
7489             }
7490         }
7491         else
7492         {
7493             ParseError("Invalid config response option '%s'", toks[i]);
7494         }
7495     }
7496     mSplitFree(&toks, num_toks);
7497 }
7498 #endif
7499 
ConfigFlowbitsSize(SnortConfig * sc,char * args)7500 void ConfigFlowbitsSize(SnortConfig *sc, char *args)
7501 {
7502     if ((sc == NULL) || (args == NULL))
7503         return;
7504     setFlowbitSize(args);
7505     sc->flowbit_size = (uint16_t)getFlowbitSizeInBytes();
7506 }
7507 
7508 /****************************************************************************
7509  *
7510  * Purpose: Parses a protocol plus a list of ports.
7511  *          The protocol should be "udp" or "tcp".
7512  *          The ports list should be a list of numbers or pairs of numbers.
7513  *          Each element of the list is separated by a space character.
7514  *          Each pair of numbers is separated by a colon character.
7515  *          So the string passed in is e.g. "tcp 443 578 6667:6681 13456"
7516  *          The numbers do not have to be in numerical order.
7517  *
7518  * Arguments:
7519  *  SnortConfig *
7520  *      The snort config to store ignored ports.
7521  *  char *
7522  *      string containing protocol plus list of ports
7523  *
7524  * Returns: void function
7525  *
7526  *****************************************************************************/
ConfigIgnorePorts(SnortConfig * sc,char * args)7527 void ConfigIgnorePorts(SnortConfig *sc, char *args)
7528 {
7529     char ** toks;
7530     int     num_toks = 0;
7531     int     i, p;
7532     uint16_t hi_port = 0, lo_port = 0;
7533     int     protocol;
7534     int     not_flag;
7535 
7536     if ((sc == NULL) || (args == NULL))
7537         return;
7538 
7539     LogMessage("Found ignore_ports config directive (%s)\n", args);
7540 
7541     toks = mSplit(args, " \t", 0, &num_toks, 0);
7542 
7543     if ( !num_toks )
7544         ParseError("config ignore_ports: Empty port list.");
7545 
7546     protocol = GetRuleProtocol(toks[0]);
7547 
7548     if ( !(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) )
7549     {
7550         ParseError("Invalid protocol: %s.", toks[0]);
7551     }
7552 
7553     for ( i = 1; i < num_toks; i++ )
7554     {
7555         /*  Re-use function from rules processing  */
7556         ParsePort(sc, toks[i], &hi_port, &lo_port, toks[0], &not_flag);
7557 
7558         for ( p = lo_port; p <= hi_port; p++ )
7559         {
7560             if (protocol == IPPROTO_TCP)
7561                 sc->ignore_ports[p] |= PROTO_BIT__TCP;
7562             else if (protocol == IPPROTO_UDP)
7563                 sc->ignore_ports[p] |= PROTO_BIT__UDP;
7564         }
7565     }
7566 
7567     mSplitFree(&toks, num_toks);
7568 }
7569 
ConfigIncludeVlanInAlert(SnortConfig * sc,char * args)7570 void ConfigIncludeVlanInAlert(SnortConfig *sc, char *args)
7571 {
7572     if (sc == NULL)
7573         return;
7574 
7575     sc->output_flags |= OUTPUT_FLAG__ALERT_VLAN;
7576 }
7577 
ConfigInterface(SnortConfig * sc,char * args)7578 void ConfigInterface(SnortConfig *sc, char *args)
7579 {
7580     if ((args == NULL) || (sc == NULL) || (sc->interface != NULL))
7581         return;
7582 
7583 #ifdef WIN32
7584     /* first, try to handle the "-i1" case, where an interface
7585      * is specified by number.  If this fails, then fall-through
7586      * to the case outside the ifdef/endif, where an interface
7587      * can be specified by its fully qualified name, like as is
7588      * shown by running 'snort -W', ie.
7589      * "\Device\Packet_{12345678-90AB-CDEF-1234567890AB}"
7590      */
7591     {
7592         char errorbuf[PCAP_ERRBUF_SIZE];
7593         int adaplen = atoi(args);
7594 
7595         if (adaplen > 0)
7596         {
7597             pcap_if_t *alldevs;
7598             pcap_if_t *dev;
7599             int i = 1;
7600 
7601             if (pcap_findalldevs(&alldevs, errorbuf) == -1)
7602                 ParseError("Could not get device list: %s.", errorbuf);
7603 
7604             for (dev = alldevs; dev != NULL; dev = dev->next)
7605             {
7606                 if (i == adaplen)
7607                     break;
7608                 i++;
7609             }
7610 
7611             if (dev == NULL)
7612                 ParseError("Invalid device number: %d.", adaplen);
7613 
7614             sc->interface = SnortStrdup(dev->name);
7615             pcap_freealldevs(alldevs);
7616             return;
7617         }
7618     }
7619 #endif  /* WIN32 */
7620 
7621     /* this code handles the case in which the user specifies
7622      * the entire name of the interface and it is compiled
7623      * regardless of which OS you have */
7624     sc->interface = SnortStrdup(args);
7625 }
7626 
ConfigIpv6Frag(SnortConfig * sc,char * args)7627 void ConfigIpv6Frag(SnortConfig *sc, char *args)
7628 {
7629     int num_opts;
7630     char **opt_toks;
7631     int i;
7632 
7633     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"IPv6 Rule Option\n"););
7634 
7635     if ((sc == NULL) || (args == NULL))
7636         return;
7637 
7638     opt_toks = mSplit(args, ",", 0, &num_opts, 0);
7639 
7640     for (i = 0; i < num_opts; i++)
7641     {
7642         char **arg_toks;
7643         int num_args;
7644 
7645         arg_toks = mSplit(opt_toks[i], " \t", 2, &num_args, 0);
7646 
7647         if(num_args != 2 || !arg_toks[1])
7648         {
7649              ParseError("ipv6_frag option '%s' requires an argument.",
7650                         arg_toks[0]);
7651              continue;
7652         }
7653 
7654         if(!strcasecmp(arg_toks[0], "bsd_icmp_frag_alert"))
7655         {
7656             DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7657                       "disabling the BSD ICMP fragmentation alert\n"););
7658             if(!strcasecmp(arg_toks[1], "off"))
7659                 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IPV6_BSD_ICMP_FRAG;
7660         }
7661         else if(!strcasecmp(arg_toks[0], "bad_ipv6_frag_alert"))
7662         {
7663             DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7664                       "disabling the IPv6 bad fragmentation packet alerts\n"););
7665             if(!strcasecmp(arg_toks[1], "off"))
7666                 sc->targeted_policies[getParserPolicy(sc)]->decoder_alert_flags &= ~DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
7667 
7668         }
7669         else if (!strcasecmp(arg_toks[0], "frag_timeout"))
7670         {
7671             long val;
7672             char *endp;
7673 
7674             val = strtol(arg_toks[1], &endp, 0);
7675             if(val <= 0 || val > 3600)
7676             {
7677                 ParseError("ipv6_frag_timeout: Invalid argument '%s'.  "
7678                            "Must be greater that 0 and less than 3600 "
7679                            "secnods.", arg_toks[1]);
7680             }
7681 
7682             if(args == endp || *endp)
7683             {
7684                 ParseError("ipv6_frag_timeout: Invalid argument '%s'.",
7685                            arg_toks[1]);
7686             }
7687 
7688             sc->ipv6_frag_timeout = val;
7689         }
7690         else if (!strcasecmp(arg_toks[0], "max_frag_sessions"))
7691         {
7692             long val;
7693             char *endp;
7694 
7695             val = strtol(arg_toks[1], &endp, 0);
7696             if (val <= 0)
7697             {
7698                 ParseError("ipv6_max_frag_sessions: Invalid number of sessions "
7699                            "'%s'. Must be greater than 0.", arg_toks[1]);
7700             }
7701 
7702             if(args == endp || *endp)
7703             {
7704                 ParseError("ipv6_max_frag_sessions: Invalid number of "
7705                            "sessions '%s'.", arg_toks[1]);
7706             }
7707 
7708             sc->ipv6_max_frag_sessions = val;
7709         }
7710         else if (!strcasecmp(arg_toks[0], "drop_bad_ipv6_frag"))
7711         {
7712             if(!strcasecmp(arg_toks[1], "off"))
7713             {
7714                 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
7715                       "disabling the BSD ICMP fragmentation alert\n"););
7716                 sc->targeted_policies[getParserPolicy(sc)]->decoder_drop_flags &= ~DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
7717             }
7718         }
7719         else
7720         {
7721              ParseError("Invalid option to ipv6_frag '%s %s'.",
7722                         arg_toks[0], arg_toks[1]);
7723         }
7724 
7725         mSplitFree(&arg_toks, num_args);
7726     }
7727 
7728     mSplitFree(&opt_toks, num_opts);
7729 }
7730 
ConfigLayer2Resets(SnortConfig * sc,char * args)7731 void ConfigLayer2Resets(SnortConfig *sc, char *args)
7732 {
7733     ParseWarning("layer2resets is deprecated.\n");
7734 }
7735 
ConfigLogDir(SnortConfig * sc,char * args)7736 void ConfigLogDir(SnortConfig *sc, char *args)
7737 {
7738     if ((args == NULL) || (sc == NULL) || (sc->log_dir != NULL))
7739         return;
7740 
7741     sc->log_dir = SnortStrdup(args);
7742 }
7743 
ConfigDaqType(SnortConfig * sc,char * args)7744 void ConfigDaqType(SnortConfig *sc, char *args)
7745 {
7746     if ( !args || !sc )
7747         return;
7748 
7749     if ( sc->daq_type )
7750         ParseError("Setting DAQ to %s but %s already selected.\n",
7751             args, sc->daq_type);
7752 
7753     // will be validated later after paths are established
7754     sc->daq_type = SnortStrdup(args);
7755 }
7756 
ConfigDaqMode(SnortConfig * sc,char * args)7757 void ConfigDaqMode(SnortConfig *sc, char *args)
7758 {
7759     if ( !args || !sc || sc->daq_mode )
7760         return;
7761 
7762     // will be validated later when daq is instantiated
7763     sc->daq_mode = SnortStrdup(args);
7764 }
7765 
ConfigDaqVar(SnortConfig * sc,char * args)7766 void ConfigDaqVar(SnortConfig *sc, char *args)
7767 {
7768     if ( !args || !sc )
7769         return;
7770 
7771     if ( !sc->daq_vars )
7772     {
7773         sc->daq_vars = StringVector_New();
7774 
7775         if ( !sc->daq_vars )
7776             ParseError("can't allocate memory for daq_var '%s'.", args);
7777     }
7778     if ( !StringVector_Add(sc->daq_vars, args) )
7779         ParseError("can't allocate memory for daq_var '%s'.", args);
7780 }
7781 
ConfigDaqDir(SnortConfig * sc,char * args)7782 void ConfigDaqDir(SnortConfig *sc, char *args)
7783 {
7784     if ( !args || !sc )
7785         return;
7786 
7787     if ( !sc->daq_dirs )
7788     {
7789         sc->daq_dirs = StringVector_New();
7790 
7791         if ( !sc->daq_dirs )
7792             ParseError("can't allocate memory for daq_dir '%s'.", args);
7793     }
7794     if ( !StringVector_Add(sc->daq_dirs, args) )
7795         ParseError("can't allocate memory for daq_dir '%s'.", args);
7796 }
7797 
ConfigDirtyPig(SnortConfig * sc,char * args)7798 void ConfigDirtyPig(SnortConfig *sc, char *args)
7799 {
7800     if ( sc )
7801         sc->dirty_pig = 1;
7802 }
7803 
7804 #ifdef TARGET_BASED
ConfigMaxAttributeHosts(SnortConfig * sc,char * args)7805 void ConfigMaxAttributeHosts(SnortConfig *sc, char *args)
7806 {
7807     uint32_t val = 0;
7808     char *endp;
7809 
7810     if ((sc == NULL) || (args == NULL))
7811         return;
7812 
7813     val = strtoul(args, &endp, 10);
7814     if (args == endp || *endp || (val == 0))
7815     {
7816         ParseError("max_attribute_hosts: Invalid number of hosts '%s'.  Must "
7817                    "be unsigned positive integer value.", args);
7818     }
7819     if ((val > MAX_MAX_ATTRIBUTE_HOSTS) || (val < MIN_MAX_ATTRIBUTE_HOSTS))
7820     {
7821         ParseError("max_atttribute_hosts: Invalid number of hosts %s'.  "
7822                    "Must be between %d and %d.", args,
7823                    MIN_MAX_ATTRIBUTE_HOSTS, MAX_MAX_ATTRIBUTE_HOSTS);
7824     }
7825 
7826     sc->max_attribute_hosts = val;
7827 }
7828 
ConfigMaxAttributeServicesPerHost(SnortConfig * sc,char * args)7829 void ConfigMaxAttributeServicesPerHost(SnortConfig *sc, char *args)
7830 {
7831     uint32_t val = 0;
7832     char *endp;
7833 
7834     if ((sc == NULL) || (args == NULL))
7835         return;
7836 
7837     val = strtoul(args, &endp, 10);
7838     if (args == endp || *endp || (val == 0))
7839     {
7840         ParseError("max_attribute_services_per_host: Invalid number of services '%s'.  Must "
7841                    "be unsigned positive integer value.", args);
7842     }
7843     if ((val > MAX_MAX_ATTRIBUTE_SERVICES_PER_HOST) || (val < MIN_MAX_ATTRIBUTE_SERVICES_PER_HOST))
7844     {
7845         ParseError("max_atttribute_services_per_host: Invalid number of services %s'.  "
7846                    "Must be between %d and %d.", args,
7847                    MIN_MAX_ATTRIBUTE_SERVICES_PER_HOST, MAX_MAX_ATTRIBUTE_SERVICES_PER_HOST);
7848     }
7849 
7850     sc->max_attribute_services_per_host = val;
7851 }
7852 
ConfigMaxMetadataServices(SnortConfig * sc,char * args)7853 void ConfigMaxMetadataServices(SnortConfig *sc, char *args)
7854 {
7855     uint32_t val = 0;
7856     char *endp;
7857 
7858     if ((sc == NULL) || (args == NULL))
7859         return;
7860 
7861     val = strtoul(args, &endp, 10);
7862     if (args == endp || *endp || (val == 0))
7863     {
7864         ParseError("max_metadata_services: Invalid number of hosts '%s'.  Must "
7865                    "be unsigned positive integer value.", args);
7866     }
7867     if ((val > MAX_MAX_METADATA_SERVICES) || (val < MIN_MAX_METADATA_SERVICES))
7868     {
7869         ParseError("max_metadata_services: Invalid number of hosts '%s'.  "
7870                    "Must be between %d and %d.", args,
7871                     MIN_MAX_METADATA_SERVICES, MAX_MAX_METADATA_SERVICES);
7872     }
7873 
7874     sc->max_metadata_services = val;
7875 }
7876 
ConfigDisableAttributeReload(SnortConfig * sc,char * args)7877 void ConfigDisableAttributeReload(SnortConfig *sc, char *args)
7878 {
7879     if (sc == NULL)
7880         return;
7881 
7882     sc->run_flags |= RUN_FLAG__DISABLE_ATTRIBUTE_RELOAD_THREAD;
7883 }
7884 #endif
7885 
7886 #ifdef MPLS
ConfigMaxMplsLabelChain(SnortConfig * sc,char * args)7887 void ConfigMaxMplsLabelChain(SnortConfig *sc, char *args)
7888 {
7889     char *endp;
7890     long val = 0;
7891 
7892     if (sc == NULL)
7893         return;
7894 
7895     if (args != NULL)
7896     {
7897         val = strtol(args, &endp, 0);
7898         if ((args == endp) || *endp || (val < -1))
7899             val = DEFAULT_LABELCHAIN_LENGTH;
7900     }
7901     else
7902     {
7903         val = DEFAULT_LABELCHAIN_LENGTH;
7904     }
7905 
7906     sc->mpls_stack_depth = val;
7907 }
7908 
ConfigMplsPayloadType(SnortConfig * sc,char * args)7909 void ConfigMplsPayloadType(SnortConfig *sc, char *args)
7910 {
7911     if (sc == NULL)
7912         return;
7913 
7914     if (args != NULL)
7915     {
7916         if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV4) == 0)
7917         {
7918             sc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV4;
7919         }
7920         else if (strcasecmp(args, MPLS_PAYLOAD_OPT__IPV6) == 0)
7921         {
7922             sc->mpls_payload_type = MPLS_PAYLOADTYPE_IPV6;
7923         }
7924         else if (strcasecmp(args, MPLS_PAYLOAD_OPT__ETHERNET) == 0)
7925         {
7926             sc->mpls_payload_type = MPLS_PAYLOADTYPE_ETHERNET;
7927         }
7928         else
7929         {
7930             ParseError("Non supported mpls payload type: %s.", args);
7931         }
7932     }
7933     else
7934     {
7935         sc->mpls_payload_type = DEFAULT_MPLS_PAYLOADTYPE;
7936     }
7937 }
7938 #endif
7939 
ConfigMinTTL(SnortConfig * sc,char * args)7940 void ConfigMinTTL(SnortConfig *sc, char *args)
7941 {
7942     long int value;
7943     char *endptr;
7944 
7945     if ((sc == NULL) || (args == NULL))
7946         return;
7947 
7948     value = strtol(args, &endptr, 0);
7949 
7950     if ((errno == ERANGE) || (*endptr != '\0') ||
7951         (value < 1) || (value > UINT8_MAX))
7952     {
7953         ParseError("Invalid argument to 'min_ttl' configuration: %s.  "
7954                    "Must be a positive integer.", args);
7955     }
7956 
7957     {
7958         SnortPolicy* pPolicy = sc->targeted_policies[getParserPolicy(sc)];
7959         pPolicy->min_ttl = (uint8_t)value;
7960     }
7961 }
7962 
7963 #ifdef NORMALIZER
ConfigNewTTL(SnortConfig * sc,char * args)7964 void ConfigNewTTL(SnortConfig *sc, char *args)
7965 {
7966     long int value;
7967     char *endptr;
7968 
7969     if ((sc == NULL) || (args == NULL))
7970         return;
7971 
7972     value = strtol(args, &endptr, 0);
7973 
7974     if ((errno == ERANGE) || (*endptr != '\0') ||
7975         (value < 1) || (value > UINT8_MAX))
7976     {
7977         ParseError("Invalid argument to 'new_ttl' configuration: %s.  "
7978                    "Must be a non-negative integer.", args);
7979     }
7980 
7981     {
7982         SnortPolicy* pPolicy = sc->targeted_policies[getParserPolicy(sc)];
7983         pPolicy->new_ttl = (uint8_t)value;
7984     }
7985 }
7986 #endif
7987 
ConfigNoLog(SnortConfig * sc,char * args)7988 void ConfigNoLog(SnortConfig *sc, char *args)
7989 {
7990     if (sc == NULL)
7991         return;
7992 
7993     sc->no_log = 1;
7994 }
7995 
ConfigNoLoggingTimestamps(SnortConfig * sc,char * args)7996 void ConfigNoLoggingTimestamps(SnortConfig *sc, char *args)
7997 {
7998     if (sc == NULL)
7999         return;
8000 
8001     sc->output_flags |= OUTPUT_FLAG__NO_TIMESTAMP;
8002 }
8003 
ConfigNoPcre(SnortConfig * sc,char * args)8004 void ConfigNoPcre(SnortConfig *sc, char *args)
8005 {
8006     if (sc == NULL)
8007         return;
8008 
8009     sc->run_flags |= RUN_FLAG__NO_PCRE;
8010 }
8011 
ConfigNoPromiscuous(SnortConfig * sc,char * args)8012 void ConfigNoPromiscuous(SnortConfig *sc, char *args)
8013 {
8014     if (sc == NULL)
8015         return;
8016 
8017     sc->run_flags |= RUN_FLAG__NO_PROMISCUOUS;
8018 }
8019 
ConfigObfuscate(SnortConfig * sc,char * args)8020 void ConfigObfuscate(SnortConfig *sc, char *args)
8021 {
8022     if (sc == NULL)
8023         return;
8024 
8025     sc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
8026 }
8027 
ConfigObfuscationMask(SnortConfig * sc,char * args)8028 void ConfigObfuscationMask(SnortConfig *sc, char *args)
8029 {
8030 
8031     if ((sc == NULL) || (args == NULL))
8032         return;
8033 
8034     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Got obfus data: %s\n", args););
8035 
8036     sc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
8037 
8038     sfip_pton(args, &sc->obfuscation_net);
8039 }
8040 
ConfigPafMax(SnortConfig * sc,char * args)8041 void ConfigPafMax (SnortConfig *sc, char *args)
8042 {
8043     long int value;
8044     char *endptr;
8045 
8046 
8047     const unsigned max = MAXIMUM_PAF_MAX;
8048 
8049     if ((sc == NULL) || (args == NULL))
8050         return;
8051 
8052     value = SnortStrtoulRange(args, &endptr, 0, 0, max);
8053 
8054     if ( (errno == ERANGE) || (*endptr != '\0') )
8055     {
8056         ParseError(
8057             "Invalid argument to '%s' configuration: %s.  "
8058             "Must be between 0 (off) and %u (max).",
8059             CONFIG_OPT__PAF_MAX, args, max);
8060     }
8061 
8062     {
8063         sc->paf_max = (uint32_t)value;
8064     }
8065 }
8066 
ConfigRuleListOrder(SnortConfig * sc,char * args)8067 void ConfigRuleListOrder(SnortConfig *sc, char *args)
8068 {
8069     OrderRuleLists(sc, args);
8070 }
8071 
ConfigPcreMatchLimit(SnortConfig * sc,char * args)8072 void ConfigPcreMatchLimit(SnortConfig *sc, char *args)
8073 {
8074     char *endp;
8075     long val = 0;
8076 
8077     if ((sc == NULL) || (args == NULL))
8078         return;
8079 
8080     val = strtol(args, &endp, 0);
8081     if ((args == endp) || *endp || (val < -1))
8082     {
8083         ParseError("pcre_match_limit: Invalid value '%s'.", args);
8084     }
8085 
8086     sc->pcre_match_limit = val;
8087 
8088     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "pcre_match_limit: %d\n",
8089                             sc->pcre_match_limit););
8090 }
8091 
ConfigPcreMatchLimitRecursion(SnortConfig * sc,char * args)8092 void ConfigPcreMatchLimitRecursion(SnortConfig *sc, char *args)
8093 {
8094     char *endp;
8095     long val = 0;
8096 
8097     if ((sc == NULL) || (args == NULL))
8098         return;
8099 
8100     val = strtol(args, &endp, 0);
8101     if ((args == endp) || *endp || (val < -1))
8102     {
8103         ParseError("pcre_match_limit_recursion: Invalid value '%s'.", args);
8104     }
8105 
8106     sc->pcre_match_limit_recursion = val;
8107 
8108     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "pcre_match_limit_recursion: %d\n",
8109                             sc->pcre_match_limit_recursion););
8110 }
8111 
ConfigPerfFile(SnortConfig * sc,char * args)8112 void ConfigPerfFile(SnortConfig *sc, char *args)
8113 {
8114     if ((sc == NULL) || (args == NULL))
8115         return;
8116 
8117     sc->perf_file = SnortStrdup(args);
8118 }
8119 
ConfigDumpPeriodicMemStatsFile(SnortConfig * sc,char * args)8120 void ConfigDumpPeriodicMemStatsFile(SnortConfig *sc, char *args)
8121 {
8122     if ((sc == NULL) || (args == NULL))
8123         return;
8124 
8125     sc->memdump_file = SnortStrdup(args);
8126 }
8127 
ConfigPacketCount(SnortConfig * sc,char * args)8128 void ConfigPacketCount(SnortConfig *sc, char *args)
8129 {
8130     char *endptr;
8131     long count;
8132 
8133     if ((sc == NULL) || (args == NULL))
8134         return;
8135 
8136     count = SnortStrtoul(args, &endptr, 0);
8137     if ((errno == ERANGE) || (*endptr != '\0'))
8138     {
8139         ParseError("Invalid packet count: %s.  Packet count must be between "
8140                    "0 and %u inclusive.", args, UINT32_MAX);
8141     }
8142 
8143     if ( count > 0 )
8144     {
8145         sc->pkt_cnt = count;
8146         LogMessage("Exiting after " STDu64 " packets\n", sc->pkt_cnt);
8147         return;
8148     }
8149 #ifdef REG_TEST
8150     sc->pkt_skip = -count;
8151     LogMessage("Processing after " STDu64 " packets\n", sc->pkt_skip);
8152 #else
8153     ParseError("Invalid packet count: %s.  Packet count must be greater than zero.");
8154 #endif
8155 }
8156 
ConfigPacketSnaplen(SnortConfig * sc,char * args)8157 void ConfigPacketSnaplen(SnortConfig *sc, char *args)
8158 {
8159     char *endptr;
8160     uint32_t snaplen;
8161 
8162     if ((sc == NULL) || (args == NULL))
8163         return;
8164 
8165     snaplen = SnortStrtoul(args, &endptr, 0);
8166 
8167     if ((errno == ERANGE) || (*endptr != '\0') ||
8168         ((snaplen != 0) && (snaplen < MIN_SNAPLEN)) ||
8169         (snaplen > MAX_SNAPLEN) )
8170     {
8171         ParseError("Invalid snaplen: %s.  Snaplen must be between "
8172                    "%u and %u inclusive or 0 for default = %u.",
8173                    args, MIN_SNAPLEN, MAX_SNAPLEN, DAQ_GetSnapLen());
8174     }
8175 
8176     sc->pkt_snaplen = snaplen;
8177 
8178     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
8179         "Snap length of packets set to: %d\n", sc->pkt_snaplen););
8180 }
8181 
ConfigPidPath(SnortConfig * sc,char * args)8182 void ConfigPidPath(SnortConfig *sc, char *args)
8183 {
8184     if ((args == NULL) || (sc == NULL))
8185         return;
8186 
8187     LogMessage("Found pid path directive (%s)\n", args);
8188 
8189     sc->run_flags |= RUN_FLAG__CREATE_PID_FILE;
8190     if (SnortStrncpy(sc->pid_path, args, sizeof(sc->pid_path)) != SNORT_STRNCPY_SUCCESS)
8191         ParseError("Pid path too long.");
8192 
8193     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Pid Path directory = %s\n",
8194                             sc->pid_path););
8195 }
8196 
ConfigPolicy(SnortConfig * sc,char * args)8197 void ConfigPolicy(SnortConfig *sc, char *args)
8198 {
8199     int num_toks;
8200     char **toks;
8201 
8202     if ((sc == NULL) || (sc->targeted_policies == NULL))
8203         return;
8204 
8205     toks = mSplit(args, " \t,", 20, &num_toks, 0);
8206 
8207     if (num_toks != 1)
8208     {
8209         mSplitFree(&toks, num_toks);
8210         return;
8211     }
8212 
8213     sc->targeted_policies[getParserPolicy(sc)]->configPolicyId = (unsigned short)(atoi(toks[0]));
8214 
8215     mSplitFree(&toks, num_toks);
8216 }
8217 
ConfigIpsPolicyMode(SnortConfig * sc,char * args)8218 void ConfigIpsPolicyMode(SnortConfig *sc, char *args)
8219 {
8220     if ((sc == NULL) || (sc->targeted_policies == NULL))
8221         return;
8222 
8223     sc->targeted_policies[getParserPolicy(sc)]->ips_policy_mode = GetPolicyMode(args, sc->run_flags);
8224 }
8225 
ConfigNapPolicyMode(SnortConfig * sc,char * args)8226 void ConfigNapPolicyMode(SnortConfig *sc, char *args)
8227 {
8228     if ((sc == NULL) || (sc->targeted_policies == NULL))
8229         return;
8230 
8231     sc->targeted_policies[getParserPolicy(sc)]->nap_policy_mode = GetPolicyMode(args, sc->run_flags);
8232 }
8233 
GetPolicyMode(char * args,int run_flags)8234 static int GetPolicyMode(char *args, int run_flags)
8235 {
8236     char **toks;
8237     int num_toks;
8238     int i;
8239     int mode = 0;
8240 
8241     if (args == NULL)
8242     {
8243         if ( run_flags & RUN_FLAG__INLINE )
8244             return POLICY_MODE__INLINE;
8245         else if ( run_flags & RUN_FLAG__INLINE_TEST )
8246             return POLICY_MODE__INLINE_TEST;
8247         else
8248             return POLICY_MODE__PASSIVE;
8249     }
8250 
8251     toks = mSplit(args, " \t", 10, &num_toks, 0);
8252     for (i = 0; i < num_toks; i++)
8253     {
8254         if (strcasecmp(toks[i], POLICY_MODE_PASSIVE) == 0)
8255         {
8256             if ( ScAdapterInlineTestMode() )
8257                 mode = POLICY_MODE__INLINE_TEST;
8258             else
8259                 mode = POLICY_MODE__PASSIVE;
8260         }
8261         else if (strcasecmp(toks[i], POLICY_MODE_INLINE) == 0)
8262         {
8263             /* If --enable-inline-test is specified it overwrites
8264              * policy_mode: inline */
8265             if( ScAdapterInlineTestMode() )
8266                 mode = POLICY_MODE__INLINE_TEST;
8267             else if (!ScAdapterInlineMode())
8268             {
8269                ParseWarning("Adapter is in Passive Mode. Hence switching "
8270                        "policy mode to tap.");
8271                mode = POLICY_MODE__PASSIVE;
8272 
8273             }
8274             else
8275                 mode = POLICY_MODE__INLINE;
8276         }
8277         else if (strcasecmp(toks[i], POLICY_MODE_INLINE_TEST) == 0)
8278         {
8279             mode = POLICY_MODE__INLINE_TEST;
8280         }
8281         else
8282         {
8283             ParseError("Unknown command line policy mode option: %s.", toks[i]);
8284         }
8285     }
8286 
8287     mSplitFree(&toks, num_toks);
8288     return mode;
8289 }
8290 
ConfigPolicyVersion(SnortConfig * sc,char * args)8291 void ConfigPolicyVersion(SnortConfig *sc, char *args)
8292 {
8293     char **toks;
8294     int num_toks;
8295 
8296     if ((sc == NULL) || (sc->targeted_policies == NULL) ||
8297         (snort_conf_file == NULL) || (args == NULL))
8298     {
8299         return;
8300     }
8301 
8302     toks = mSplit(args, " \t", 0, &num_toks, 0);
8303 
8304     if (num_toks == 1)
8305     {
8306         if (getParserPolicy(sc) != getDefaultPolicy())
8307         {
8308             ParseError("Targeted policies must have base policy version and "
8309                        "targeted policy version.");
8310         }
8311 
8312         if (sc->base_version == NULL)
8313         {
8314             sc->base_version = SnortStrdup(toks[0]);
8315         }
8316         else
8317         {
8318             if (strcmp(sc->base_version, toks[0]) != 0)
8319             {
8320                 ParseError("Base policy version mismatch: Current base "
8321                            "version: %s, %s: %s",
8322                            sc->base_version, file_name, toks[0]);
8323             }
8324         }
8325     }
8326     else if (num_toks == 2)
8327     {
8328         SnortPolicy *p = sc->targeted_policies[getParserPolicy(sc)];
8329 
8330         if (getParserPolicy(sc) == getDefaultPolicy())
8331             ParseError("Base policy must only have one policy version.");
8332 
8333         if (sc->base_version == NULL)
8334         {
8335             ParseError("Config option \"%s\" must be configured in \"%s\"",
8336                        CONFIG_OPT__POLICY_VERSION, snort_conf_file);
8337         }
8338 
8339         if (strcmp(sc->base_version, toks[0]) != 0)
8340         {
8341             ParseError("Base policy version mismatch: Current base "
8342                        "version: %s, %s: %s",
8343                        sc->base_version, file_name, toks[0]);
8344         }
8345 
8346         if (p->policy_version == NULL)
8347         {
8348             p->policy_version = SnortStrdup(toks[1]);
8349         }
8350         else
8351         {
8352             if (strcmp(p->policy_version, toks[1]) != 0)
8353             {
8354                 ParseError("Targeted policy version mismatch: Current targeted "
8355                            "policy version: %s, %s: %s",
8356                            p->policy_version, file_name, toks[1]);
8357             }
8358         }
8359     }
8360     else
8361     {
8362         ParseError("Invalid number of arguments to \"%s\": %s.",
8363                    CONFIG_OPT__POLICY_VERSION, args);
8364     }
8365 
8366     mSplitFree(&toks, num_toks);
8367 }
8368 
ConfigProtectedContent(SnortConfig * sc,char * args)8369 void ConfigProtectedContent(SnortConfig *sc, char *args)
8370 {
8371     int num_toks;
8372     char **toks;
8373 
8374     if ((sc == NULL) || (args == NULL))
8375         return;
8376 
8377     toks = mSplit(args, " \t", 2, &num_toks, 0);
8378 
8379     if( num_toks != 2 )
8380         ParseError("Invalid argument to protected_content");
8381 
8382     if( strcasecmp(toks[0], PROTECTED_CONTENT_OPT__HASH_TYPE) != 0 )
8383         ParseError("Invalid argument to protected_content");
8384 
8385     if( (sc->Default_Protected_Content_Hash_Type = SecHash_Name2Type( toks[1] )) == SECHASH_NONE )
8386         ParseError("Invalid protected content hash type");
8387 
8388     mSplitFree(&toks, num_toks);
8389 }
8390 
8391 #ifdef PPM_MGR
8392 /*
8393  * config ppm: feature, feature, feature,..
8394  *
8395  * config ppm: max-pkt-time usecs,
8396  *             disable-pkt-inspection,
8397  *             max-rule-time usecs,
8398  *             disable-rule-inspection, threshold 5,
8399  *             max-suspend-time secs,
8400  *             rule-events alert|syslog|console,
8401  *             pkt-events  alert|syslog|console,
8402  *             debug,
8403  *             debug-pkts
8404  */
ConfigPPM(SnortConfig * sc,char * args)8405 void ConfigPPM(SnortConfig *sc, char *args)
8406 {
8407     char **toks;
8408     int num_toks;
8409     int i;
8410     char *endptr;
8411     unsigned long int val;
8412     char **opts;
8413     int num_opts;
8414     int pktOpts = 0, ruleOpts = 0;
8415 
8416     if (sc == NULL)
8417         return;
8418 
8419     toks = mSplit(args, ",", 0, &num_toks, 0);
8420 
8421     if (!sc->ppm_cfg.enabled)
8422         ppm_init(&sc->ppm_cfg);
8423 
8424     /* defaults are set by ppm_init() */
8425     for(i = 0; i < num_toks; i++)
8426     {
8427         opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8428 
8429         if (strcasecmp(opts[0], PPM_OPT__MAX_PKT_TIME) == 0)
8430         {
8431             if (num_opts != 2)
8432             {
8433                 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8434             }
8435 
8436             val = SnortStrtoul(opts[1], &endptr, 0);
8437             if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8438             {
8439                 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8440             }
8441 
8442             ppm_set_max_pkt_time(&sc->ppm_cfg, val);
8443         }
8444         else if (strcasecmp(opts[0], PPM_OPT__MAX_RULE_TIME) == 0)
8445         {
8446             if (num_opts != 2)
8447             {
8448                 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8449             }
8450 
8451             val = SnortStrtoul(opts[1], &endptr, 0);
8452             if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8453             {
8454                 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8455             }
8456 
8457             ppm_set_max_rule_time(&sc->ppm_cfg, val);
8458         }
8459         else if (strcasecmp(opts[0], PPM_OPT__SUSPEND_TIMEOUT) == 0)
8460         {
8461             if (num_opts != 2)
8462             {
8463                 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8464             }
8465 
8466             val = SnortStrtoul(opts[1], &endptr, 0);
8467             if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8468             {
8469                 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8470             }
8471 
8472             ppm_set_max_suspend_time(&sc->ppm_cfg, val);
8473             ruleOpts++;
8474         }
8475         else if (strcasecmp(opts[0], PPM_OPT__SUSPEND_EXP_RULES) == 0)
8476         {
8477             if (num_opts != 1)
8478             {
8479                 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8480             }
8481 
8482             ppm_set_rule_action(&sc->ppm_cfg, PPM_ACTION_SUSPEND);
8483             ruleOpts++;
8484         }
8485         else if (strcasecmp(opts[0], PPM_OPT__THRESHOLD) == 0)
8486         {
8487             if (num_opts != 2)
8488             {
8489                 ParseError("config ppm: missing argument for '%s'.", opts[0]);
8490             }
8491 
8492             val = SnortStrtoul(opts[1], &endptr, 0);
8493             if ((opts[1][0] == '-') || (errno == ERANGE) || (*endptr != '\0'))
8494             {
8495                 ParseError("config ppm: Invalid %s '%s'.", opts[0], opts[1]);
8496             }
8497 
8498             ppm_set_rule_threshold(&sc->ppm_cfg, val);
8499             ruleOpts++;
8500         }
8501         else if (strcasecmp(opts[0], PPM_OPT__FAST_PATH_EXP_PKTS) == 0)
8502         {
8503             if (num_opts != 1)
8504             {
8505                 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8506             }
8507 
8508             ppm_set_pkt_action(&sc->ppm_cfg, PPM_ACTION_SUSPEND);
8509             pktOpts++;
8510         }
8511         else if (strcasecmp(opts[0], PPM_OPT__PKT_LOG) == 0)
8512         {
8513             if (num_opts == 1)
8514             {
8515                 ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8516             }
8517             else
8518             {
8519                 int k;
8520 
8521                 for (k = 1; k < num_opts; k++)
8522                 {
8523                     if (strcasecmp(opts[k], PPM_OPT__ALERT) == 0)
8524                     {
8525                         ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_ALERT);
8526                     }
8527                     else if (strcasecmp(opts[k], PPM_OPT__LOG) == 0)
8528                     {
8529                         ppm_set_pkt_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8530                     }
8531                     else
8532                     {
8533                         ParseError("config ppm: Invalid %s arg '%s'.", opts[0], opts[k]);
8534                     }
8535                 }
8536             }
8537             pktOpts++;
8538         }
8539         else if (strcasecmp(opts[0], PPM_OPT__RULE_LOG) == 0)
8540         {
8541             int k;
8542 
8543             if (num_opts == 1)
8544             {
8545                 ParseError("config ppm: insufficient %s opts.", opts[0]);
8546             }
8547 
8548             for (k = 1; k < num_opts; k++)
8549             {
8550                 if (strcasecmp(opts[k], PPM_OPT__ALERT) == 0)
8551                 {
8552                     ppm_set_rule_log(&sc->ppm_cfg, PPM_LOG_ALERT);
8553                 }
8554                 else if (strcasecmp(opts[k], PPM_OPT__LOG) == 0)
8555                 {
8556                     ppm_set_rule_log(&sc->ppm_cfg, PPM_LOG_MESSAGE);
8557                 }
8558                 else
8559                 {
8560                     ParseError("config ppm: Invalid %s arg '%s'.", opts[0], opts[k]);
8561                 }
8562             }
8563 
8564             ruleOpts++;
8565         }
8566 #ifdef DEBUG
8567         else if (strcasecmp(opts[0], PPM_OPT__DEBUG_PKTS) == 0)
8568         {
8569             if (num_opts != 1)
8570             {
8571                 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8572             }
8573 
8574             ppm_set_debug_pkts(&sc->ppm_cfg, 1);
8575             pktOpts++;
8576         }
8577 #if 0
8578         else if(!strcasecmp(opts[0], "debug-rules"))
8579         {
8580             if( 1 != num_opts )
8581                 ParseError("config ppm: too many arguments for '%s'.", opts[0]);
8582             ppm_set_debug_rules(1);
8583         }
8584 #endif
8585 #endif
8586         else
8587         {
8588             ParseError("'%s' is an invalid option to the 'config ppm:' "
8589                        "configuration.", opts[0]);
8590         }
8591 
8592         mSplitFree(&opts, num_opts);
8593     }
8594 
8595     mSplitFree(&toks, num_toks);
8596 }
8597 #endif
8598 
ConfigProcessAllEvents(SnortConfig * sc,char * args)8599 void ConfigProcessAllEvents(SnortConfig *sc, char *args)
8600 {
8601     if (sc == NULL)
8602         return;
8603 
8604     sc->run_flags |= RUN_FLAG__PROCESS_ALL_EVENTS;
8605 }
8606 
8607 #ifdef PERF_PROFILING
8608 /* Profiling configurations are done later after log directory has
8609  * absolutely been set */
_ConfigProfilePreprocs(SnortConfig * sc,char * args)8610 static void _ConfigProfilePreprocs(SnortConfig *sc, char *args)
8611 {
8612     return;
8613 }
8614 
ConfigProfilePreprocs(SnortConfig * sc,char * args)8615 void ConfigProfilePreprocs(SnortConfig *sc, char *args)
8616 {
8617     char **toks;
8618     int num_toks;
8619     int i;
8620 
8621     if (sc == NULL)
8622         return;
8623 
8624     LogMessage("Found profile_preprocs config directive (%s)\n",
8625                args == NULL ? "<no args>" : args);
8626 
8627     /* Initialize the defaults */
8628     sc->profile_preprocs.num = -1;
8629     sc->profile_preprocs.sort = PROFILE_SORT_AVG_TICKS;
8630 
8631     toks = mSplit(args, ",", 0, &num_toks, 0);
8632 
8633     if (num_toks > 3)
8634     {
8635         ParseError("profile_preprocs speciified with invalid options (%s)", args);
8636     }
8637 
8638     for (i = 0; i < num_toks; i++)
8639     {
8640         char **opts;
8641         int num_opts;
8642         int opt_filename = 0;
8643         char *endptr;
8644 
8645         opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8646         if (num_opts > 0)
8647         {
8648             opt_filename = strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0;
8649         }
8650 
8651         if ((!opt_filename && (num_opts != 2)) ||
8652             (opt_filename && ((num_opts > 3) || (num_opts < 2))))
8653         {
8654             ParseError("profile_preprocs has an invalid option (%s)", toks[i]);
8655         }
8656 
8657         if (strcasecmp(opts[0], PROFILE_OPT__PRINT) == 0)
8658         {
8659             if (strcasecmp(opts[1], PROFILE_OPT__ALL) == 0)
8660             {
8661                 sc->profile_preprocs.num = -1;
8662             }
8663             else
8664             {
8665                 sc->profile_preprocs.num = SnortStrtol(opts[1], &endptr, 10);
8666                 if ((errno == ERANGE) || (*endptr != '\0'))
8667                 {
8668                     ParseError("Invalid argument to profile_preprocs 'print' "
8669                                "configuration: %s", opts[1]);
8670                 }
8671             }
8672         }
8673         else if (strcasecmp(opts[0], PROFILE_OPT__SORT) == 0)
8674         {
8675             if (strcasecmp(opts[1], PROFILE_OPT__CHECKS) == 0)
8676             {
8677                 sc->profile_preprocs.sort = PROFILE_SORT_CHECKS;
8678             }
8679             else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS) == 0)
8680             {
8681                 sc->profile_preprocs.sort = PROFILE_SORT_AVG_TICKS;
8682             }
8683             else if (strcasecmp(opts[1], PROFILE_OPT__TOTAL_TICKS) == 0)
8684             {
8685                 sc->profile_preprocs.sort = PROFILE_SORT_TOTAL_TICKS;
8686             }
8687             else
8688             {
8689                 ParseError("profile_preprocs has an invalid sort option (%s)", toks[i]);
8690             }
8691         }
8692         else if (strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0)
8693         {
8694             sc->profile_preprocs.filename = ProcessFileOption(sc, opts[1]);
8695             if (opts[2] && (strcasecmp(opts[2], PROFILE_OPT__APPEND) == 0))
8696             {
8697                 sc->profile_preprocs.append = 1;
8698             }
8699             else
8700             {
8701                 sc->profile_preprocs.append = 0;
8702             }
8703         }
8704         else
8705         {
8706             ParseError("profile_preprocs has an invalid option (%s)", toks[i]);
8707         }
8708 
8709         mSplitFree(&opts, num_opts);
8710     }
8711 
8712     mSplitFree(&toks, num_toks);
8713 }
8714 
_ConfigProfileRules(SnortConfig * sc,char * args)8715 static void _ConfigProfileRules(SnortConfig *sc, char *args)
8716 {
8717     return;
8718 }
8719 
ConfigProfileRules(SnortConfig * sc,char * args)8720 void ConfigProfileRules(SnortConfig *sc, char *args)
8721 {
8722     char **toks;
8723     int num_toks;
8724     int i;
8725 
8726     if (sc == NULL)
8727         return;
8728 
8729     LogMessage("Found profile_rules config directive (%s)\n",
8730                args == NULL ? "<no args>" : args);
8731 
8732     /* Initialize the defaults */
8733     sc->profile_rules.num = -1;
8734     sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS;
8735 
8736     toks = mSplit(args, ",", 0, &num_toks, 0);
8737 
8738     if (num_toks > 3)
8739     {
8740         ParseError("profile_rules speciified with invalid options (%s)", args);
8741     }
8742 
8743     for (i = 0; i < num_toks;i++)
8744     {
8745         char **opts;
8746         int num_opts;
8747         int opt_filename = 0;
8748         char *endptr;
8749 
8750         opts = mSplit(toks[i], " \t", 0, &num_opts, 0);
8751         if (num_opts > 0)
8752         {
8753             opt_filename = strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0;
8754         }
8755 
8756         if ((!opt_filename && (num_opts != 2)) ||
8757             (opt_filename && ((num_opts > 3) || (num_opts < 2))))
8758         {
8759             ParseError("profile_rules has an invalid option (%s)", toks[i]);
8760         }
8761 
8762         if (strcasecmp(opts[0], PROFILE_OPT__PRINT) == 0)
8763         {
8764             if (strcasecmp(opts[1], PROFILE_OPT__ALL) == 0)
8765             {
8766                 sc->profile_rules.num = -1;
8767             }
8768             else
8769             {
8770                 sc->profile_rules.num = SnortStrtol(opts[1], &endptr, 10);
8771                 if ((errno == ERANGE) || (*endptr != '\0'))
8772                 {
8773                     ParseError("Invalid argument to profile_rules 'print' "
8774                                "configuration: %s", opts[1]);
8775                 }
8776             }
8777         }
8778         else if (strcasecmp(opts[0], PROFILE_OPT__SORT) == 0)
8779         {
8780             if (strcasecmp(opts[1], PROFILE_OPT__CHECKS) == 0)
8781             {
8782                 sc->profile_rules.sort = PROFILE_SORT_CHECKS;
8783             }
8784             else if (strcasecmp(opts[1], PROFILE_OPT__MATCHES) == 0)
8785             {
8786                 sc->profile_rules.sort = PROFILE_SORT_MATCHES;
8787             }
8788             else if (strcasecmp(opts[1], PROFILE_OPT__NO_MATCHES) == 0)
8789             {
8790                 sc->profile_rules.sort = PROFILE_SORT_NOMATCHES;
8791             }
8792             else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS) == 0)
8793             {
8794                 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS;
8795             }
8796             else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS_PER_MATCH) == 0)
8797             {
8798                 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS_PER_MATCH;
8799             }
8800             else if (strcasecmp(opts[1], PROFILE_OPT__AVG_TICKS_PER_NO_MATCH) == 0)
8801             {
8802                 sc->profile_rules.sort = PROFILE_SORT_AVG_TICKS_PER_NOMATCH;
8803             }
8804             else if (strcasecmp(opts[1], PROFILE_OPT__TOTAL_TICKS) == 0)
8805             {
8806                 sc->profile_rules.sort = PROFILE_SORT_TOTAL_TICKS;
8807             }
8808             else
8809             {
8810                 ParseError("profile_rules has an invalid sort option (%s)", toks[i]);
8811             }
8812         }
8813         else if (strcasecmp(opts[0], PROFILE_OPT__FILENAME) == 0)
8814         {
8815             sc->profile_rules.filename = ProcessFileOption(sc, opts[1]);
8816             if (opts[2] && (strcasecmp(opts[2], PROFILE_OPT__APPEND) == 0))
8817             {
8818                 sc->profile_rules.append = 1;
8819             }
8820             else
8821             {
8822                 sc->profile_rules.append = 0;
8823             }
8824         }
8825         else
8826         {
8827             ParseError("profile_rules has an invalid option (%s)", toks[i]);
8828         }
8829 
8830         mSplitFree(&opts, num_opts);
8831     }
8832 
8833     mSplitFree(&toks, num_toks);
8834 }
8835 #endif
8836 
ConfigQuiet(SnortConfig * sc,char * args)8837 void ConfigQuiet(SnortConfig *sc, char *args)
8838 {
8839     if (sc == NULL)
8840         return;
8841 
8842     sc->logging_flags |= LOGGING_FLAG__QUIET;
8843     sc->internal_log_level = INTERNAL_LOG_LEVEL__ERROR;
8844 }
8845 
8846 /*
8847  * Process the 'config rate_filter: memcap <#bytes>'
8848  */
8849 // TBD refactor - was cloned from sfthreshold.c
ConfigRateFilter(SnortConfig * sc,char * args)8850 void ConfigRateFilter(SnortConfig *sc, char *args)
8851 {
8852     char **toks;
8853     int num_toks;
8854 
8855     if ((sc == NULL) || (args == NULL))
8856         return;
8857 
8858     toks = mSplit(args, " \t", 2, &num_toks, 0);
8859     if (num_toks != 2)
8860     {
8861         ParseError("Rate filter memcap requires a positive integer argument.");
8862     }
8863 
8864     if (strcasecmp(toks[0], "memcap") == 0)
8865     {
8866         char *endptr;
8867 
8868         sc->rate_filter_config->memcap = SnortStrtol(toks[1], &endptr, 0);
8869         if ((errno == ERANGE) || (*endptr != '\0') ||
8870             (sc->rate_filter_config->memcap < 0))
8871         {
8872             ParseError("Invalid rate filter memcap: %s.  Must be a "
8873                        "positive integer.", toks[1]);
8874         }
8875     }
8876     else
8877     {
8878         ParseError("Unknown argument to rate filter configuration: %s.", toks[0]);
8879     }
8880 
8881     mSplitFree(&toks, num_toks);
8882 }
8883 
ConfigReference(SnortConfig * sc,char * args)8884 void ConfigReference(SnortConfig *sc, char *args)
8885 {
8886     char **toks;
8887     int num_toks;
8888     char *url = NULL;
8889 
8890     if ((sc == NULL) || (args == NULL))
8891         return;
8892 
8893     /* 2 tokens: name <url> */
8894     toks = mSplit(args, " \t", 0, &num_toks, 0);
8895     if (num_toks > 2)
8896     {
8897         ParseError("Reference config requires at most two arguments: "
8898                    "\"name [<url>]\".");
8899     }
8900 
8901     if (num_toks == 2)
8902         url = toks[1];
8903 
8904     ReferenceSystemAdd(&sc->references, toks[0], url);
8905 
8906     mSplitFree(&toks, num_toks);
8907 }
8908 
8909 /*
8910  * Function: ConfigReferenceNet
8911  *
8912  * Purpose: Translate the command line character string into its equivalent
8913  *          32-bit network byte ordered value (with netmask)
8914  *
8915  * Arguments: args => The address/CIDR block
8916  *
8917  * Returns: void function
8918  */
ConfigReferenceNet(SnortConfig * sc,char * args)8919 void ConfigReferenceNet(SnortConfig *sc, char *args)
8920 {
8921 
8922     if ((sc == NULL) || (args == NULL))
8923         return;
8924 
8925     sfip_pton(args, &sc->homenet);
8926 }
8927 
ConfigSetGid(SnortConfig * sc,char * args)8928 void ConfigSetGid(SnortConfig *sc, char *args)
8929 {
8930 #ifdef WIN32
8931     ParseError("Setting the group id is not supported in the "
8932                "WIN32 port of snort!");
8933 #else
8934     size_t i;
8935     char *endptr;
8936 
8937     if ((sc == NULL) || (args == NULL))
8938         return;
8939 
8940     for (i = 0; i < strlen(args); i++)
8941     {
8942         /* If we get something other than a digit, assume it's
8943          * a group name */
8944         if (!isdigit((int)args[i]))
8945         {
8946             struct group *gr = getgrnam(args);
8947 
8948             if (gr == NULL)
8949                 ParseError("Group \"%s\" unknown.", args);
8950 
8951             sc->group_id = gr->gr_gid;
8952             break;
8953         }
8954     }
8955 
8956     /* It's all digits.  Assume it's a group id */
8957     if (i == strlen(args))
8958     {
8959         sc->group_id = SnortStrtol(args, &endptr, 10);
8960         if ((errno == ERANGE) || (*endptr != '\0') ||
8961             (sc->group_id < 0))
8962         {
8963             ParseError("Group id \"%s\" out of range.", args);
8964         }
8965     }
8966 #endif
8967 }
8968 
ConfigSetUid(SnortConfig * sc,char * args)8969 void ConfigSetUid(SnortConfig *sc, char *args)
8970 {
8971 #ifdef WIN32
8972     ParseError("Setting the user id is not supported in the "
8973                "WIN32 port of snort!");
8974 #else
8975     size_t i;
8976     char *endptr;
8977 
8978     if ((sc == NULL) || (args == NULL))
8979         return;
8980 
8981     for (i = 0; i < strlen(args); i++)
8982     {
8983         /* If we get something other than a digit, assume it's
8984          * a user name */
8985         if (!isdigit((int)args[i]))
8986         {
8987             struct passwd *pw = getpwnam(args);
8988 
8989             if (pw == NULL)
8990                 ParseError("User \"%s\" unknown.", args);
8991 
8992             sc->user_id = (int)pw->pw_uid;
8993 
8994             /* Why would someone want to run as another user
8995              * but still as root group? */
8996             if (sc->group_id == -1)
8997                 sc->group_id = (int)pw->pw_gid;
8998 
8999             break;
9000         }
9001     }
9002 
9003     /* It's all digits.  Assume it's a user id */
9004     if (i == strlen(args))
9005     {
9006         sc->user_id = SnortStrtol(args, &endptr, 10);
9007         if ((errno == ERANGE) || (*endptr != '\0'))
9008             ParseError("User id \"%s\" out of range.", args);
9009 
9010         /* Set group id to user's default group if not
9011          * already set */
9012         if (sc->group_id == -1)
9013         {
9014             struct passwd *pw = getpwuid((uid_t)sc->user_id);
9015 
9016             if (pw == NULL)
9017                 ParseError("User \"%s\" unknown.", args);
9018 
9019             sc->group_id = (int)pw->pw_gid;
9020         }
9021     }
9022 
9023     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "UserID: %d GroupID: %d.\n",
9024                             sc->user_id, sc->group_id););
9025 #endif  /* !WIN32 */
9026 }
9027 
ConfigShowYear(SnortConfig * sc,char * args)9028 void ConfigShowYear(SnortConfig *sc, char *args)
9029 {
9030     if (sc == NULL)
9031         return;
9032 
9033     sc->output_flags |= OUTPUT_FLAG__INCLUDE_YEAR;
9034     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabled year in timestamp\n"););
9035 }
9036 
ConfigSoRuleMemcap(SnortConfig * sc,char * args)9037 void ConfigSoRuleMemcap(SnortConfig *sc, char *args)
9038 {
9039     char *endptr;
9040 
9041     if ((sc == NULL) || (args == NULL))
9042         return;
9043 
9044     sc->so_rule_memcap = SnortStrtoul(args, &endptr, 0);
9045     if ((errno == ERANGE) || (*endptr != '\0'))
9046     {
9047         ParseError("Invalid so rule memcap: %s.  Memcap must be between "
9048                    "0 and %u inclusive.", args, UINT32_MAX);
9049     }
9050 }
9051 
ConfigStateful(SnortConfig * sc,char * args)9052 void ConfigStateful(SnortConfig *sc, char *args)
9053 {
9054     if (sc == NULL)
9055         return;
9056 
9057     /* If stream5 is configured, the STATEFUL flag is set.  This is
9058      * somewhat misnamed and is used to assure a session is established */
9059     sc->run_flags |= RUN_FLAG__ASSURE_EST;
9060 }
9061 
ConfigTaggedPacketLimit(SnortConfig * sc,char * args)9062 void ConfigTaggedPacketLimit(SnortConfig *sc, char *args)
9063 {
9064     char *endptr;
9065 
9066     if ((sc == NULL) || (args == NULL))
9067         return;
9068 
9069     sc->tagged_packet_limit = SnortStrtol(args, &endptr, 0);
9070     if ((errno == ERANGE) || (*endptr != '\0') ||
9071         (sc->tagged_packet_limit < 0))
9072     {
9073         ParseError("Invalid tagged_packet_limit: %s.  Must be a "
9074                    "positive integer.", args);
9075     }
9076 }
9077 
9078 /*
9079    Process the 'config threshold: memcap #bytes, option2-name option2-value, ...'
9080 
9081    config threshold: memcap #bytes
9082 */
ConfigThreshold(SnortConfig * sc,char * args)9083 void ConfigThreshold(SnortConfig *sc, char *args)
9084 {
9085     static int warned = 0;
9086 
9087     if (!warned)
9088     {
9089         ParseWarning("config threshold is deprecated;"
9090                    " use config event_filter instead.\n");
9091 
9092         warned = 1;
9093     }
9094 
9095     ConfigEventFilter(sc, args);
9096 }
9097 
ConfigTreatDropAsAlert(SnortConfig * sc,char * args)9098 void ConfigTreatDropAsAlert(SnortConfig *sc, char *args)
9099 {
9100     if (sc == NULL)
9101         return;
9102 
9103     sc->run_flags |= RUN_FLAG__TREAT_DROP_AS_ALERT;
9104 }
9105 
ConfigTreatDropAsIgnore(SnortConfig * sc,char * args)9106 void ConfigTreatDropAsIgnore(SnortConfig *sc, char *args)
9107 {
9108     if (sc == NULL)
9109         return;
9110 
9111     sc->run_flags |= RUN_FLAG__TREAT_DROP_AS_IGNORE;
9112 }
9113 
ConfigUmask(SnortConfig * sc,char * args)9114 void ConfigUmask(SnortConfig *sc, char *args)
9115 {
9116 #ifdef WIN32
9117     ParseError("Setting the umask is not supported in the "
9118                "WIN32 port of snort!");
9119 #else
9120     char *endptr;
9121     long mask;
9122 
9123     if ((sc == NULL) || (args == NULL))
9124         return;
9125 
9126     mask = SnortStrtol(args, &endptr, 0);
9127 
9128     if ((errno == ERANGE) || (*endptr != '\0') ||
9129         (mask < 0) || (mask & ~FILEACCESSBITS))
9130     {
9131         ParseError("Bad umask: %s", args);
9132     }
9133     sc->file_mask = (mode_t)mask;
9134 #endif
9135 }
9136 
ConfigUtc(SnortConfig * sc,char * args)9137 void ConfigUtc(SnortConfig *sc, char *args)
9138 {
9139     if (sc == NULL)
9140         return;
9141 
9142     sc->output_flags |= OUTPUT_FLAG__USE_UTC;
9143 }
9144 
ConfigVerbose(SnortConfig * sc,char * args)9145 void ConfigVerbose(SnortConfig *sc, char *args)
9146 {
9147     if (sc == NULL)
9148         return;
9149 
9150     sc->logging_flags |= LOGGING_FLAG__VERBOSE;
9151     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Verbose Flag active\n"););
9152 }
9153 
ConfigVlanAgnostic(SnortConfig * sc,char * args)9154 void ConfigVlanAgnostic(SnortConfig *sc, char *args)
9155 {
9156     if (sc == NULL)
9157         return;
9158 
9159     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "VLAN Agnostic active\n"););
9160     sc->vlan_agnostic = 1; /* TODO: add this to some existing flag bitfield? */
9161 }
9162 
ConfigAddressSpaceAgnostic(SnortConfig * sc,char * args)9163 void ConfigAddressSpaceAgnostic(SnortConfig *sc, char *args)
9164 {
9165     if (sc == NULL)
9166         return;
9167 
9168     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Address Space Agnostic active\n"););
9169     sc->addressspace_agnostic = 1; /* TODO: add this to some existing flag bitfield? */
9170 }
9171 
ConfigLogIPv6Extra(SnortConfig * sc,char * args)9172 void ConfigLogIPv6Extra(SnortConfig *sc, char *args)
9173 {
9174     if (sc == NULL)
9175         return;
9176 
9177     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "LOG IPV6 EXTRA DATA active\n"););
9178     sc->log_ipv6_extra = 1; /* TODO: add this to some existing flag bitfield? */
9179 }
9180 
ConfigDumpDynamicRulesPath(SnortConfig * sc,char * args)9181 void ConfigDumpDynamicRulesPath(SnortConfig *sc, char *args)
9182 {
9183     if (sc == NULL)
9184         return;
9185     sc->run_mode_flags |= RUN_MODE_FLAG__RULE_DUMP;
9186     if ( args != NULL )
9187         sc->dynamic_rules_path = SnortStrdup(args);
9188 }
9189 
ConfigControlSocketDirectory(SnortConfig * sc,char * args)9190 void ConfigControlSocketDirectory(SnortConfig *sc, char *args)
9191 {
9192     if (sc == NULL)
9193         return;
9194     if ( args != NULL )
9195         sc->cs_dir = SnortStrdup(args);
9196 }
9197 
ConfigFile(SnortConfig * sc,char * args)9198 void ConfigFile(SnortConfig *sc, char *args)
9199 {
9200     if (sc == NULL)
9201         return;
9202     if ( args != NULL )
9203     {
9204         if (!sc->file_config)
9205             sc->file_config = file_service_config_create();
9206         file_service_config(sc, args, sc->file_config);
9207     }
9208 }
9209 
ConfigTunnelVerdicts(SnortConfig * sc,char * args)9210 void ConfigTunnelVerdicts ( SnortConfig *sc, char *args )
9211 {
9212     char* tmp, *tok;
9213 
9214     if (sc == NULL)
9215         return;
9216 
9217     tmp = SnortStrdup(args);
9218     tok = strtok(tmp, " ,");
9219 
9220     while ( tok )
9221     {
9222         if ( !strcasecmp(tok, "gtp") )
9223             sc->tunnel_mask |= TUNNEL_GTP;
9224 
9225         else if ( !strcasecmp(tok, "teredo") )
9226             sc->tunnel_mask |= TUNNEL_TEREDO;
9227 
9228         else if ( !strcasecmp(tok, "gre") )
9229             sc->tunnel_mask |= TUNNEL_GRE;
9230 
9231         else if ( !strcasecmp(tok, "6in4") )
9232             sc->tunnel_mask |= TUNNEL_6IN4;
9233 
9234         else if ( !strcasecmp(tok, "4in6") )
9235             sc->tunnel_mask |= TUNNEL_4IN6;
9236 
9237         else if ( !strcasecmp(tok, "4in4") )
9238             sc->tunnel_mask |= TUNNEL_4IN4;
9239 
9240         else if ( !strcasecmp(tok, "6in6") )
9241             sc->tunnel_mask |= TUNNEL_6IN6;
9242 
9243         else if ( !strcasecmp(tok, "mpls") )
9244             sc->tunnel_mask |= TUNNEL_MPLS;
9245 
9246         else
9247             ParseError("Unknown tunnel bypass protocol");
9248 
9249         tok = strtok(NULL, " ,");
9250     }
9251     free(tmp);
9252 }
9253 
9254 #ifdef SIDE_CHANNEL
ConfigSideChannel(SnortConfig * sc,char * args)9255 static void ConfigSideChannel(SnortConfig *sc, char *args)
9256 {
9257     if (sc == NULL)
9258         return;
9259     sc->side_channel_config.enabled = true;
9260     if (args != NULL)
9261         sc->side_channel_config.opts = SnortStrdup(args);
9262 }
9263 #endif
9264 
ConfigMaxIP6Extensions(SnortConfig * sc,char * args)9265 void ConfigMaxIP6Extensions(SnortConfig *sc, char *args)
9266 {
9267     char *endptr;
9268     unsigned long parsed_value;
9269 
9270     if ((sc == NULL) || (args == NULL))
9271         return;
9272 
9273     parsed_value = SnortStrtoul(args, &endptr, 0);
9274 
9275     if ((*endptr != '\0') || (parsed_value > UINT8_MAX))
9276     {
9277         ParseError("Max IP6 extension count must be a value between 0 and %d (inclusive), not: '%s'.", UINT8_MAX, args);
9278     }
9279 
9280     sc->max_ip6_extensions = (uint8_t) parsed_value;
9281 }
9282 
ConfigDisableReplace(SnortConfig * sc,char * args)9283 void ConfigDisableReplace(SnortConfig *sc, char *args)
9284 {
9285     if(sc == NULL)
9286         return;
9287     sc->disable_replace_opt = 1;
9288 }
9289 
9290 #ifdef DUMP_BUFFER
ConfigBufferDump(SnortConfig * sc,char * args)9291 void ConfigBufferDump(SnortConfig *sc, char *args)
9292 {
9293     if ( !sc )
9294         return;
9295 
9296     sc->no_log = 0;
9297 
9298     if (!args)
9299         return;
9300 
9301     if ( !sc->buffer_dump_file )
9302     {
9303         sc->buffer_dump_file = StringVector_New();
9304 
9305         if ( !sc->buffer_dump_file )
9306             ParseError("can't allocate memory for buffer_dump_file '%s'.", args);
9307     }
9308     if ( !StringVector_Add(sc->buffer_dump_file, args) )
9309         ParseError("can't allocate memory for buffer_dump '%s'.", args);
9310 }
9311 #endif
9312 
9313 /****************************************************************************
9314  *
9315  * Function: ParseRule()
9316  *
9317  * Purpose:  Process an individual rule and add it to the rule list
9318  *
9319  * Arguments: rule => rule string
9320  *
9321  * Returns: void function
9322  *
9323  ***************************************************************************/
ParseRule(SnortConfig * sc,SnortPolicy * p,char * args,RuleType rule_type,ListHead * list)9324 static void ParseRule(SnortConfig *sc, SnortPolicy *p, char *args,
9325                       RuleType rule_type, ListHead *list)
9326 {
9327     char **toks = NULL;
9328     int num_toks = 0;
9329     int protocol = 0;
9330     RuleTreeNode test_rtn;
9331     RuleTreeNode *rtn;
9332     OptTreeNode *otn;
9333     char *roptions = NULL;
9334     port_entry_t pe;
9335     PortVarTable *portVarTable = p->portVarTable;
9336     PortTable *nonamePortVarTable = p->nonamePortVarTable;
9337 
9338     if ((sc == NULL) || (args == NULL))
9339       return;
9340 
9341     memset(&test_rtn, 0, sizeof(RuleTreeNode));
9342 
9343     memset(&pe, 0, sizeof(pe));
9344 
9345     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"[*] Rule start\n"););
9346 
9347     /* We have a preproc or decoder rule - we assume a header of 'tcp any any -> any any ' */
9348     if (*args == '(')
9349     {
9350         test_rtn.flags |= ANY_DST_PORT;
9351         test_rtn.flags |= ANY_SRC_PORT;
9352         test_rtn.flags |= ANY_DST_IP;
9353         test_rtn.flags |= ANY_SRC_IP;
9354         test_rtn.flags |= BIDIRECTIONAL;
9355         test_rtn.type = rule_type;
9356         protocol = IPPROTO_TCP;
9357 
9358         roptions = args;
9359 
9360         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Preprocessor Rule detected\n"););
9361     }
9362     else
9363     {
9364         /* proto ip port dir ip port r*/
9365         toks = mSplit(args, " \t", 7, &num_toks, '\\');
9366 
9367         /* A rule might not have rule options */
9368         if (num_toks < 6)
9369         {
9370             ParseError("Bad rule in rules file: %s", args);
9371         }
9372 
9373         if (num_toks == 7)
9374             roptions = toks[6];
9375 
9376         test_rtn.type = rule_type;
9377 
9378         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Non-Preprocessor Rule detected\n"););
9379 
9380         /* Set the rule protocol - fatal errors if protocol not found */
9381         protocol = GetRuleProtocol(toks[0]);
9382         test_rtn.proto = protocol;
9383 
9384         switch (protocol)
9385         {
9386             case IPPROTO_TCP:
9387                 sc->ip_proto_array[IPPROTO_TCP] = 1;
9388                 break;
9389             case IPPROTO_UDP:
9390                 sc->ip_proto_array[IPPROTO_UDP] = 1;
9391                 break;
9392             case IPPROTO_ICMP:
9393                 sc->ip_proto_array[IPPROTO_ICMP] = 1;
9394                 sc->ip_proto_array[IPPROTO_ICMPV6] = 1;
9395                 break;
9396             case ETHERNET_TYPE_IP:
9397                 /* This will be set via ip_protos */
9398                 break;
9399             default:
9400                 ParseError("Bad protocol: %s", toks[0]);
9401                 break;
9402         }
9403 
9404 
9405         /* Process the IP address and CIDR netmask - changed version 1.2.1
9406          * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
9407          * applied instead of checking the flag if we see a "!<ip number>" we
9408          * need to set a flag so that we can properly deal with it when we are
9409          * processing packets. */
9410         ProcessIP(sc, toks[1], &test_rtn, SRC, 0);
9411 
9412         /* Check to make sure that the user entered port numbers.
9413          * Sometimes they forget/don't know that ICMP rules need them */
9414         if ((strcasecmp(toks[2], RULE_DIR_OPT__DIRECTIONAL) == 0) ||
9415             (strcasecmp(toks[2], RULE_DIR_OPT__BIDIRECTIONAL) == 0))
9416         {
9417             ParseError("Port value missing in rule!");
9418         }
9419 
9420         DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Src-Port: %s\n",toks[2]););
9421 
9422         if (ParsePortList(&test_rtn, portVarTable, nonamePortVarTable,
9423                           toks[2], protocol, 0 /* =src port */ ))
9424         {
9425             ParseError("Bad source port: '%s'", toks[2]);
9426         }
9427 
9428         /* changed version 1.8.4
9429          * Die when someone has tried to define a rule character other
9430          * than -> or <> */
9431         if ((strcmp(toks[3], RULE_DIR_OPT__DIRECTIONAL) != 0) &&
9432             (strcmp(toks[3], RULE_DIR_OPT__BIDIRECTIONAL) != 0))
9433         {
9434             ParseError("Illegal direction specifier: %s", toks[3]);
9435         }
9436 
9437         /* New in version 1.3: support for bidirectional rules
9438          * This checks the rule "direction" token and sets the bidirectional
9439          * flag if the token = '<>' */
9440         if (strcmp(toks[3], RULE_DIR_OPT__BIDIRECTIONAL) == 0)
9441         {
9442             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Bidirectional rule!\n"););
9443             test_rtn.flags |= BIDIRECTIONAL;
9444         }
9445 
9446         /* changed version 1.2.1
9447          * "any" IP's are now set to addr 0, netmask 0, and the normal rules are
9448          * applied instead of checking the flag
9449          * If we see a "!<ip number>" we need to set a flag so that we can
9450          * properly deal with it when we are processing packets */
9451         ProcessIP(sc, toks[4], &test_rtn, DST, 0);
9452 
9453         DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Dst-Port: %s\n", toks[5]););
9454 
9455         if (ParsePortList(&test_rtn, portVarTable, nonamePortVarTable,
9456                           toks[5], protocol, 1 /* =dst port */ ))
9457         {
9458             ParseError("Bad destination port: '%s'", toks[5]);
9459         }
9460     }
9461 
9462     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"test_rtn.flags = 0x%X\n", test_rtn.flags););
9463     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Processing Head Node....\n"););
9464 
9465     test_rtn.listhead = list;
9466 
9467     rtn = ProcessHeadNode(sc, &test_rtn, list);
9468     /* The IPs in the test node get free'd in ProcessHeadNode if there is
9469      * already a matching RTN.  The portobjects will get free'd when the
9470      * port var table is free'd */
9471 
9472     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Parsing Rule Options...\n"););
9473 
9474     otn = ParseRuleOptions(sc, &rtn, roptions, rule_type, protocol);
9475     if (otn == NULL)
9476     {
9477         /* This otn is a dup and we're choosing to keep the old one */
9478         mSplitFree(&toks, num_toks);
9479         return;
9480     }
9481 
9482     rule_count++;
9483 
9484     /* Get rule option info */
9485     pe.gid = otn->sigInfo.generator;
9486     pe.sid = otn->sigInfo.id;
9487 
9488     /* Have to have at least 6 toks */
9489     if (num_toks != 0)
9490     {
9491         pe.protocol = SnortStrdup(toks[0]);
9492         pe.src_port = SnortStrdup(toks[2]);
9493         pe.dst_port = SnortStrdup(toks[5]);
9494     }
9495 
9496     /* See what kind of content is going in the fast pattern matcher */
9497     if (otn->ds_list[PLUGIN_DYNAMIC] != NULL)
9498     {
9499         DynamicData *dd = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
9500         if (dd->contentFlags & CONTENT_HTTP)
9501             pe.uricontent = 1;
9502         else if (dd->contentFlags & CONTENT_NORMAL)
9503             pe.content = 1;
9504     }
9505     else
9506     {
9507         /* Since http_cookie content is not used in fast pattern matcher,
9508          * need to iterate the entire list */
9509         if (otn->ds_list[PLUGIN_PATTERN_MATCH_URI] != NULL)
9510         {
9511             PatternMatchData *pmd = otn->ds_list[PLUGIN_PATTERN_MATCH_URI];
9512 
9513             for (; pmd != NULL; pmd = pmd->next)
9514             {
9515                 if ( IsHttpBufFpEligible(pmd->http_buffer) )
9516                 {
9517                     pe.uricontent = 1;
9518                     break;
9519                 }
9520             }
9521         }
9522 
9523         if (!pe.uricontent && ((otn->ds_list[PLUGIN_PATTERN_MATCH] != NULL)
9524                     || (otn->ds_list[PLUGIN_PATTERN_MATCH_OR] != NULL)))
9525         {
9526             pe.content = 1;
9527         }
9528     }
9529 
9530     if (rtn->flags & BIDIRECTIONAL)
9531          pe.dir = 1;
9532 
9533     pe.proto = protocol;
9534     pe.rule_type = rule_type;
9535 
9536     port_list_add_entry(&port_list, &pe);
9537 
9538     /*
9539      * The src/dst port parsing must be done before the Head Nodes are processed, since they must
9540      * compare the ports/port_objects to find the right rtn list to add the otn rule to.
9541      *
9542      * After otn processing we can finalize port object processing for this rule
9543      */
9544     if (FinishPortListRule(sc->port_tables, rtn, otn, protocol, &pe, sc->fast_pattern_config))
9545         ParseError("Failed to finish a port list rule.");
9546 
9547     mSplitFree(&toks, num_toks);
9548 }
9549 
9550 /****************************************************************************
9551  *
9552  * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int)
9553  *
9554  * Purpose:  Process the header block info and add to the block list if
9555  *           necessary
9556  *
9557  * Arguments: test_node => data generated by the rules parsers
9558  *            list => List Block Header refernece
9559  *            protocol => ip protocol
9560  *
9561  * Returns: void function
9562  *
9563  ***************************************************************************/
ProcessHeadNode(SnortConfig * sc,RuleTreeNode * test_node,ListHead * list)9564 static RuleTreeNode * ProcessHeadNode(SnortConfig *sc, RuleTreeNode *test_node,
9565                                       ListHead *list)
9566 {
9567     RuleTreeNode *rtn = findHeadNode(sc, test_node, getParserPolicy(sc));
9568 
9569     /* if it doesn't match any of the existing nodes, make a new node and
9570      * stick it at the end of the list */
9571     if (rtn == NULL)
9572     {
9573         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n"););
9574 
9575         rtn = (RuleTreeNode *)SnortAlloc(sizeof(RuleTreeNode));
9576 
9577         rtn->otnRefCount++;
9578 
9579         /* copy the prototype header info into the new header block */
9580         XferHeader(test_node, rtn);
9581 
9582         head_count++;
9583         rtn->head_node_number = head_count;
9584 
9585         /* initialize the function list for the new RTN */
9586         SetupRTNFuncList(rtn);
9587 
9588         /* add link to parent listhead */
9589         rtn->listhead = list;
9590 
9591         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
9592                 "New Chain head flags = 0x%X\n", rtn->flags););
9593     }
9594     else
9595     {
9596         rtn->otnRefCount++;
9597         FreeRuleTreeNode(test_node);
9598     }
9599 
9600     return rtn;
9601 }
9602 
9603 #if 0
9604 #ifdef DEBUG_MSGS
9605 static void PrintRtnPorts(RuleTreeNode *rtn_list)
9606 {
9607     int i = 0;
9608     char buf[STD_BUF];
9609 
9610     SnortSnprintf(buf, STD_BUF, "%s", "    ");
9611 
9612     while (rtn_list != NULL)
9613     {
9614         if (rtn_list->flags & EXCEPT_DST_PORT)
9615         {
9616             SnortSnprintfAppend(buf, STD_BUF, "!");
9617         }
9618 
9619         SnortSnprintfAppend(buf, STD_BUF, "%d ", rtn_list->ldp);
9620 
9621         rtn_list = rtn_list->right;
9622 
9623         if (i == 15)
9624         {
9625             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "%s\n", buf););
9626 
9627             i = 0;
9628 
9629             SnortSnprintf(buf, STD_BUF, "%s", "     ");
9630         }
9631 
9632         i++;
9633     }
9634 
9635     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "%s\n", buf););
9636 }
9637 #endif
9638 #endif
9639 
ParseAlert(SnortConfig * sc,SnortPolicy * p,char * args)9640 static void ParseAlert(SnortConfig *sc, SnortPolicy *p, char *args)
9641 {
9642     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Alert\n"););
9643     ParseRule(sc, p, args, RULE_TYPE__ALERT, &sc->Alert);
9644 }
9645 
ParseDrop(SnortConfig * sc,SnortPolicy * p,char * args)9646 static void ParseDrop(SnortConfig *sc, SnortPolicy *p, char *args)
9647 {
9648     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Drop\n"););
9649 
9650     /* Parse as an alert if we're treating drops as alerts */
9651     if (ScTreatDropAsAlertNewConf(sc))
9652         ParseRule(sc, p, args, RULE_TYPE__ALERT, &sc->Alert);
9653 
9654     else if ( ScKeepDropRules(sc) || ScLoadAsDropRules(sc) )
9655         ParseRule(sc, p, args, RULE_TYPE__DROP, &sc->Drop);
9656 }
9657 
ParseLog(SnortConfig * sc,SnortPolicy * p,char * args)9658 static void ParseLog(SnortConfig *sc, SnortPolicy *p, char *args)
9659 {
9660     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Log\n"););
9661     ParseRule(sc, p, args, RULE_TYPE__LOG, &sc->Log);
9662 }
9663 
ParsePass(SnortConfig * sc,SnortPolicy * p,char * args)9664 static void ParsePass(SnortConfig *sc, SnortPolicy *p, char *args)
9665 {
9666     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Pass\n"););
9667     ParseRule(sc, p, args, RULE_TYPE__PASS, &sc->Pass);
9668 }
9669 
ParseReject(SnortConfig * sc,SnortPolicy * p,char * args)9670 static void ParseReject(SnortConfig *sc, SnortPolicy *p, char *args)
9671 {
9672     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Reject\n"););
9673     ParseRule(sc, p, args, RULE_TYPE__REJECT, &sc->Reject);
9674 #ifdef ACTIVE_RESPONSE
9675     Active_SetEnabled(1);
9676 #endif
9677 }
9678 
ParseSdrop(SnortConfig * sc,SnortPolicy * p,char * args)9679 static void ParseSdrop(SnortConfig *sc, SnortPolicy *p, char *args)
9680 {
9681     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "SDrop\n"););
9682 
9683     if ( ScKeepDropRules(sc) && !ScTreatDropAsAlertNewConf(sc) )
9684         ParseRule(sc, p, args, RULE_TYPE__SDROP, &sc->SDrop);
9685 }
9686 
ParsePortVar(SnortConfig * sc,SnortPolicy * p,char * args)9687 static void ParsePortVar(SnortConfig *sc, SnortPolicy *p, char *args)
9688 {
9689     char **toks;
9690     int num_toks;
9691 
9692     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "PortVar\n"););
9693 
9694     toks = mSplit(args, " \t", 0, &num_toks, 0);
9695     if (num_toks != 2)
9696     {
9697         ParseError("Missing argument to %s", toks[0]);
9698     }
9699 
9700     /* Check command line variables to see if this has already
9701      * been defined */
9702     if (cmd_line_var_list != NULL)
9703     {
9704         VarNode *tmp = cmd_line_var_list;
9705 
9706         while (tmp != NULL)
9707         {
9708             /* Already defined this via command line */
9709             if (strcasecmp(toks[0], tmp->name) == 0)
9710             {
9711                 mSplitFree(&toks, num_toks);
9712                 return;
9713             }
9714 
9715             tmp = tmp->next;
9716         }
9717     }
9718 
9719     PortVarDefine(sc, toks[0], toks[1]);
9720 
9721     mSplitFree(&toks, num_toks);
9722 }
9723 
ParseIpVar(SnortConfig * sc,SnortPolicy * p,char * args)9724 static void ParseIpVar(SnortConfig *sc, SnortPolicy *p, char *args)
9725 {
9726     char **toks;
9727     int num_toks;
9728     int ret;
9729 
9730     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "IpVar\n"););
9731 
9732     toks = mSplit(args, " \t", 0, &num_toks, 0);
9733     if (num_toks != 2)
9734     {
9735         ParseError("Missing argument to %s", toks[0]);
9736     }
9737 
9738     /* Check command line variables to see if this has already
9739      * been defined */
9740     if (cmd_line_var_list != NULL)
9741     {
9742         VarNode *tmp = cmd_line_var_list;
9743 
9744         while (tmp != NULL)
9745         {
9746             /* Already defined this via command line */
9747             if (strcasecmp(toks[0], tmp->name) == 0)
9748             {
9749                 mSplitFree(&toks, num_toks);
9750                 return;
9751             }
9752 
9753             tmp = tmp->next;
9754         }
9755     }
9756 
9757     DisallowCrossTableDuplicateVars(sc, toks[0], VAR_TYPE__IPVAR);
9758 
9759     if((ret = sfvt_define(p->ip_vartable, toks[0], toks[1])) != SFIP_SUCCESS)
9760     {
9761         switch(ret) {
9762             case SFIP_ARG_ERR:
9763                 ParseError("The following is not allowed: %s.", toks[1]);
9764                 break;
9765 
9766             case SFIP_DUPLICATE:
9767                 ParseMessage("Var '%s' redefined.", toks[0]);
9768                 break;
9769 
9770             case SFIP_CONFLICT:
9771                 ParseError("Negated IP ranges that are more general than "
9772                         "non-negated ranges are not allowed. Consider "
9773                         "inverting the logic in %s.", toks[0]);
9774                 break;
9775 
9776             case SFIP_NOT_ANY:
9777                 ParseError("!any is not allowed in %s.", toks[0]);
9778                 break;
9779 
9780 	    case SFIP_INVALID_VAR:
9781 		ParseError("Variable name should contain minimum 1 alphabetic character."
9782 			   " Following variable name is not allowed: %s.", toks[0]);
9783 		break;
9784 
9785             default:
9786                 ParseError("Failed to parse the IP address: %s.", toks[1]);
9787         }
9788     }
9789 
9790     mSplitFree(&toks, num_toks);
9791 }
9792 
ParseVar(SnortConfig * sc,SnortPolicy * p,char * args)9793 static void ParseVar(SnortConfig *sc, SnortPolicy *p, char *args)
9794 {
9795     char **toks;
9796     int num_toks;
9797 
9798     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Variable\n"););
9799 
9800     toks = mSplit(args, " \t", 0, &num_toks, 0);
9801     if (num_toks != 2)
9802     {
9803         ParseError("Missing argument to %s", toks[0]);
9804     }
9805 
9806     /* Check command line variables to see if this has already
9807      * been defined */
9808     if (cmd_line_var_list != NULL)
9809     {
9810         VarNode *tmp = cmd_line_var_list;
9811 
9812         while (tmp != NULL)
9813         {
9814            // Already defined this via command line
9815             if (strcasecmp(toks[0], tmp->name) == 0)
9816             {
9817                 mSplitFree(&toks, num_toks);
9818                 return;
9819             }
9820 
9821             tmp = tmp->next;
9822         }
9823     }
9824 
9825     AddVarToTable(sc, toks[0], toks[1]);
9826     mSplitFree(&toks, num_toks);
9827 }
9828 
ParseFile(SnortConfig * sc,SnortPolicy * p,char * args)9829 static void ParseFile(SnortConfig *sc, SnortPolicy *p, char *args)
9830 {
9831     if (!sc->file_config)
9832         sc->file_config = file_service_config_create();
9833     file_rule_parse(args, sc->file_config);
9834 }
9835 
AddVarToTable(SnortConfig * sc,char * name,char * value)9836 static void AddVarToTable(SnortConfig *sc, char *name, char *value)
9837 {
9838     //TODO: snort.cfg and rules should use PortVar instead ...this allows compatability for now.
9839     if (strstr(name, "_PORT") || strstr(name, "PORT_"))
9840     {
9841         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"PortVar\n"););
9842         PortVarDefine(sc, name, value);
9843     }
9844     else
9845     {
9846         VarDefine(sc, name, value);
9847     }
9848 }
9849 
ParseThreshFilter(SnortConfig * sc,SnortPolicy * p,char * args,const char * ERR_KEY)9850 static void ParseThreshFilter(
9851     SnortConfig *sc, SnortPolicy *p, char *args, const char* ERR_KEY
9852 ) {
9853     char **toks;
9854     int num_toks;
9855     int count_flag = 0;
9856     int seconds_flag = 0;
9857     int type_flag = 0;
9858     int tracking_flag = 0;
9859     int genid_flag = 0;
9860     int sigid_flag = 0;
9861     int i;
9862     THDX_STRUCT thdx;
9863 
9864     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Event Filter\n"););
9865 
9866     memset(&thdx, 0, sizeof(THDX_STRUCT));
9867 
9868     toks = mSplit(args, ",", 0, &num_toks, 0);  /* get rule option pairs */
9869 
9870     for (i = 0; i < num_toks; i++)
9871     {
9872         char **pairs;
9873         int num_pairs;
9874 
9875         pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0);  /* get rule option pairs */
9876 
9877         if (num_pairs != 2)
9878         {
9879             ParseError(ERR_NOT_PAIRED);
9880         }
9881 
9882         if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
9883         {
9884             if ( count_flag++ )
9885             {
9886                 ParseError(ERR_EXTRA_OPTION);
9887             }
9888 
9889             thdx.count = xatol(pairs[1],"event_filter: count");
9890 
9891             if ((thdx.count < 1) && (thdx.count != THD_NO_THRESHOLD))
9892             {
9893                 ParseError("event_filter: count must be > 0 or %d\n",
9894                            THD_NO_THRESHOLD);
9895             }
9896         }
9897         else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
9898         {
9899             if ( seconds_flag++ )
9900             {
9901                 ParseError(ERR_EXTRA_OPTION);
9902             }
9903 
9904             thdx.seconds = xatoup(pairs[1],"event_filter: seconds");
9905         }
9906         else if (strcasecmp(pairs[0], THRESHOLD_OPT__TYPE) == 0)
9907         {
9908             if ( type_flag++ )
9909             {
9910                 ParseError(ERR_EXTRA_OPTION);
9911             }
9912 
9913             if (strcasecmp(pairs[1], THRESHOLD_TYPE__LIMIT) == 0)
9914             {
9915                 thdx.type = THD_TYPE_LIMIT;
9916             }
9917             else if (strcasecmp(pairs[1], THRESHOLD_TYPE__THRESHOLD) == 0)
9918             {
9919                 thdx.type = THD_TYPE_THRESHOLD;
9920             }
9921             else if (strcasecmp(pairs[1], THRESHOLD_TYPE__BOTH) == 0)
9922             {
9923                 thdx.type = THD_TYPE_BOTH;
9924             }
9925             else
9926             {
9927                 ParseError(ERR_BAD_VALUE);
9928             }
9929         }
9930         else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
9931         {
9932             if ( tracking_flag++ )
9933             {
9934                 ParseError(ERR_EXTRA_OPTION);
9935             }
9936 
9937             if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
9938             {
9939                 thdx.tracking = THD_TRK_SRC;
9940             }
9941             else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
9942             {
9943                 thdx.tracking = THD_TRK_DST;
9944             }
9945             else
9946             {
9947                 ParseError(ERR_BAD_VALUE);
9948             }
9949         }
9950         else if (strcasecmp(pairs[0], THRESHOLD_OPT__GID) == 0)
9951         {
9952             if ( genid_flag++ )
9953             {
9954                 ParseError(ERR_EXTRA_OPTION);
9955             }
9956 
9957             thdx.gen_id = xatou(pairs[1], "event_filter: gen_id");
9958         }
9959         else if (strcasecmp(pairs[0], THRESHOLD_OPT__SID) == 0)
9960         {
9961             if ( sigid_flag++ )
9962             {
9963                 ParseError(ERR_EXTRA_OPTION);
9964             }
9965 
9966             thdx.sig_id = xatou(pairs[1], "event_filter: sig_id");
9967         }
9968         else
9969         {
9970             ParseError(ERR_BAD_OPTION);
9971         }
9972 
9973         mSplitFree(&pairs, num_pairs);
9974     }
9975 
9976     if ((count_flag + tracking_flag + type_flag + seconds_flag + genid_flag
9977         + sigid_flag) != 6)
9978     {
9979         ParseError(ERR_BAD_ARG_COUNT);
9980     }
9981 
9982     if (sfthreshold_create(sc, sc->threshold_config, &thdx))
9983     {
9984         if (thdx.sig_id == 0)
9985         {
9986             ParseError(ERR_CREATE_EX, "only one per gen_id != 0");
9987         }
9988         else if (thdx.gen_id == 0)
9989         {
9990             ParseError(ERR_CREATE_EX, "gen_id = 0 requires sig_id = 0");
9991         }
9992         else
9993         {
9994             ParseError(ERR_CREATE_EX, "gen_id, sig_id must be unique");
9995         }
9996     }
9997 
9998     mSplitFree(&toks, num_toks);
9999 }
10000 
10001 /*
10002    threshold gen_id #, sig_id #, type limit|threshold|both, \
10003        track by_src|by_dst, count #, seconds #
10004 */
ParseThreshold(SnortConfig * sc,SnortPolicy * p,char * args)10005 static void ParseThreshold(SnortConfig *sc, SnortPolicy *p, char *args)
10006 {
10007     static int warned = 0;
10008 
10009     if (!warned)
10010     {
10011         ParseWarning("threshold (standalone) is deprecated; "
10012             "use event_filter instead.\n");
10013         warned = 1;
10014     }
10015 
10016     ParseThreshFilter(sc, p, args, "standalone threshold");
10017 }
10018 
ParseEventFilter(SnortConfig * sc,SnortPolicy * p,char * args)10019 static void ParseEventFilter(SnortConfig *sc, SnortPolicy *p, char *args)
10020 {
10021     ParseThreshFilter(sc, p, args, "event_filter");
10022 }
10023 
10024 /*
10025    suppress gen_id #, sig_id #, track by_src|by_dst, ip cidr'
10026 */
ParseSuppress(SnortConfig * sc,SnortPolicy * p,char * args)10027 static void ParseSuppress(SnortConfig *sc, SnortPolicy *p, char *args)
10028 {
10029     char **toks;
10030     int num_toks;
10031     int tracking_flag = 0;
10032     int genid_flag = 0;
10033     int sigid_flag = 0;
10034     int ip_flag = 0;
10035     int i;
10036     THDX_STRUCT thdx;
10037     const char* ERR_KEY = "suppress";
10038 
10039     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Suppress\n"););
10040 
10041     memset(&thdx, 0, sizeof(THDX_STRUCT));
10042 
10043     thdx.type = THD_TYPE_SUPPRESS;
10044     thdx.priority = THD_PRIORITY_SUPPRESS;
10045     thdx.tracking = THD_TRK_NONE;
10046 
10047     /* Potential IP list might be present so we can't split on commas
10048      * Change commas to semi-colons */
10049     args = FixSeparators(args, ';', "suppress");
10050     toks = mSplit(args, ";", 0, &num_toks, 0);  /* get rule option pairs */
10051 
10052     for (i = 0; i < num_toks; i++)
10053     {
10054         char **pairs;
10055         int num_pairs;
10056 
10057         pairs = mSplit(toks[i], " \t", 2, &num_pairs, 0);  /* get rule option pairs */
10058 
10059         if (num_pairs != 2)
10060         {
10061             ParseError(ERR_NOT_PAIRED);
10062         }
10063 
10064         if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
10065         {
10066             if ( tracking_flag++ )
10067             {
10068                 ParseError(ERR_EXTRA_OPTION);
10069             }
10070 
10071             if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
10072             {
10073                 thdx.tracking = THD_TRK_SRC;
10074             }
10075             else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
10076             {
10077                 thdx.tracking = THD_TRK_DST;
10078             }
10079             else
10080             {
10081                 ParseError(ERR_BAD_VALUE);
10082             }
10083         }
10084         else if (strcasecmp(pairs[0], THRESHOLD_OPT__GID) == 0)
10085         {
10086             if ( genid_flag++ )
10087             {
10088                 ParseError(ERR_EXTRA_OPTION);
10089             }
10090 
10091             thdx.gen_id = xatou(pairs[1], "suppress: gen_id");
10092         }
10093         else if (strcasecmp(pairs[0], THRESHOLD_OPT__SID) == 0)
10094         {
10095             if ( sigid_flag++ )
10096             {
10097                 ParseError(ERR_EXTRA_OPTION);
10098             }
10099 
10100             thdx.sig_id = xatou(pairs[1], "suppress: sig_id");
10101         }
10102         else if (strcasecmp(pairs[0], THRESHOLD_OPT__IP) == 0)
10103         {
10104             if ( ip_flag++ )
10105             {
10106                 ParseError(ERR_EXTRA_OPTION);
10107             }
10108 
10109             thdx.ip_address = IpAddrSetParse(sc, pairs[1]);
10110         }
10111         else
10112         {
10113             ParseError(ERR_BAD_OPTION);
10114         }
10115 
10116         mSplitFree(&pairs, num_pairs);
10117     }
10118 
10119     if (((genid_flag + sigid_flag) != 2) ||
10120          (((tracking_flag + ip_flag) != 0) && ((tracking_flag + ip_flag) != 2)))
10121     {
10122         ParseError(ERR_BAD_ARG_COUNT);
10123     }
10124 
10125     if (sfthreshold_create(sc, sc->threshold_config, &thdx))
10126     {
10127         ParseError(ERR_CREATE);
10128     }
10129 
10130     mSplitFree(&toks, num_toks);
10131 }
10132 
ParseOtnClassType(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10133 static void ParseOtnClassType(SnortConfig *sc, RuleTreeNode *rtn,
10134                               OptTreeNode *otn, RuleType rtype, char *args)
10135 {
10136     ClassType *class_type;
10137 
10138     if (args == NULL)
10139     {
10140         ParseWarning("ClassType without an argument!");
10141         return;
10142     }
10143 
10144     class_type = ClassTypeLookupByType(sc, args);
10145     if (class_type == NULL)
10146         ParseError("Unknown ClassType: %s", args);
10147 
10148     otn->sigInfo.classType = class_type;
10149 
10150     /* Add the class_id to class_id so we can reference it for all rules,
10151      * whether they have a class_id or not.  */
10152     otn->sigInfo.class_id = class_type->id;
10153 
10154     if (otn->sigInfo.priority == 0)
10155         otn->sigInfo.priority = class_type->priority;
10156 
10157     /* XXX deprecated */
10158     otn->event_data.classification = class_type->id;
10159     if (otn->event_data.priority == 0)
10160         otn->event_data.priority = class_type->priority;
10161 }
10162 
ParseOtnDetectionFilter(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10163 static void ParseOtnDetectionFilter(SnortConfig *sc, RuleTreeNode *rtn,
10164                                     OptTreeNode *otn, RuleType rtype, char *args)
10165 {
10166     int count_flag = 0;
10167     int seconds_flag = 0;
10168     int tracking_flag = 0;
10169     char **toks;
10170     int num_toks;
10171     int i;
10172     static THDX_STRUCT thdx;
10173     const char* ERR_KEY = "detection_filter";
10174 
10175     memset(&thdx, 0, sizeof(THDX_STRUCT));
10176 
10177     toks = mSplit(args, ",", 0, &num_toks, 0);
10178 
10179     /* Parameter Check - enough args ?*/
10180     if (num_toks != 3)
10181     {
10182         ParseError(ERR_PAIR_COUNT, 3);
10183     }
10184 
10185     for (i = 0; i < num_toks; i++)
10186     {
10187         char **pairs;
10188         int num_pairs;
10189 
10190         pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0);
10191         if (num_pairs != 2)
10192         {
10193             ParseError(ERR_NOT_PAIRED);
10194         }
10195 
10196         if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
10197         {
10198             if ( count_flag++ )
10199             {
10200                 ParseError(ERR_EXTRA_OPTION);
10201             }
10202 
10203             thdx.count = xatoup(pairs[1],"detection_filter: count");
10204         }
10205         else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
10206         {
10207             if ( seconds_flag++ )
10208             {
10209                 ParseError(ERR_EXTRA_OPTION);
10210             }
10211 
10212             thdx.seconds = xatoup(pairs[1],"detection_filter: seconds");
10213         }
10214         else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
10215         {
10216             if ( tracking_flag++ )
10217             {
10218                 ParseError(ERR_EXTRA_OPTION);
10219             }
10220 
10221             if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
10222             {
10223                 thdx.tracking = THD_TRK_SRC;
10224             }
10225             else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
10226             {
10227                 thdx.tracking = THD_TRK_DST;
10228             }
10229             else
10230             {
10231                 ParseError(ERR_BAD_VALUE);
10232             }
10233         }
10234         else
10235         {
10236             ParseError(ERR_BAD_OPTION);
10237         }
10238 
10239         mSplitFree(&pairs, num_pairs);
10240     }
10241 
10242     if ((count_flag + tracking_flag + seconds_flag) != 3)
10243     {
10244         ParseError(ERR_BAD_ARG_COUNT);
10245     }
10246 
10247     mSplitFree(&toks, num_toks);
10248 
10249     thdx.type = THD_TYPE_DETECT;
10250 
10251     otn->detection_filter =
10252         detection_filter_create(sc->detection_filter_config, &thdx);
10253 }
10254 
ParseOtnGid(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10255 static void ParseOtnGid(SnortConfig *sc, RuleTreeNode *rtn,
10256                         OptTreeNode *otn, RuleType rtype, char *args)
10257 {
10258     unsigned long int gid;
10259     char *endptr;
10260 
10261     if (args == NULL)
10262         ParseError("Gid rule option requires an argument.");
10263 
10264     gid = SnortStrtoul(args, &endptr, 0);
10265     if ((errno == ERANGE) || (*endptr != '\0'))
10266     {
10267         ParseError("Invalid argument to 'gid' rule option: %s.  "
10268                    "Must be a positive integer.", args);
10269     }
10270 
10271     otn->sigInfo.generator = (uint32_t)gid;
10272     otn->event_data.sig_generator = (uint32_t)gid;
10273 }
10274 
10275 /****************************************************************************
10276  * Function: ParseOtnLogTo()
10277  *
10278  * Purpose: stuff the special log filename onto the proper rule option
10279  *
10280  * Arguments:
10281  *  OptTreeNode *
10282  *      The otn for this rule option
10283  *  RuleType
10284  *      The rule type of the rule using this option
10285  *  char *
10286  *      The arguments to this rule option
10287  *
10288  * Returns: None
10289  *
10290  ***************************************************************************/
ParseOtnLogTo(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10291 static void ParseOtnLogTo(SnortConfig *sc, RuleTreeNode *rtn,
10292                           OptTreeNode *otn, RuleType rtype, char *args)
10293 {
10294     char *sptr;
10295     char *eptr;
10296 
10297     if (args == NULL)
10298         ParseError("'logto' requires a file name as an argument.");
10299 
10300     /* grab everything between the starting " and the end one */
10301     sptr = strchr(args, '"');
10302     eptr = strrchr(args, '"');
10303 
10304     if ((sptr != NULL) && (eptr != NULL))
10305     {
10306         /* increment past the first quote */
10307         sptr++;
10308 
10309         /* zero out the second one */
10310         *eptr = 0;
10311     }
10312     else
10313     {
10314         sptr = args;
10315     }
10316 
10317     /* alloc up a nice shiny clean buffer */
10318     otn->logto = SnortStrdup(sptr);
10319 }
10320 
10321 /****************************************************************************
10322  * Function: ParseOtnMessage()
10323  *
10324  * Purpose: Stuff the alert message onto the rule
10325  *
10326  * Arguments:
10327  *  OptTreeNode *
10328  *      The otn for this rule option
10329  *  RuleType
10330  *      The rule type of the rule using this option
10331  *  char *
10332  *      The arguments to this rule option
10333  *
10334  * Returns: None
10335  *
10336  ***************************************************************************/
ParseOtnMessage(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10337 static void ParseOtnMessage(SnortConfig *sc, RuleTreeNode *rtn,
10338                             OptTreeNode *otn, RuleType rtype, char *args)
10339 {
10340     size_t i;
10341     int escaped = 0;
10342     char msg_buf[2048];  /* Arbitrary length, but should be enough */
10343 
10344     if (args == NULL)
10345         ParseError("Message rule option requires an argument.");
10346 
10347     if (*args == '"')
10348     {
10349         /* Have to have at least quote, char, quote */
10350         if (strlen(args) < 3)
10351             ParseError("Empty argument passed to rule option 'msg'.");
10352 
10353         if (args[strlen(args) - 1] != '"')
10354         {
10355             ParseError("Unmatch quote in rule option 'msg'.");
10356         }
10357 
10358         /* Move past first quote and NULL terminate last quote */
10359         args++;
10360         args[strlen(args) - 1] = '\0';
10361 
10362         /* If last quote is escaped, fatal error.
10363          * Make sure the backslash is not escaped */
10364         if ((args[strlen(args) - 1] == '\\') &&
10365             (strlen(args) > 1) && (args[strlen(args) - 2] != '\\'))
10366         {
10367             ParseError("Unmatch quote in rule option 'msg'.");
10368         }
10369     }
10370 
10371     /* Only valid escaped chars are ';', '"' and '\' */
10372     /* Would be ok except emerging threats rules are escaping other chars */
10373     for (i = 0; (i < sizeof(msg_buf)) && (*args != '\0');)
10374     {
10375         if (escaped)
10376         {
10377 #if 0
10378             if ((*args != ';') && (*args != '"') && (*args != '\\'))
10379             {
10380                 ParseError("Invalid escaped character in 'msg' rule "
10381                            "option: '%c'.  Valid characters to escape are "
10382                            "';', '\"' and '\\'.\n", *args);
10383             }
10384 #endif
10385 
10386             msg_buf[i++] = *args;
10387             escaped = 0;
10388         }
10389         else if (*args == '\\')
10390         {
10391             escaped = 1;
10392         }
10393         else
10394         {
10395             msg_buf[i++] = *args;
10396         }
10397 
10398         args++;
10399     }
10400 
10401     if (escaped)
10402     {
10403         ParseError("Message in 'msg' rule option has invalid escape character\n");
10404     }
10405 
10406     if (i == sizeof(msg_buf))
10407     {
10408         ParseError("Message in 'msg' rule option too long.  Please limit "
10409                    "to %d characters.", sizeof(msg_buf));
10410     }
10411 
10412     msg_buf[i] = '\0';
10413 
10414     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Message: %s\n", msg_buf););
10415 
10416     otn->sigInfo.message = SnortStrdup(msg_buf);
10417 }
10418 
10419 /*
10420  * metadata may be key/value pairs or just keys
10421  *
10422  * metadata: key [=] value, key [=] value, key [=] value, key, key, ... ;
10423  *
10424  * This option may be used one or more times, with one or more key/value pairs.
10425  *
10426  * updated 8/28/06 - man
10427  *
10428  * keys:
10429  *
10430  * engine
10431  * rule-flushing
10432  * rule-type
10433  * soid
10434  * service
10435  */
ParseOtnMetadata(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10436 static void ParseOtnMetadata(SnortConfig *sc, RuleTreeNode *rtn,
10437                              OptTreeNode *otn, RuleType rtype, char *args)
10438 {
10439     char **metadata_toks;
10440     int num_metadata_toks;
10441     int i;
10442 
10443     char **key_value_toks = NULL;
10444     int num_key_value_toks = 0;
10445 
10446 
10447     if (args == NULL)
10448         ParseError("Metadata rule option requires an argument.");
10449 
10450     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "metadata: %s\n", args););
10451 
10452     metadata_toks = mSplit(args, ",", 100, &num_metadata_toks, 0);
10453 
10454     for (i = 0; i < num_metadata_toks; i++)
10455     {
10456         char *key = NULL;
10457         char *value = NULL;
10458 
10459         // After the first loop iteration, free the |key_value_toks|
10460         if (key_value_toks != NULL) {
10461             mSplitFree(&key_value_toks, num_key_value_toks);
10462             key_value_toks     = NULL;
10463             num_key_value_toks = 0;
10464         }
10465 
10466         key_value_toks = mSplit(metadata_toks[i], "= ", 2, &num_key_value_toks, 0);
10467 
10468         key = key_value_toks[0];
10469         if (num_key_value_toks == 2)
10470             value = key_value_toks[1];
10471 
10472         DEBUG_WRAP( DebugMessage(DEBUG_CONFIGRULES, "metadata: key=%s\n", key);
10473           if(value) DebugMessage(DEBUG_CONFIGRULES, " value=%s\n", value); );
10474 
10475         /* process key/value pairs */
10476         if (strcasecmp(key, METADATA_KEY__ENGINE) == 0)
10477         {
10478             if (value == NULL)
10479                 ParseError("Metadata key '%s' requires a value", key);
10480 
10481             if (strcasecmp(value, METADATA_VALUE__SHARED) != 0)
10482                 ParseError("Metadata key '%s', passed an invalid value '%s'.", key, value);
10483 
10484             otn->sigInfo.shared = 1;
10485         }
10486         /* this should follow 'rule-type' since it changes rule_flusing defaults set by rule-type */
10487         else if (strcasecmp(key, METADATA_KEY__RULE_FLUSHING) == 0)
10488         {
10489             if (value == NULL)
10490                 ParseError("Metadata key '%s' requires a value.", key);
10491 
10492             if ((strcasecmp(value, METADATA_VALUE__ENABLED) == 0) ||
10493                 (strcasecmp(value, METADATA_VALUE__ON) == 0))
10494             {
10495                 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_ON;
10496             }
10497             else if ((strcasecmp(value, METADATA_VALUE__DISABLED) == 0) ||
10498                      (strcasecmp(value, METADATA_VALUE__OFF) == 0))
10499             {
10500                 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10501             }
10502             else
10503             {
10504                 ParseError("Metadata key '%s', passed an invalid value '%s'.",
10505                            key, value);
10506             }
10507         }
10508         else if (strcasecmp(key, METADATA_KEY__RULE_TYPE) == 0)
10509         {
10510             if (value == NULL)
10511                 ParseError("Metadata key '%s' requires a value.", key);
10512 
10513             if (strcasecmp(value, METADATA_VALUE__PREPROC) == 0)
10514             {
10515                 otn->sigInfo.rule_type = SI_RULE_TYPE_PREPROC;
10516                 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10517             }
10518             else if (strcasecmp(value, METADATA_VALUE__DECODE) == 0)
10519             {
10520                 if ( otn->sigInfo.id >= DECODE_INDEX_MAX )
10521                 {
10522                     ParseError("Unknown 'sid' for rule-type decode.");
10523                 }
10524                 else
10525                 {
10526                     otn->sigInfo.rule_type = SI_RULE_TYPE_DECODE;
10527                     otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_OFF;
10528                 }
10529             }
10530             else if (strcasecmp(value, METADATA_VALUE__DETECT) == 0)
10531             {
10532                 otn->sigInfo.rule_type = SI_RULE_TYPE_DETECT;
10533                 otn->sigInfo.rule_flushing = SI_RULE_FLUSHING_ON;
10534             }
10535             else
10536             {
10537                 ParseError("Metadata key '%s', passed an invalid value '%s'.",
10538                            key, value);
10539             }
10540         }
10541         else if (strcasecmp(key, METADATA_KEY__SOID) == 0)
10542         {
10543             char **toks;
10544             int num_toks;
10545             char *endptr;
10546             uint64_t long_val;
10547 
10548             if (value == NULL)
10549                 ParseError("Metadata key '%s' requires a value.", key);
10550 
10551             /* value is a '|' separated pair of gid|sid representing the
10552              * GID/SID of the original rule.  This is used when the rule
10553              * is duplicated rule by a user with different IP/port info.
10554              */
10555             toks = mSplit(value, "|", 2, &num_toks, 0);
10556             if (num_toks != 2)
10557             {
10558                 ParseError("Metadata Key '%s' Invalid Value. Must be a pipe "
10559                            "(|) separated pair.", key);
10560             }
10561 
10562             long_val = SnortStrtoul(toks[0], &endptr, 10);
10563             if ((errno == ERANGE) || (*endptr != '\0') || (long_val > UINT32_MAX))
10564                 ParseError("Bogus gid %s", toks[0]);
10565 
10566             otn->sigInfo.otnKey.gid = (uint32_t)long_val;
10567 
10568             long_val = SnortStrtoul(toks[1], &endptr, 10);
10569             if ((errno == ERANGE) || (*endptr != '\0') || (long_val > UINT32_MAX))
10570                 ParseError("Bogus sid %s", toks[1]);
10571 
10572             otn->sigInfo.otnKey.sid = (uint32_t)long_val;
10573 
10574             mSplitFree(&toks, num_toks);
10575         }
10576 #ifdef TARGET_BASED
10577         /* track all of the rules for each service */
10578         else if (strcasecmp(key, METADATA_KEY__SERVICE) == 0 )
10579         {
10580             // metadata: service http, ... ;
10581             unsigned j, svc_count = otn->sigInfo.num_services;
10582             int16_t ordinal = 0;
10583             bool found = false;
10584 
10585             if (value == NULL)
10586             {
10587                 ParseError("Metadata key '%s' requires a value.", key);
10588             }
10589 
10590             if (otn->sigInfo.num_services >= sc->max_metadata_services)
10591             {
10592                 ParseError("Too many service's specified for rule.");
10593             }
10594 
10595             if (otn->sigInfo.services == NULL)
10596             {
10597                 otn->sigInfo.services = SnortAlloc(sizeof(ServiceInfo) * sc->max_metadata_services);
10598             }
10599 
10600             // Service Override(s)
10601             if ( strcmp(value, "and-ports") == 0 )
10602             {
10603                 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10604                     ParseWarning("Multiple service overrides specified: using '%s'", value);
10605 
10606                 otn->sigInfo.service_override = ServiceOverride_AndPorts;
10607                 continue;
10608             }
10609             else if ( strcmp(value, "or-ports") == 0 )
10610             {
10611                 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10612                     ParseWarning("Multiple service overrides specified: using '%s'", value);
10613 
10614                 otn->sigInfo.service_override = ServiceOverride_OrPorts;
10615                 continue;
10616             }
10617             else if ( strcmp(value, "else-ports") == 0 )
10618             {
10619                 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10620                     ParseWarning("Multiple service overrides specified: using '%s'", value);
10621 
10622                 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
10623                 continue;
10624             }
10625             else if ( strcmp(value, "unknown") == 0 )
10626             {
10627                 if (otn->sigInfo.service_override != ServiceOverride_Nil)
10628                     ParseWarning("Multiple service overrides specified: using '%s'", value);
10629 
10630                 // "Unknown" is a convenient synonym for "else-ports".
10631                 // It emulates pre-Snort 2.9.8 behavior on "port-only" rules.
10632                 otn->sigInfo.service_override = ServiceOverride_ElsePorts;
10633                 continue;
10634             }
10635             else
10636             {
10637                 ordinal = FindProtocolReference(value);
10638                 if (ordinal == SFTARGET_UNKNOWN_PROTOCOL)
10639                     ordinal = AddProtocolReference(value);
10640             }
10641 
10642             for ( j = 0; j < svc_count; j++ )
10643             {
10644                 if (otn->sigInfo.services[j].service_ordinal == ordinal)
10645                 {
10646                     ParseWarning("Duplicate service metadata \"%s\" found.", value);
10647                     found = true;
10648                     break;
10649                 }
10650             }
10651 
10652             if ( !found )
10653             {
10654                 otn->sigInfo.services[svc_count].service = SnortStrdup(value);
10655                 otn->sigInfo.services[svc_count].service_ordinal = ordinal;
10656                 otn->sigInfo.num_services++;
10657             }
10658         }
10659 #endif // TARGET_BASED
10660     }
10661 
10662     mSplitFree(&key_value_toks, num_key_value_toks);
10663     mSplitFree(&metadata_toks, num_metadata_toks);
10664 }
10665 
ParseOtnPriority(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10666 static void ParseOtnPriority(SnortConfig *sc, RuleTreeNode *rtn,
10667                              OptTreeNode *otn, RuleType rtype, char *args)
10668 {
10669     unsigned long int priority;
10670     char *endptr;
10671 
10672     if (args == NULL)
10673         ParseError("Priority rule option requires an argument.");
10674 
10675     priority = SnortStrtoul(args, &endptr, 0);
10676     if ((errno == ERANGE) || (*endptr != '\0'))
10677     {
10678         ParseError("Invalid argument to 'gid' rule option: %s.  "
10679                    "Must be a positive integer.", args);
10680     }
10681 
10682     otn->sigInfo.priority = (uint32_t)priority;
10683     /* deprecated */
10684     otn->event_data.priority = (uint32_t)priority;
10685 }
10686 
ParseOtnReference(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10687 static void ParseOtnReference(SnortConfig *sc, RuleTreeNode *rtn,
10688                               OptTreeNode *otn, RuleType rtype, char *args)
10689 {
10690     char **toks;
10691     int num_toks;
10692 
10693     if (args == NULL)
10694         ParseError("Reference rule option requires an argument.");
10695 
10696     /* 2 tokens: system, id */
10697     toks = mSplit(args, ",", 2, &num_toks, 0);
10698     if (num_toks != 2)
10699     {
10700         ParseWarning("Ignoring invalid Reference spec '%s'.", args);
10701         mSplitFree(&toks, num_toks);
10702         return;
10703     }
10704 
10705     AddReference(sc, &otn->sigInfo.refs, toks[0], toks[1]);
10706 
10707     mSplitFree(&toks, num_toks);
10708 }
10709 
ParseOtnRevision(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10710 static void ParseOtnRevision(SnortConfig *sc, RuleTreeNode *rtn,
10711                              OptTreeNode *otn, RuleType rtype, char *args)
10712 {
10713     unsigned long int rev;
10714     char *endptr;
10715 
10716     if (args == NULL)
10717         ParseError("Revision rule option requires an argument.");
10718 
10719     rev = SnortStrtoul(args, &endptr, 0);
10720     if ((errno == ERANGE) || (*endptr != '\0'))
10721     {
10722         ParseError("Invalid argument to 'rev' rule option: %s.  "
10723                    "Must be a positive integer.", args);
10724     }
10725 
10726     otn->sigInfo.rev = (uint32_t)rev;
10727     /* deprecated */
10728     otn->event_data.sig_rev = (uint32_t)rev;
10729 }
10730 
ParseOtnSid(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10731 static void ParseOtnSid(SnortConfig *sc, RuleTreeNode *rtn,
10732                         OptTreeNode *otn, RuleType rtype, char *args)
10733 {
10734     unsigned long int sid;
10735     char *endptr;
10736 
10737     if (args == NULL)
10738         ParseError("Revision rule option requires an argument.");
10739 
10740     sid = SnortStrtoul(args, &endptr, 0);
10741     if ((errno == ERANGE) || (*endptr != '\0'))
10742     {
10743         ParseError("Invalid argument to 'sid' rule option: %s.  "
10744                    "Must be a positive integer.", args);
10745     }
10746 
10747     otn->sigInfo.id = (uint32_t)sid;
10748     /* deprecated */
10749     otn->event_data.sig_id = (uint32_t)sid;
10750 }
10751 
ParseOtnTag(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10752 static void ParseOtnTag(SnortConfig *sc, RuleTreeNode *rtn,
10753                         OptTreeNode *otn, RuleType rtype, char *args)
10754 {
10755     int type = 0;
10756     int count = 0;
10757     int metric = 0;
10758     int packets = 0;
10759     int seconds = 0;
10760     int bytes = 0;
10761     int direction = 0;
10762     int i;
10763     char **toks;
10764     int num_toks;
10765     uint8_t got_count = 0;
10766 
10767     if (otn->tag != NULL)
10768         ParseError("Can only use 'tag' rule option once per rule.");
10769 
10770     DEBUG_WRAP(DebugMessage(DEBUG_RULES, "Parsing tag args: %s\n", args););
10771     toks = mSplit(args, " ,", 0, &num_toks, 0);
10772 
10773     if (num_toks < 1)
10774         ParseError("Invalid tag arguments: %s", args);
10775 
10776     if (strcasecmp(toks[0], TAG_OPT__SESSION) == 0)
10777         type = TAG_SESSION;
10778     else if (strcasecmp(toks[0], TAG_OPT__HOST) == 0)
10779         type = TAG_HOST;
10780     else
10781         ParseError("Invalid tag type: %s", toks[0]);
10782 
10783     for (i = 1; i < num_toks; i++)
10784     {
10785         if (!got_count)
10786         {
10787             if (isdigit((int)toks[i][0]))
10788             {
10789                 long int val;
10790                 char *endptr;
10791 
10792                 val = SnortStrtol(toks[i], &endptr, 0);
10793                 if ((errno == ERANGE) || (*endptr != '\0') ||
10794                         (val < 0) || (val > INT32_MAX))
10795                 {
10796                     ParseError("Invalid argument to 'tag' rule option.  "
10797                             "Numbers must be between 0 and %d.", INT32_MAX);
10798                 }
10799 
10800                 count = (int)val;
10801                 got_count = 1;
10802             }
10803             else
10804             {
10805                 /* Check for src/dst/exclusive */
10806                 break;
10807             }
10808         }
10809         else
10810         {
10811             if (strcasecmp(toks[i], TAG_OPT__SECONDS) == 0)
10812             {
10813                 if (metric & TAG_METRIC_SECONDS)
10814                     ParseError("Can only configure seconds metric to tag rule option once");
10815                 if (!count)
10816                     ParseError("Tag seconds metric must have a positive count");
10817 
10818                 metric |= TAG_METRIC_SECONDS;
10819                 seconds = count;
10820             }
10821             else if (strcasecmp(toks[i], TAG_OPT__PACKETS) == 0)
10822             {
10823                 if (metric & (TAG_METRIC_PACKETS|TAG_METRIC_UNLIMITED))
10824                     ParseError("Can only configure packets metric to tag rule option once");
10825                 if (count)
10826                     metric |= TAG_METRIC_PACKETS;
10827                 else
10828                     metric |= TAG_METRIC_UNLIMITED;
10829 
10830                 packets = count;
10831             }
10832             else if (strcasecmp(toks[i], TAG_OPT__BYTES) == 0)
10833             {
10834                 if (metric & TAG_METRIC_BYTES)
10835                     ParseError("Can only configure bytes metric to tag rule option once");
10836                 if (!count)
10837                     ParseError("Tag bytes metric must have a positive count");
10838 
10839                 metric |= TAG_METRIC_BYTES;
10840                 bytes = count;
10841             }
10842             else
10843             {
10844                 ParseError("Invalid tag metric: %s", toks[i]);
10845             }
10846             got_count = 0;
10847         }
10848     }
10849 
10850     if ( got_count )
10851         ParseError("Invalid tag rule option: %s", args);
10852 
10853     if ((metric & TAG_METRIC_UNLIMITED) &&
10854         !(metric & (TAG_METRIC_BYTES|TAG_METRIC_SECONDS)))
10855     {
10856         ParseError("Invalid Tag options. 'packets' parameter '0' but "
10857                    "neither seconds or bytes specified: %s", args);
10858     }
10859 
10860     if (i < num_toks)
10861     {
10862         if (type == TAG_HOST)
10863         {
10864             if (strcasecmp(toks[i], TAG_OPT__SRC) == 0)
10865                 direction = TAG_HOST_SRC;
10866             else if (strcasecmp(toks[i], TAG_OPT__DST) == 0)
10867                 direction = TAG_HOST_DST;
10868             else
10869                 ParseError("Invalid 'tag:host' option: %s.", toks[i]);
10870         }
10871         else
10872         {
10873             if (strcasecmp(toks[i], TAG_OPT__EXCLUSIVE) == 0)
10874                 metric |= TAG_METRIC_SESSION;
10875             else
10876                 ParseError("Invalid 'tag:session' option: %s.", toks[i]);
10877         }
10878         i++;
10879     }
10880     else if (type == TAG_HOST)
10881     {
10882         ParseError("Tag host type must specify direction");
10883     }
10884 
10885     if ( !metric || (i != num_toks) )
10886         ParseError("Invalid 'tag' option: %s.", args);
10887 
10888     mSplitFree(&toks, num_toks);
10889 
10890     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Set type: %d  metric: %x count: %d\n", type,
10891                             metric, count););
10892 
10893     otn->tag = (TagData *)SnortAlloc(sizeof(TagData));
10894 
10895     otn->tag->tag_type = type;
10896     otn->tag->tag_metric = metric;
10897     otn->tag->tag_seconds = seconds;
10898     otn->tag->tag_bytes = bytes;
10899     otn->tag->tag_packets = packets;
10900     otn->tag->tag_direction = direction;
10901 }
10902 
10903 /*
10904 Parse Threshold Rule option parameters for each RULE
10905 
10906 'threshold: type limit|threshold|both, track by_src|by_dst, count #, seconds #;'
10907 */
ParseOtnThreshold(SnortConfig * sc,RuleTreeNode * rtn,OptTreeNode * otn,RuleType rtype,char * args)10908 static void ParseOtnThreshold(SnortConfig *sc, RuleTreeNode *rtn,
10909                               OptTreeNode *otn, RuleType rtype, char *args)
10910 {
10911     int count_flag = 0;
10912     int seconds_flag = 0;
10913     int type_flag = 0;
10914     int tracking_flag = 0;
10915     char **toks;
10916     int num_toks;
10917     static THDX_STRUCT thdx;
10918     int i;
10919     static int warned = 0;
10920     const char* ERR_KEY = "rule threshold";
10921 
10922     if (args == NULL)
10923         ParseError("Threshold rule option requires an argument.");
10924 
10925     if (!warned)
10926     {
10927         ParseWarning("threshold (in rule) is deprecated; "
10928             "use detection_filter instead.\n");
10929 
10930         warned = 1;
10931     }
10932 
10933     memset(&thdx, 0, sizeof(THDX_STRUCT));
10934 
10935     /* Make this lower than standalone threshold command defaults ??? */
10936     thdx.priority = -1;
10937 
10938     toks = mSplit(args, ",", 0, &num_toks, 0);
10939 
10940     /* Parameter Check - enough args ?*/
10941     if (num_toks != 4)
10942     {
10943         ParseError(ERR_PAIR_COUNT, 4);
10944     }
10945 
10946     for (i = 0; i < num_toks; i++)
10947     {
10948         char **pairs;
10949         int num_pairs;
10950 
10951         pairs = mSplit(toks[i], " \t", 0, &num_pairs, 0);
10952         if (num_pairs != 2)
10953         {
10954             ParseError(ERR_NOT_PAIRED);
10955         }
10956 
10957         if (strcasecmp(pairs[0], THRESHOLD_OPT__COUNT) == 0)
10958         {
10959             if ( count_flag++ )
10960             {
10961                 ParseError(ERR_EXTRA_OPTION);
10962             }
10963 
10964             thdx.count = xatoup(pairs[1],"threshold: count");
10965         }
10966         else if (strcasecmp(pairs[0], THRESHOLD_OPT__SECONDS) == 0)
10967         {
10968             if ( seconds_flag++ )
10969             {
10970                 ParseError(ERR_EXTRA_OPTION);
10971             }
10972 
10973             thdx.seconds = xatoup(pairs[1],"threshold: seconds");
10974         }
10975         else if (strcasecmp(pairs[0], THRESHOLD_OPT__TYPE) == 0)
10976         {
10977             if ( type_flag++ )
10978             {
10979                 ParseError(ERR_EXTRA_OPTION);
10980             }
10981 
10982             if (strcasecmp(pairs[1], THRESHOLD_TYPE__LIMIT) == 0)
10983             {
10984                 thdx.type = THD_TYPE_LIMIT;
10985             }
10986             else if (strcasecmp(pairs[1], THRESHOLD_TYPE__THRESHOLD) == 0)
10987             {
10988                 thdx.type = THD_TYPE_THRESHOLD;
10989             }
10990             else if (strcasecmp(pairs[1], THRESHOLD_TYPE__BOTH) == 0)
10991             {
10992                 thdx.type = THD_TYPE_BOTH;
10993             }
10994             else
10995             {
10996                 ParseError(ERR_BAD_VALUE);
10997             }
10998         }
10999         else if (strcasecmp(pairs[0], THRESHOLD_OPT__TRACK) == 0)
11000         {
11001             if ( tracking_flag++ )
11002             {
11003                 ParseError(ERR_EXTRA_OPTION);
11004             }
11005 
11006             if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_SRC) == 0)
11007             {
11008                 thdx.tracking = THD_TRK_SRC;
11009             }
11010             else if (strcasecmp(pairs[1], THRESHOLD_TRACK__BY_DST) == 0)
11011             {
11012                 thdx.tracking = THD_TRK_DST;
11013             }
11014             else
11015             {
11016                 ParseError(ERR_BAD_VALUE);
11017             }
11018         }
11019         else
11020         {
11021             ParseError(ERR_BAD_OPTION);
11022         }
11023 
11024         mSplitFree(&pairs, num_pairs);
11025     }
11026 
11027     if ((count_flag + tracking_flag + type_flag + seconds_flag) != 4)
11028     {
11029         ParseError(ERR_BAD_ARG_COUNT);
11030     }
11031 
11032     mSplitFree(&toks, num_toks);
11033 
11034     /* Save this since we still need to add gid and sid */
11035     thdx_tmp = &thdx;
11036 }
11037 
CreateDefaultRules(SnortConfig * sc)11038 static void CreateDefaultRules(SnortConfig *sc)
11039 {
11040     if (sc == NULL)
11041         return;
11042 
11043     CreateRuleType(sc, RULE_LIST_TYPE__PASS, RULE_TYPE__PASS, 0, &sc->Pass); /* changed on Jan 06 */
11044     CreateRuleType(sc, RULE_LIST_TYPE__DROP, RULE_TYPE__DROP, 1, &sc->Drop);
11045     CreateRuleType(sc, RULE_LIST_TYPE__SDROP, RULE_TYPE__SDROP, 0, &sc->SDrop);
11046     CreateRuleType(sc, RULE_LIST_TYPE__REJECT, RULE_TYPE__REJECT, 1, &sc->Reject);
11047     CreateRuleType(sc, RULE_LIST_TYPE__ALERT, RULE_TYPE__ALERT, 1, &sc->Alert);
11048     CreateRuleType(sc, RULE_LIST_TYPE__LOG, RULE_TYPE__LOG, 1, &sc->Log);
11049 }
11050 
GetRuleType(char * arg)11051 static RuleType GetRuleType(char *arg)
11052 {
11053     if (arg == NULL)
11054         return RULE_TYPE__NONE;
11055 
11056     if (strcasecmp(arg, SNORT_CONF_KEYWORD__ALERT) == 0)
11057         return RULE_TYPE__ALERT;
11058     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__DROP) == 0)
11059         return RULE_TYPE__DROP;
11060     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__BLOCK) == 0)
11061         return RULE_TYPE__DROP;
11062     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__LOG) == 0)
11063         return RULE_TYPE__LOG;
11064     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__PASS) == 0)
11065         return RULE_TYPE__PASS;
11066     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__REJECT) == 0)
11067         return RULE_TYPE__REJECT;
11068     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__SDROP) == 0)
11069         return RULE_TYPE__SDROP;
11070     else if (strcasecmp(arg, SNORT_CONF_KEYWORD__SBLOCK) == 0)
11071         return RULE_TYPE__SDROP;
11072 
11073     return RULE_TYPE__NONE;
11074 }
11075 
FreeRuleTreeNodes(SnortConfig * sc)11076 static void FreeRuleTreeNodes(SnortConfig *sc)
11077 {
11078     RuleTreeNode *rtn;
11079     OptTreeNode *otn;
11080     tSfPolicyId policyId;
11081     SFGHASH_NODE *hashNode;
11082 
11083     if (sc->otn_map == NULL)
11084         return;
11085 
11086     for (hashNode = sfghash_findfirst(sc->otn_map);
11087          hashNode;
11088          hashNode = sfghash_findnext(sc->otn_map))
11089     {
11090         otn = (OptTreeNode *)hashNode->data;
11091 
11092         /* Autogenerated OTNs along with their respective pseudo RTN
11093          * will get cleaned up when the OTN is free'd */
11094         if (otn->generated)
11095             continue;
11096 
11097         for (policyId = 0;
11098              policyId < otn->proto_node_num;
11099              policyId++)
11100         {
11101             rtn = getRtnFromOtn(otn, policyId);
11102             DestroyRuleTreeNode(rtn);
11103 
11104             otn->proto_nodes[policyId] = NULL;
11105         }
11106     }
11107 }
11108 
FreeOutputLists(ListHead * list)11109 static void FreeOutputLists(ListHead *list)
11110 {
11111     if (list->AlertList != NULL)
11112         FreeOutputList(list->AlertList);
11113 
11114     if (list->LogList != NULL)
11115         FreeOutputList(list->LogList);
11116 }
11117 
FreeRuleLists(SnortConfig * sc)11118 void FreeRuleLists(SnortConfig *sc)
11119 {
11120     if (sc == NULL)
11121         return;
11122 
11123     FreeRuleTreeNodes(sc);
11124 
11125     FreeOutputLists(&sc->Drop);
11126     FreeOutputLists(&sc->SDrop);
11127     FreeOutputLists(&sc->Reject);
11128     FreeOutputLists(&sc->Alert);
11129     FreeOutputLists(&sc->Log);
11130     FreeOutputLists(&sc->Pass);
11131     FreeOutputLists(&sc->Activation);
11132     FreeOutputLists(&sc->Dynamic);
11133 
11134     /* Iterate through the user-defined types */
11135     if (sc->rule_lists != NULL)
11136     {
11137         RuleListNode *node = sc->rule_lists;
11138 
11139         while (node != NULL)
11140         {
11141             RuleListNode *tmp = node;
11142 
11143             node = node->next;
11144 
11145             if ((tmp->RuleList != &sc->Drop) &&
11146                 (tmp->RuleList != &sc->SDrop) &&
11147                 (tmp->RuleList != &sc->Reject) &&
11148                 (tmp->RuleList != &sc->Alert) &&
11149                 (tmp->RuleList != &sc->Log) &&
11150                 (tmp->RuleList != &sc->Pass) &&
11151                 (tmp->RuleList != &sc->Activation) &&
11152                 (tmp->RuleList != &sc->Dynamic))
11153             {
11154                 FreeOutputLists(tmp->RuleList);
11155                 free(tmp->RuleList);
11156             }
11157 
11158             if (tmp->name)
11159                 free(tmp->name);
11160 
11161             free(tmp);
11162         }
11163 
11164         sc->rule_lists = NULL;
11165     }
11166 }
11167 
port_entry_free(port_entry_t * pentry)11168 static void port_entry_free(port_entry_t *pentry)
11169 {
11170     if (pentry->src_port != NULL)
11171     {
11172         free(pentry->src_port);
11173         pentry->src_port = NULL;
11174     }
11175 
11176     if (pentry->dst_port != NULL)
11177     {
11178         free(pentry->dst_port);
11179         pentry->dst_port = NULL;
11180     }
11181 
11182     if (pentry->protocol != NULL)
11183     {
11184         free(pentry->protocol);
11185         pentry->protocol = NULL;
11186     }
11187 }
11188 
port_list_add_entry(port_list_t * plist,port_entry_t * pentry)11189 static int port_list_add_entry( port_list_t * plist, port_entry_t * pentry)
11190 {
11191     int ret;
11192 
11193     if( !plist )
11194     {
11195         port_entry_free(pentry);
11196         return -1;
11197     }
11198 
11199     if( plist->pl_cnt >= plist->pl_max )
11200     {
11201         port_entry_free(pentry);
11202         return -1;
11203     }
11204 
11205     ret = SafeMemcpy( &plist->pl_array[plist->pl_cnt], pentry, sizeof(port_entry_t),
11206                 &plist->pl_array[plist->pl_cnt],
11207                 (char*)(&plist->pl_array[plist->pl_cnt]) + sizeof(port_entry_t));
11208     if (ret != SAFEMEM_SUCCESS)
11209     {
11210         ParseError("%s SafeMemcpy() Failed !!!", __FUNCTION__);
11211         return -1;
11212     }
11213 
11214     plist->pl_cnt++;
11215 
11216     return 0;
11217 }
11218 
11219 #if 0
11220 static port_entry_t * port_list_get( port_list_t * plist, int index)
11221 {
11222     if( index < plist->pl_max )
11223     {
11224         return &plist->pl_array[index];
11225     }
11226     return NULL;
11227 }
11228 
11229 static void port_list_print( port_list_t * plist)
11230 {
11231     int i;
11232     for(i=0;i<plist->pl_cnt;i++)
11233     {
11234         LogMessage("rule %d { ", i);
11235         LogMessage(" gid %u sid %u",plist->pl_array[i].gid,plist->pl_array[i].sid );
11236         LogMessage(" protocol %s", plist->pl_array[i].protocol);
11237         LogMessage(" dir %d",plist->pl_array[i].dir);
11238         LogMessage(" src_port %s dst_port %s ",
11239                 plist->pl_array[i].src_port,
11240                 plist->pl_array[i].dst_port );
11241         LogMessage(" content %d",
11242                 plist->pl_array[i].content);
11243         LogMessage(" uricontent %d",
11244                 plist->pl_array[i].uricontent);
11245         LogMessage(" }\n");
11246     }
11247 }
11248 #endif
11249 
port_list_free(port_list_t * plist)11250 static void port_list_free( port_list_t * plist)
11251 {
11252     int i;
11253     for(i=0;i<plist->pl_cnt;i++)
11254     {
11255         port_entry_free(&plist->pl_array[i]);
11256     }
11257     plist->pl_cnt = 0;
11258 }
11259 
11260 /* Finish processing/setup Port Tables */
finish_portlist_table(FastPatternConfig * fp,char * s,PortTable * pt)11261 static void finish_portlist_table(FastPatternConfig *fp, char *s, PortTable *pt)
11262 {
11263     PortTableSortUniqRules(pt);
11264 
11265     if( fpDetectGetDebugPrintRuleGroupsUnCompiled(fp) )
11266     {
11267         LogMessage("***\n***Port-Table : %s Ports/Rules-UnCompiled\n",s);
11268         PortTablePrintInputEx( pt, rule_index_map_print_index );
11269     }
11270 
11271     PortTableCompile( pt );
11272 
11273     if( fpDetectGetDebugPrintRuleGroupsCompiled(fp) )
11274     {
11275         LogMessage("***\n***Port-Table : %s Ports/Rules-Compiled\n",s);
11276         PortTablePrintCompiledEx( pt, rule_index_map_print_index );
11277         LogMessage("*** End of Compiled Group\n");
11278     }
11279 }
11280 
rule_index_map_print_index(int index,char * buf,int bufsize)11281 void rule_index_map_print_index( int index, char *buf, int bufsize )
11282 {
11283     if( index < ruleIndexMap->num_rules )
11284     {
11285         SnortSnprintfAppend(buf, bufsize, "%u:%u ",
11286                             ruleIndexMap->map[index].gid,
11287                             ruleIndexMap->map[index].sid);
11288     }
11289 }
11290 
PortTablesNew(void)11291 static rule_port_tables_t * PortTablesNew(void)
11292 {
11293     rule_port_tables_t *rpt =
11294         (rule_port_tables_t *)SnortAlloc(sizeof(rule_port_tables_t));
11295 
11296     /* No content rule objects */
11297     rpt->tcp_nocontent = PortObjectNew();
11298     if (rpt->tcp_nocontent == NULL)
11299         ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11300     PortObjectAddPortAny(rpt->tcp_nocontent);
11301 
11302     rpt->udp_nocontent = PortObjectNew();
11303     if (rpt->udp_nocontent == NULL)
11304         ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11305     PortObjectAddPortAny(rpt->udp_nocontent);
11306 
11307     rpt->icmp_nocontent = PortObjectNew();
11308     if (rpt->icmp_nocontent == NULL)
11309         ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11310     PortObjectAddPortAny(rpt->icmp_nocontent);
11311 
11312     rpt->ip_nocontent = PortObjectNew();
11313     if (rpt->ip_nocontent == NULL)
11314         ParseError("ParseRulesFile nocontent PortObjectNew() failed");
11315     PortObjectAddPortAny(rpt->ip_nocontent);
11316 
11317     /* Create the Any-Any Port Objects for each protocol */
11318     rpt->tcp_anyany = PortObjectNew();
11319     if (rpt->tcp_anyany == NULL)
11320         ParseError("ParseRulesFile tcp any-any PortObjectNew() failed");
11321     PortObjectAddPortAny(rpt->tcp_anyany);
11322 
11323     rpt->udp_anyany = PortObjectNew();
11324     if (rpt->udp_anyany == NULL)
11325         ParseError("ParseRulesFile udp any-any PortObjectNew() failed");
11326     PortObjectAddPortAny(rpt->udp_anyany);
11327 
11328     rpt->icmp_anyany = PortObjectNew();
11329     if (rpt->icmp_anyany == NULL)
11330         ParseError("ParseRulesFile icmp any-any PortObjectNew() failed");
11331     PortObjectAddPortAny(rpt->icmp_anyany);
11332 
11333     rpt->ip_anyany = PortObjectNew();
11334     if (rpt->ip_anyany == NULL)
11335         ParseError("ParseRulesFile ip PortObjectNew() failed");
11336     PortObjectAddPortAny(rpt->ip_anyany);
11337 
11338     /* Create the tcp Rules PortTables */
11339     rpt->tcp_src = PortTableNew();
11340     if (rpt->tcp_src == NULL)
11341         ParseError("ParseRulesFile tcp-src PortTableNew() failed");
11342 
11343     rpt->tcp_dst = PortTableNew();
11344     if (rpt->tcp_dst == NULL)
11345         ParseError("ParseRulesFile tcp-dst PortTableNew() failed");
11346 
11347     /* Create the udp Rules PortTables */
11348     rpt->udp_src = PortTableNew();
11349     if (rpt->udp_src == NULL)
11350         ParseError("ParseRulesFile udp-src PortTableNew() failed");
11351 
11352     rpt->udp_dst = PortTableNew();
11353     if (rpt->udp_dst == NULL)
11354         ParseError("ParseRulesFile udp-dst PortTableNew() failed");
11355 
11356     /* Create the icmp Rules PortTables */
11357     rpt->icmp_src = PortTableNew();
11358     if (rpt->icmp_src == NULL)
11359         ParseError("ParseRulesFile icmp-src PortTableNew() failed");
11360 
11361     rpt->icmp_dst = PortTableNew();
11362     if (rpt->icmp_dst == NULL)
11363         ParseError("ParseRulesFile icmp-dst PortTableNew() failed");
11364 
11365     /* Create the ip Rules PortTables */
11366     rpt->ip_src = PortTableNew();
11367     if (rpt->ip_src == NULL)
11368         ParseError("ParseRulesFile ip-src PortTableNew() failed");
11369 
11370     rpt->ip_dst = PortTableNew();
11371     if (rpt->ip_dst == NULL)
11372         ParseError("ParseRulesFile ip-dst PortTableNew() failed");
11373 
11374     /*
11375      * someday these could be read from snort.conf, something like...
11376      * 'config portlist: large-rule-count <val>'
11377      */
11378     rpt->tcp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11379     rpt->tcp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11380     rpt->udp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11381     rpt->udp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11382     rpt->icmp_src->pt_lrc= DEFAULT_LARGE_RULE_GROUP;
11383     rpt->icmp_dst->pt_lrc= DEFAULT_LARGE_RULE_GROUP;
11384     rpt->ip_src->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11385     rpt->ip_dst->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11386 
11387 #ifdef TARGET_BASED
11388     // if TARGET_BASED is not enabled, ensure that these
11389     // port tables are NULL.
11390     rpt->ns_tcp_src = NULL;
11391     rpt->ns_tcp_dst = NULL;
11392     rpt->ns_udp_src = NULL;
11393     rpt->ns_udp_dst = NULL;
11394     rpt->ns_icmp_src = NULL;
11395     rpt->ns_icmp_dst = NULL;
11396     rpt->ns_ip_src = NULL;
11397     rpt->ns_ip_dst = NULL;
11398 #endif
11399 
11400 #ifdef TARGET_BASED
11401     // Create NOSERVICE port tables
11402     rpt->ns_tcp_src = PortTableNew();
11403     if (rpt->ns_tcp_src == NULL)
11404         ParseError("ParseRulesFile tcp-src PortTableNew() failed");
11405 
11406     rpt->ns_tcp_dst = PortTableNew();
11407     if (rpt->ns_tcp_dst == NULL)
11408         ParseError("ParseRulesFile tcp-dst PortTableNew() failed");
11409 
11410     /* Create the udp Rules PortTables */
11411     rpt->ns_udp_src = PortTableNew();
11412     if (rpt->ns_udp_src == NULL)
11413         ParseError("ParseRulesFile udp-src PortTableNew() failed");
11414 
11415     rpt->ns_udp_dst = PortTableNew();
11416     if (rpt->ns_udp_dst == NULL)
11417         ParseError("ParseRulesFile udp-dst PortTableNew() failed");
11418 
11419     /* Create the icmp Rules PortTables */
11420     rpt->ns_icmp_src = PortTableNew();
11421     if (rpt->ns_icmp_src == NULL)
11422         ParseError("ParseRulesFile icmp-src PortTableNew() failed");
11423 
11424     rpt->ns_icmp_dst = PortTableNew();
11425     if (rpt->ns_icmp_dst == NULL)
11426         ParseError("ParseRulesFile icmp-dst PortTableNew() failed");
11427 
11428     /* Create the ip Rules PortTables */
11429     rpt->ns_ip_src = PortTableNew();
11430     if (rpt->ns_ip_src == NULL)
11431         ParseError("ParseRulesFile ip-src PortTableNew() failed");
11432 
11433     rpt->ns_ip_dst = PortTableNew();
11434     if (rpt->ns_ip_dst == NULL)
11435         ParseError("ParseRulesFile ip-dst PortTableNew() failed");
11436 
11437     rpt->ns_tcp_src->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11438     rpt->ns_tcp_dst->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11439     rpt->ns_udp_src->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11440     rpt->ns_udp_dst->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
11441     rpt->ns_icmp_src->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11442     rpt->ns_icmp_dst->pt_lrc = DEFAULT_LARGE_RULE_GROUP;
11443     rpt->ns_ip_src->pt_lrc   = DEFAULT_LARGE_RULE_GROUP;
11444     rpt->ns_ip_dst->pt_lrc   = DEFAULT_LARGE_RULE_GROUP;
11445 #endif // TARGET_BASED
11446 
11447     return rpt;
11448 }
11449 
PortTablesFinish(rule_port_tables_t * port_tables,FastPatternConfig * fp)11450 static void PortTablesFinish(rule_port_tables_t *port_tables, FastPatternConfig *fp)
11451 {
11452     /* TCP-SRC */
11453     if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11454     {
11455         LogMessage("*** TCP-Any-Any Port List\n");
11456         PortObjectPrintEx(port_tables->tcp_anyany,
11457                           rule_index_map_print_index);
11458     }
11459 
11460     finish_portlist_table(fp, "tcp src", port_tables->tcp_src);
11461     finish_portlist_table(fp, "tcp dst", port_tables->tcp_dst);
11462 
11463     /* UDP-SRC */
11464     if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11465     {
11466         LogMessage("*** UDP-Any-Any Port List\n");
11467         PortObjectPrintEx(port_tables->udp_anyany,
11468                           rule_index_map_print_index);
11469     }
11470 
11471     finish_portlist_table(fp, "udp src", port_tables->udp_src);
11472     finish_portlist_table(fp, "udp dst", port_tables->udp_dst);
11473 
11474     /* ICMP-SRC */
11475     if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11476     {
11477         LogMessage("*** ICMP-Any-Any Port List\n");
11478         PortObjectPrintEx(port_tables->icmp_anyany,
11479                           rule_index_map_print_index);
11480     }
11481 
11482     finish_portlist_table(fp, "icmp src", port_tables->icmp_src);
11483     finish_portlist_table(fp, "icmp dst", port_tables->icmp_dst);
11484 
11485     /* IP-SRC */
11486     if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
11487     {
11488         LogMessage("IP-Any-Any Port List\n");
11489         PortObjectPrintEx(port_tables->ip_anyany,
11490                           rule_index_map_print_index);
11491     }
11492 
11493     finish_portlist_table(fp, "ip src", port_tables->ip_src);
11494     finish_portlist_table(fp, "ip dst", port_tables->ip_dst);
11495 
11496 #ifdef TARGET_BASED
11497     // NOSERVICE Port Tables
11498     finish_portlist_table(fp, "tcp src noservice", port_tables->ns_tcp_src);
11499     finish_portlist_table(fp, "tcp dst noservice", port_tables->ns_tcp_dst);
11500 
11501     finish_portlist_table(fp, "udp src noservice", port_tables->ns_udp_src);
11502     finish_portlist_table(fp, "udp dst noservice", port_tables->ns_udp_dst);
11503 
11504     finish_portlist_table(fp, "icmp src noservice", port_tables->ns_icmp_src);
11505     finish_portlist_table(fp, "icmp dst noservice", port_tables->ns_icmp_dst);
11506 
11507     finish_portlist_table(fp, "ip src noservice", port_tables->ns_ip_src);
11508     finish_portlist_table(fp, "ip dst noservice", port_tables->ns_ip_dst);
11509 #endif // TARGET_BASED
11510 
11511     RuleListSortUniq(port_tables->tcp_anyany->rule_list);
11512     RuleListSortUniq(port_tables->udp_anyany->rule_list);
11513     RuleListSortUniq(port_tables->icmp_anyany->rule_list);
11514     RuleListSortUniq(port_tables->ip_anyany->rule_list);
11515     RuleListSortUniq(port_tables->tcp_nocontent->rule_list);
11516     RuleListSortUniq(port_tables->udp_nocontent->rule_list);
11517     RuleListSortUniq(port_tables->icmp_nocontent->rule_list);
11518     RuleListSortUniq(port_tables->ip_nocontent->rule_list);
11519 }
11520 
VarTablesFree(SnortConfig * sc)11521 void VarTablesFree(SnortConfig *sc)
11522 {
11523     tSfPolicyId i;
11524 
11525     if (sc == NULL)
11526         return;
11527 
11528     for (i = 0; i < sc->num_policies_allocated; i++)
11529     {
11530         SnortPolicy *p = sc->targeted_policies[i];
11531 
11532         if (p == NULL)
11533             continue;
11534 
11535         if (p->var_table != NULL)
11536         {
11537             DeleteVars(p->var_table);
11538             p->var_table = NULL;
11539         }
11540 
11541         if (p->ip_vartable != NULL)
11542         {
11543             sfvt_free_table(p->ip_vartable);
11544             p->ip_vartable = NULL;
11545         }
11546 
11547         if (p->portVarTable != NULL)
11548         {
11549             PortVarTableFree(p->portVarTable);
11550             p->portVarTable = NULL;
11551         }
11552 
11553         if (p->nonamePortVarTable != NULL)
11554         {
11555             PortTableFree(p->nonamePortVarTable);
11556             p->nonamePortVarTable = NULL;
11557         }
11558     }
11559 }
11560 
PortTablesFree(rule_port_tables_t * port_tables)11561 void PortTablesFree(rule_port_tables_t *port_tables)
11562 {
11563     if (port_tables == NULL)
11564         return;
11565 
11566     if (port_tables->tcp_src)
11567         PortTableFree(port_tables->tcp_src);
11568     if (port_tables->tcp_dst)
11569         PortTableFree(port_tables->tcp_dst);
11570     if (port_tables->udp_src)
11571         PortTableFree(port_tables->udp_src);
11572     if (port_tables->udp_dst)
11573         PortTableFree(port_tables->udp_dst);
11574     if (port_tables->icmp_src)
11575         PortTableFree(port_tables->icmp_src);
11576     if (port_tables->icmp_dst)
11577         PortTableFree(port_tables->icmp_dst);
11578     if (port_tables->ip_src)
11579         PortTableFree(port_tables->ip_src);
11580     if (port_tables->ip_dst)
11581         PortTableFree(port_tables->ip_dst);
11582 
11583     if (port_tables->tcp_anyany)
11584         PortObjectFree(port_tables->tcp_anyany);
11585     if (port_tables->udp_anyany)
11586         PortObjectFree(port_tables->udp_anyany);
11587     if (port_tables->icmp_anyany)
11588         PortObjectFree(port_tables->icmp_anyany);
11589     if (port_tables->ip_anyany)
11590         PortObjectFree(port_tables->ip_anyany);
11591 
11592     if (port_tables->tcp_nocontent)
11593         PortObjectFree(port_tables->tcp_nocontent);
11594     if (port_tables->udp_nocontent)
11595         PortObjectFree(port_tables->udp_nocontent);
11596     if (port_tables->icmp_nocontent)
11597         PortObjectFree(port_tables->icmp_nocontent);
11598     if (port_tables->ip_nocontent)
11599         PortObjectFree(port_tables->ip_nocontent);
11600 
11601 #ifdef TARGET_BASED
11602     if (port_tables->ns_tcp_src)
11603         PortTableFree(port_tables->ns_tcp_src);
11604     if (port_tables->ns_tcp_dst)
11605         PortTableFree(port_tables->ns_tcp_dst);
11606 
11607     if (port_tables->ns_udp_src)
11608         PortTableFree(port_tables->ns_udp_src);
11609     if (port_tables->ns_udp_dst)
11610         PortTableFree(port_tables->ns_udp_dst);
11611 
11612     if (port_tables->ns_icmp_src)
11613         PortTableFree(port_tables->ns_icmp_src);
11614     if (port_tables->ns_icmp_dst)
11615         PortTableFree(port_tables->ns_icmp_dst);
11616 
11617     if (port_tables->ns_ip_src)
11618         PortTableFree(port_tables->ns_ip_src);
11619     if (port_tables->ns_ip_dst)
11620         PortTableFree(port_tables->ns_ip_dst);
11621 #endif
11622 
11623     free(port_tables);
11624 }
11625 
11626 /****************************************************************************
11627  *
11628  * Function: CreateRuleType
11629  *
11630  * Purpose: Creates a new type of rule and adds it to the end of the rule list
11631  *
11632  * Arguments: name = name of this rule type
11633  *                       mode = the mode for this rule type
11634  *                   rval = return value for this rule type (for detect events)
11635  *                       head = list head to use (or NULL to create a new one)
11636  *
11637  * Returns: the ListHead for the rule type
11638  *
11639  ***************************************************************************/
CreateRuleType(SnortConfig * sc,char * name,RuleType mode,int rval,ListHead * head)11640 static ListHead * CreateRuleType(SnortConfig *sc, char *name,
11641                                  RuleType mode, int rval, ListHead *head)
11642 {
11643     RuleListNode *node;
11644     int evalIndex = 0;
11645 
11646     if (sc == NULL)
11647         return NULL;
11648 
11649     node = (RuleListNode *)SnortAlloc(sizeof(RuleListNode));
11650 
11651     /* If this is the first rule list node, then we need to
11652      * create a new list. */
11653     if (sc->rule_lists == NULL)
11654     {
11655         sc->rule_lists = node;
11656     }
11657     else
11658     {
11659         RuleListNode *tmp = sc->rule_lists;
11660         RuleListNode *last;
11661 
11662         do
11663         {
11664             /* We do not allow multiple rules types with the same name. */
11665             if (strcasecmp(tmp->name, name) == 0)
11666             {
11667                 free(node);
11668                 return NULL;
11669             }
11670 
11671             evalIndex++;
11672             last = tmp;
11673             tmp = tmp->next;
11674 
11675         } while (tmp != NULL);
11676 
11677         last->next = node;
11678     }
11679 
11680     /* User defined rule type so we need to create a list head for it */
11681     if (head == NULL)
11682     {
11683         node->RuleList = (ListHead *)SnortAlloc(sizeof(ListHead));
11684     }
11685     else
11686     {
11687         /* Our default rules already have list heads */
11688         node->RuleList = head;
11689     }
11690 
11691     node->RuleList->ruleListNode = node;
11692     node->mode = mode;
11693     node->rval = rval;
11694     node->name = SnortStrdup(name);
11695     node->evalIndex = evalIndex;
11696 
11697     sc->evalOrder[node->mode] =  evalIndex;
11698     sc->num_rule_types++;
11699 
11700     return node->RuleList;
11701 }
11702 
OtnInit(SnortConfig * sc)11703 static void OtnInit(SnortConfig *sc)
11704 {
11705     if (sc == NULL)
11706         return;
11707 
11708     /* Don't initialize this more than once */
11709     if ((sc->so_rule_otn_map != NULL) || (sc->otn_map != NULL))
11710         return;
11711 
11712     /* Init sid-gid -> otn map */
11713     sc->so_rule_otn_map = SoRuleOtnLookupNew();
11714     if (sc->so_rule_otn_map == NULL)
11715          ParseError("ParseRulesFile so_otn_map sfghash_new failed.\n");
11716 
11717     /* Init sid-gid -> otn map */
11718     sc->otn_map = OtnLookupNew();
11719     if (sc->otn_map == NULL)
11720         ParseError("ParseRulesFile otn_map sfghash_new failed.\n");
11721 }
11722 
11723 #ifndef SOURCEFIRE
11724 #define IFACE_VARS_MAX 128
11725 typedef struct iface_var
11726 {
11727     char name[128];
11728     uint32_t net;
11729     uint32_t netmask;
11730 } iface_var_t;
11731 
11732 /****************************************************************************
11733  *
11734  * Function  : DefineAllIfaceVars()
11735  * Purpose   : Find all up interfaces and define iface_ADDRESS vars for them
11736  * Arguments : none
11737  * Returns   : void function
11738  *
11739  ****************************************************************************/
DefineAllIfaceVars(SnortConfig * sc)11740 static void DefineAllIfaceVars(SnortConfig *sc)
11741 {
11742     /* Cache retrieved devs so if user is running with dropped privs and
11743      * does a reload, we can use previous values */
11744     static int num_vars = 0;
11745     /* Should be more than enough to cover the number of
11746      * interfaces on a machine */
11747     static iface_var_t iface_vars[IFACE_VARS_MAX];
11748 
11749     if (num_vars > 0)
11750     {
11751         int i;
11752 
11753         for (i = 0; i < num_vars; i++)
11754         {
11755             DefineIfaceVar(sc, iface_vars[i].name,
11756                     (uint8_t *)&iface_vars[i].net,
11757                     (uint8_t *)&iface_vars[i].netmask);
11758         }
11759     }
11760     else
11761     {
11762         char errbuf[PCAP_ERRBUF_SIZE];
11763         pcap_if_t *alldevs;
11764         pcap_if_t *dev;
11765         bpf_u_int32 net, netmask;
11766 #ifdef WIN32
11767         int i = 1;
11768 #endif
11769 
11770         if (pcap_findalldevs(&alldevs, errbuf) == -1)
11771             return;
11772 
11773         for (dev = alldevs; dev != NULL; dev = dev->next)
11774         {
11775             if (pcap_lookupnet(dev->name, &net, &netmask, errbuf) == 0)
11776             {
11777                 /* We've hit the maximum variables we can cache */
11778                 if (num_vars >= IFACE_VARS_MAX)
11779                     break;
11780 #ifdef WIN32
11781                 /* For windows, define var as the index that it will be */
11782                 SnortSnprintf(iface_vars[num_vars].name,
11783                         sizeof(iface_vars[num_vars].name), "%d", i);
11784 #else
11785                 SnortSnprintf(iface_vars[num_vars].name,
11786                         sizeof(iface_vars[num_vars].name), "%s", dev->name);
11787 #endif
11788                 DefineIfaceVar(sc, iface_vars[num_vars].name,
11789                         (uint8_t *)&net,
11790                         (uint8_t *)&netmask);
11791 
11792                 iface_vars[num_vars].net = net;
11793                 iface_vars[num_vars].netmask = netmask;
11794                 num_vars++;
11795             }
11796 
11797 #ifdef WIN32
11798             i++;
11799 #endif
11800         }
11801 
11802         pcap_freealldevs(alldevs);
11803     }
11804 }
11805 
11806 /****************************************************************************
11807  *
11808  * Function  : DefineIfaceVar()
11809  * Purpose   : Assign network address and network mask to IFACE_ADDR_VARNAME
11810  *             variable.
11811  * Arguments : interface name (string) netaddress and netmask (4 octets each)
11812  * Returns   : void function
11813  *
11814  ****************************************************************************/
DefineIfaceVar(SnortConfig * sc,char * iname,uint8_t * network,uint8_t * netmask)11815 static void DefineIfaceVar(SnortConfig *sc, char *iname, uint8_t *network, uint8_t *netmask)
11816 {
11817     char valbuf[32];
11818     char varbuf[BUFSIZ];
11819 
11820     if ((network == NULL) || (*network == 0))
11821         return;
11822 
11823     SnortSnprintf(varbuf, BUFSIZ, "%s_ADDRESS", iname);
11824 
11825     SnortSnprintf(valbuf, 32, "%d.%d.%d.%d/%d.%d.%d.%d",
11826             network[0] & 0xff, network[1] & 0xff, network[2] & 0xff,
11827             network[3] & 0xff, netmask[0] & 0xff, netmask[1] & 0xff,
11828             netmask[2] & 0xff, netmask[3] & 0xff);
11829 
11830     VarDefine(sc, varbuf, valbuf);
11831 }
11832 #endif
11833 
PrintRuleOrder(RuleListNode * rule_lists)11834 void PrintRuleOrder(RuleListNode *rule_lists)
11835 {
11836     printRuleListOrder(rule_lists);
11837 }
11838 
11839 /****************************************************************************
11840  *
11841  * Function: OrderRuleLists
11842  *
11843  * Purpose: Orders the rule lists into the specefied order.
11844  *
11845  * Returns: void function
11846  *
11847  ***************************************************************************/
OrderRuleLists(SnortConfig * sc,char * order)11848 void OrderRuleLists(SnortConfig *sc, char *order)
11849 {
11850     int i;
11851     int evalIndex = 0;
11852     RuleListNode *ordered_list = NULL;
11853     RuleListNode *prev;
11854     RuleListNode *node;
11855     char **toks;
11856     int num_toks;
11857 
11858     toks = mSplit(order, " \t", 0, &num_toks, 0);
11859 
11860     for( i = 0; i < num_toks; i++ )
11861     {
11862         prev = NULL;
11863         node = sc->rule_lists;
11864 
11865         while (node != NULL)
11866         {
11867             if (strcmp(toks[i], node->name) == 0)
11868             {
11869                 if (prev == NULL)
11870                     sc->rule_lists = node->next;
11871                 else
11872                     prev->next = node->next;
11873 
11874                 /* Add node to ordered list */
11875                 ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++);
11876                 sc->evalOrder[node->mode] =  evalIndex;
11877 
11878                 break;
11879             }
11880             else
11881             {
11882                 prev = node;
11883                 node = node->next;
11884             }
11885         }
11886 
11887         if( node == NULL )
11888         {
11889             ParseError("Ruletype \"%s\" does not exist or "
11890                        "has already been ordered.", toks[i]);
11891         }
11892     }
11893 
11894     mSplitFree(&toks, num_toks);
11895 
11896     /* anything left in the rule lists needs to be moved to the ordered lists */
11897     while (sc->rule_lists != NULL)
11898     {
11899         node = sc->rule_lists;
11900         sc->rule_lists = node->next;
11901         /* Add node to ordered list */
11902         ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++);
11903         sc->evalOrder[node->mode] =  evalIndex;
11904     }
11905 
11906     /* set the rulelists to the ordered list */
11907     sc->rule_lists = ordered_list;
11908 }
11909 
addNodeToOrderedList(RuleListNode * ordered_list,RuleListNode * node,int evalIndex)11910 static RuleListNode *addNodeToOrderedList(RuleListNode *ordered_list,
11911                                           RuleListNode *node, int evalIndex)
11912 {
11913     RuleListNode *prev;
11914 
11915     prev = ordered_list;
11916 
11917     /* set the eval order for this rule set */
11918     node->evalIndex = evalIndex;
11919 
11920     if(!prev)
11921     {
11922         ordered_list = node;
11923     }
11924     else
11925     {
11926         while(prev->next)
11927             prev = prev->next;
11928         prev->next = node;
11929     }
11930 
11931     node->next = NULL;
11932 
11933     return ordered_list;
11934 }
11935 
printRuleListOrder(RuleListNode * node)11936 static void printRuleListOrder(RuleListNode * node)
11937 {
11938     char buf[STD_BUF];
11939     RuleListNode *first_node = node;
11940 
11941     SnortSnprintf(buf, STD_BUF, "Rule application order: ");
11942 
11943     while( node != NULL )
11944     {
11945         SnortSnprintfAppend(buf, STD_BUF, "%s%s",
11946                             node == first_node ? "" : "->", node->name);
11947 
11948         node = node->next;
11949     }
11950 
11951     LogMessage("%s\n", buf);
11952 }
11953 
ParseError(const char * format,...)11954 NORETURN void ParseError(const char *format, ...)
11955 {
11956     char buf[STD_BUF+1];
11957     va_list ap;
11958 
11959     va_start(ap, format);
11960     vsnprintf(buf, STD_BUF, format, ap);
11961     va_end(ap);
11962 
11963     buf[STD_BUF] = '\0';
11964 
11965     if (file_name != NULL)
11966         FatalError("%s(%d) %s\n", file_name, file_line, buf);
11967     else
11968         FatalError("%s\n", buf);
11969 }
11970 
ParseWarning(const char * format,...)11971 void ParseWarning(const char *format, ...)
11972 {
11973     char buf[STD_BUF+1];
11974     va_list ap;
11975 
11976     va_start(ap, format);
11977     vsnprintf(buf, STD_BUF, format, ap);
11978     va_end(ap);
11979 
11980     buf[STD_BUF] = '\0';
11981 
11982     if (file_name != NULL)
11983         LogMessage("WARNING: %s(%d) %s\n", file_name, file_line, buf);
11984     else
11985         LogMessage("%s\n", buf);
11986 }
11987 
ParseMessage(const char * format,...)11988 void ParseMessage(const char *format, ...)
11989 {
11990     char buf[STD_BUF+1];
11991     va_list ap;
11992 
11993     va_start(ap, format);
11994     vsnprintf(buf, STD_BUF, format, ap);
11995     va_end(ap);
11996 
11997     buf[STD_BUF] = '\0';
11998 
11999     if (file_name != NULL)
12000         LogMessage("%s(%d) %s\n", file_name, file_line, buf);
12001     else
12002         LogMessage("%s\n", buf);
12003 }
12004 
12005 typedef struct _RuleTreeNodeKey
12006 {
12007     RuleTreeNode *rtn;
12008     tSfPolicyId policyId;
12009 } RuleTreeNodeKey;
12010 
12011 // RuleTreeNode *getRtnFromOtn() made in line
12012 
12013 /**Delete rtn from OTN.
12014  *
12015  * @param otn pointer to structure OptTreeNode.
12016  * @param policyId policy id
12017  *
12018  * @return pointer to deleted RTN, NULL otherwise.
12019  */
deleteRtnFromOtn(SnortConfig * sc,OptTreeNode * otn,tSfPolicyId policyId)12020 RuleTreeNode * deleteRtnFromOtn(
12021         SnortConfig *sc,
12022         OptTreeNode *otn,
12023         tSfPolicyId policyId
12024         )
12025 {
12026     RuleTreeNode *rtn = NULL;
12027 
12028     if (otn->proto_nodes
12029             && (otn->proto_node_num >= (policyId+1)))
12030     {
12031         rtn = getRtnFromOtn(otn, policyId);
12032         otn->proto_nodes[policyId] = NULL;
12033 
12034         if (rtn)
12035         {
12036             RuleTreeNodeKey key;
12037             key.policyId = policyId;
12038             key.rtn = rtn;
12039 
12040             if (sc && sc->rtn_hash_table)
12041             {
12042                 sfxhash_remove(sc->rtn_hash_table, &key);
12043             }
12044         }
12045 
12046         return rtn;
12047     }
12048 
12049     return NULL;
12050 }
12051 
rtn_hash_func(SFHASHFCN * p,unsigned char * k,int n)12052 uint32_t rtn_hash_func(SFHASHFCN *p, unsigned char *k, int n)
12053 {
12054     uint32_t a,b,c;
12055     RuleTreeNodeKey* rtnk = (RuleTreeNodeKey *)k;
12056     RuleTreeNode *rtn = rtnk->rtn;
12057 
12058     a = rtn->type;
12059     b = rtn->flags;
12060     c = (uint32_t)(uintptr_t)rtn->listhead;
12061 
12062     mix(a,b,c);
12063 
12064     a += (uint32_t)(uintptr_t)rtn->src_portobject;
12065     b += (uint32_t)(uintptr_t)rtn->dst_portobject;
12066     c += (uint32_t)(uintptr_t)rtnk->policyId;
12067 
12068     final(a,b,c);
12069 
12070     return c;
12071 }
12072 
rtn_compare_func(const void * k1,const void * k2,size_t n)12073 int rtn_compare_func(const void *k1, const void *k2, size_t n)
12074 {
12075     RuleTreeNodeKey* rtnk1 = (RuleTreeNodeKey *)k1;
12076     RuleTreeNodeKey* rtnk2 = (RuleTreeNodeKey *)k2;
12077 
12078     if (!rtnk1 || !rtnk2)
12079         return 1;
12080 
12081     if (rtnk1->policyId != rtnk2->policyId)
12082         return 1;
12083 
12084     if (TestHeader( rtnk1->rtn, rtnk2->rtn))
12085         return 0;
12086     else
12087         return 1;
12088 }
12089 
12090 /**Add RTN to OTN for a particular OTN.
12091  * @param otn pointer to structure OptTreeNode.
12092  * @param policyId policy id
12093  * @param rtn pointer to RuleTreeNode structure
12094  *
12095  * @return 0 if successful,
12096  *         -ve otherwise
12097  */
addRtnToOtn(SnortConfig * sc,OptTreeNode * otn,tSfPolicyId policyId,RuleTreeNode * rtn)12098 int addRtnToOtn(
12099         SnortConfig *sc,
12100         OptTreeNode *otn,
12101         tSfPolicyId policyId,
12102         RuleTreeNode *rtn
12103         )
12104 {
12105     RuleTreeNodeKey key;
12106 
12107     if (otn->proto_node_num <= policyId)
12108     {
12109         /* realloc the list, initialize missing elements to 0 and add
12110          * policyId */
12111         RuleTreeNode **tmpNodeArray;
12112         unsigned int numNodes = (policyId + 1);
12113 
12114         tmpNodeArray = SnortAlloc(sizeof(RuleTreeNode *) * numNodes);
12115 
12116         /* copy original contents, the remaining elements are already
12117          * zeroed out by snortAlloc */
12118         if (otn->proto_nodes)
12119         {
12120             memcpy(tmpNodeArray, otn->proto_nodes,
12121                 sizeof(RuleTreeNode *) * otn->proto_node_num);
12122             free(otn->proto_nodes);
12123         }
12124 
12125         otn->proto_node_num = numNodes;
12126         otn->proto_nodes = tmpNodeArray;
12127     }
12128 
12129     //add policyId
12130     if (otn->proto_nodes[policyId])
12131     {
12132         DestroyRuleTreeNode(rtn);
12133         return -1;
12134     }
12135 
12136     otn->proto_nodes[policyId] = rtn;
12137 
12138     // Optimized for parsing only, this check avoids adding run time rtn
12139     if (!sc)
12140         return 0;
12141 
12142     if (!sc->rtn_hash_table)
12143     {
12144         sc->rtn_hash_table = sfxhash_new(10000, sizeof(RuleTreeNodeKey), 0, 0, 0, NULL, NULL, 1);
12145 
12146         if (sc->rtn_hash_table == NULL)
12147             FatalError("Failed to create rule tree node hash table");
12148 
12149         sfxhash_set_keyops(sc->rtn_hash_table, rtn_hash_func, rtn_compare_func);
12150 
12151     }
12152 
12153     key.policyId = policyId;
12154     key.rtn = rtn;
12155     sfxhash_add(sc->rtn_hash_table, &key, rtn);
12156 
12157     return 0; //success
12158 }
12159 
12160 // the presence of ip lists exceeds mSplit's one-level parsing
12161 // so we transform rule string into something that mSplit can
12162 // handle by changing ',' to c outside ip lists.
12163 // we also strip the leading keyword.
FixSeparators(char * rule,char c,const char * err)12164 char* FixSeparators (char* rule, char c, const char* err)
12165 {
12166     int list = 0;
12167     char* p = strchr(rule, c);
12168 
12169     if ( p && err )
12170     {
12171         FatalError("%s(%d) => %s: '%c' not allowed in argument\n",
12172             file_name, file_line, err, c);
12173     }
12174     while ( isspace((int)*rule) ) rule++;
12175 
12176     p = rule;
12177 
12178     while ( *p ) {
12179         if ( *p == '[' ) list++;
12180         else if ( *p == ']' ) list--;
12181         else if ( *p == ',' && !list ) *p = c;
12182         p++;
12183     }
12184     return rule;
12185 }
12186 
GetNameValue(char * arg,char ** nam,char ** val,const char * err)12187 void GetNameValue (char* arg, char** nam, char** val, const char* err)
12188 {
12189     while ( isspace((int)*arg) ) arg++;
12190     *nam = arg;
12191 
12192     while ( *arg && !isspace((int)*arg) ) arg++;
12193     if ( *arg ) *arg++ = '\0';
12194     *val = arg;
12195 
12196     if ( err && !**val )
12197     {
12198         FatalError("%s(%d) => %s: name value pair expected: %s\n",
12199             file_name, file_line, err, *nam);
12200     }
12201 }
12202 
IntegrityCheckRules(SnortConfig * sc)12203 static void IntegrityCheckRules(SnortConfig *sc)
12204 {
12205     OptFpList *ofl_idx = NULL;
12206     int opt_func_count;
12207     SFGHASH_NODE *hashNode = NULL;
12208     OptTreeNode *otn  = NULL;
12209     tSfPolicyId policyId = 0;
12210     RuleTreeNode *rtn = NULL;
12211 
12212     for (hashNode = sfghash_findfirst(sc->otn_map);
12213             hashNode;
12214             hashNode = sfghash_findnext(sc->otn_map))
12215     {
12216         otn = (OptTreeNode *)hashNode->data;
12217 
12218         for (policyId = 0;
12219                 policyId < otn->proto_node_num;
12220                 policyId++)
12221         {
12222             rtn = getRtnFromOtn(otn, policyId);
12223 
12224             if (!rtn)
12225             {
12226                 continue;
12227             }
12228 
12229             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
12230                     || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
12231             {
12232                 //do operation
12233                 ofl_idx = otn->opt_func;
12234                 opt_func_count = 0;
12235 
12236                 while(ofl_idx != NULL)
12237                 {
12238                     opt_func_count++;
12239                     //DEBUG_WRAP(DebugMessage(DEBUG_DETECT, "%p->",ofl_idx->OptTestFunc););
12240                     ofl_idx = ofl_idx->next;
12241                 }
12242 
12243                 if(opt_func_count == 0)
12244                 {
12245                     ParseError("Zero Length OTN List\n");
12246                 }
12247                 //DEBUG_WRAP(DebugMessage(DEBUG_DETECT,"\n"););
12248 
12249             }
12250         }
12251     }
12252 
12253     //DEBUG_WRAP(DebugMessage(DEBUG_DETECT, "OK\n"););
12254 }
12255 
12256 /**returns matched header node.
12257 */
findHeadNode(SnortConfig * sc,RuleTreeNode * testNode,tSfPolicyId policyId)12258 static RuleTreeNode * findHeadNode(SnortConfig *sc, RuleTreeNode *testNode,
12259                                    tSfPolicyId policyId)
12260 {
12261     if (sc->rtn_hash_table)
12262     {
12263         RuleTreeNodeKey key;
12264         key.policyId = policyId;
12265         key.rtn = testNode;
12266         return ((RuleTreeNode *)sfxhash_find(sc->rtn_hash_table, &key));
12267     }
12268     else
12269         return NULL;
12270 }
12271 
configOptsPrint()12272 void configOptsPrint()
12273 {
12274     int i;
12275 
12276     printf("Global policy only options\n");
12277     for (i = 0; config_opts[i].name != NULL; i++)
12278     {
12279         if(config_opts[i].default_policy_only )
12280         {
12281             printf("\t%s,\t%s\n", config_opts[i].name, config_opts[i].only_once ? "Once":"");
12282         }
12283     }
12284 
12285     printf("\nPolicy Specific options\n");
12286     for (i = 0; config_opts[i].name != NULL; i++)
12287     {
12288         if(config_opts[i].default_policy_only == 0)
12289         {
12290             printf("\t%s,\t%s\n", config_opts[i].name, config_opts[i].only_once ? "Once":"");
12291         }
12292     }
12293 }
12294 
SnortPolicyNew(void)12295 SnortPolicy * SnortPolicyNew(void)
12296 {
12297     SnortPolicy *pPolicy = (SnortPolicy *)SnortAlloc(sizeof(SnortPolicy));
12298 
12299     if (pPolicy)
12300     {
12301         // minimum possible (allows all but errors to pass by default)
12302         pPolicy->min_ttl = 1;
12303 
12304 #ifdef NORMALIZER
12305         pPolicy->new_ttl = 5;
12306 #endif
12307 
12308         /* Turn on all decoder alerts by default except for oversized alert.
12309          * Useful for bug reports ... */
12310         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__DEFAULT;
12311         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_EXP_OPT;
12312         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OBS_OPT;
12313         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_TTCP_OPT;
12314         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OPT_ANOMALY;
12315         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IP_OPT_ANOMALY;
12316         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
12317         pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BSD_ICMP_FRAG;
12318 
12319         pPolicy->decoder_drop_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG;
12320 
12321         pPolicy->checksum_flags = CHECKSUM_FLAG__ALL;
12322 
12323         memset( pPolicy->pp_enabled, 0, sizeof( PreprocEnableMask ) * MAX_PORTS );
12324     }
12325 
12326     return pPolicy;
12327 }
12328 
SnortPolicyFree(SnortPolicy * pPolicy)12329 void SnortPolicyFree(SnortPolicy *pPolicy)
12330 {
12331     if (pPolicy == NULL)
12332         return;
12333 
12334     if (pPolicy->policy_version != NULL)
12335         free(pPolicy->policy_version);
12336 
12337 #ifdef TARGET_BASED
12338     if (pPolicy->target_based_config.args != NULL)
12339     {
12340         free(pPolicy->target_based_config.args);
12341         if (pPolicy->target_based_config.file_name != NULL)
12342             free(pPolicy->target_based_config.file_name);
12343     }
12344 #endif
12345 }
12346 
12347 
12348 /* Parse a boolean argument, with many ways to say "on" or "off".
12349    Arguments:
12350      char * arg => string argument to parse
12351    Returns:
12352      1: Parsed a positive argument ("1", "on", "yes", "enable", "true")
12353      0: Parsed a negative argument ("0", "off", "no", "disable", "false")
12354     -1: Error
12355 */
ParseBool(char * arg)12356 int ParseBool(char *arg)
12357 {
12358     if (arg == NULL)
12359         return -1;
12360 
12361     /* Trim leading whitespace */
12362     while (isspace(*arg))
12363         arg++;
12364 
12365     if ( (strcasecmp(arg, "1") == 0) ||
12366          (strcasecmp(arg, "on") == 0) ||
12367          (strcasecmp(arg, "yes") == 0) ||
12368          (strcasecmp(arg, "enable") == 0) ||
12369          (strcasecmp(arg, "true") == 0) )
12370         return 1;
12371 
12372     if ( (strcasecmp(arg, "0") == 0) ||
12373          (strcasecmp(arg, "off") == 0) ||
12374          (strcasecmp(arg, "no") == 0) ||
12375          (strcasecmp(arg, "disable") == 0) ||
12376          (strcasecmp(arg, "false") == 0) )
12377         return 0;
12378 
12379     /* Other values are invalid! */
12380     return -1;
12381 }
12382