"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/parser.c" (16 Oct 2020, 372548 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "parser.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /* $Id$ */
    2 /*
    3 ** Copyright (C) 2014-2020 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 
   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().
  840 static inline int ScKeepDropRules (SnortConfig * sc)
  841 {
  842     return ( ScIpsInlineModeNewConf(sc) || ScAdapterInlineModeNewConf(sc) || ScTreatDropAsIgnoreNewConf(sc) );
  843 }
  844 
  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  ***************************************************************************/
  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 
  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 
 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 
 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
 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  ***************************************************************************/
 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  */
 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 */
 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 */
 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 */
 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  */
 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  */
 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  ***************************************************************************/
 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  ***************************************************************************/
 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  ***************************************************************************/
 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  ***************************************************************************/
 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  ***************************************************************************/
 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  ***************************************************************************/
 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 
 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 
 2157     if (sc == NULL)
 2158         return;
 2159 
 2160     for (i = 0; i < sc->num_policies_allocated; i++)
 2161     {
 2162         PreprocConfig *config;
 2163 
 2164         setParserPolicy(sc, i);
 2165 
 2166         if (sc->targeted_policies[i] == NULL)
 2167             continue;
 2168 
 2169         config = sc->targeted_policies[i]->preproc_configs;
 2170 
 2171         for (; config != NULL; config = config->next)
 2172         {
 2173             PreprocConfigFuncNode *node;
 2174 
 2175             if (config->configured)
 2176                 continue;
 2177 
 2178             file_name = config->file_name;
 2179             file_line = config->file_line;
 2180 
 2181             node = GetPreprocConfig(config->keyword);
 2182             if ((node == NULL) && configure_dynamic)
 2183                 ParseError("Unknown preprocessor: \"%s\".", config->keyword);
 2184 
 2185             if (node != NULL)
 2186             {
 2187 #ifdef SNORT_RELOAD
 2188                 if (node->initialized)
 2189                 {
 2190                     if (node->reload_func != NULL)
 2191                     {
 2192                         PreprocessorSwapData *swapData;
 2193                         PreprocessorSwapData **swapDataNode;
 2194 
 2195                         for (swapData = sc->preprocSwapData;
 2196                              swapData && swapData->preprocNode != node;
 2197                              swapData = swapData->next);
 2198                         if (!swapData)
 2199                         {
 2200                             swapData = (PreprocessorSwapData *)SnortAlloc(sizeof(*swapData));
 2201                             swapData->preprocNode = node;
 2202                             for (swapDataNode = &sc->preprocSwapData; *swapDataNode; swapDataNode = &(*swapDataNode)->next);
 2203                             *swapDataNode = swapData;
 2204                         }
 2205                         node->reload_func(sc, config->opts, &swapData->data);
 2206                         if (!sc->streamReloadConfig && node->keyword && strcmp(node->keyword, "stream5_global") == 0)
 2207                             sc->streamReloadConfig = swapData->data;
 2208                     }
 2209                 }
 2210                 else
 2211 #endif
 2212                 {
 2213                     if (node->config_func != NULL)
 2214                         node->config_func(sc, config->opts);
 2215                 }
 2216 
 2217                 config->configured = 1;
 2218             }
 2219         }
 2220     }
 2221 
 2222 #ifdef SNORT_RELOAD
 2223     for (i = 0; i < sc->num_policies_allocated; i++)
 2224     {
 2225         PreprocConfig *config;
 2226 
 2227         setParserPolicy(sc, i);
 2228 
 2229         if (sc->targeted_policies[i] == NULL)
 2230             continue;
 2231 
 2232         setParserPolicy(sc, i);
 2233 
 2234         config = sc->targeted_policies[i]->preproc_configs;
 2235 
 2236         /* Set all configured preprocessors to intialized */
 2237         for (; config != NULL; config = config->next)
 2238         {
 2239             if (config->configured)
 2240             {
 2241                 PreprocConfigFuncNode *node = GetPreprocConfig(config->keyword);
 2242 
 2243                 if (node != NULL)
 2244                     node->initialized = 1;
 2245             }
 2246         }
 2247     }
 2248 #endif
 2249 
 2250     /* Reset these since we're done with configuring dynamic preprocessors */
 2251     file_name = stored_file_name;
 2252     file_line = stored_file_line;
 2253 }
 2254 
 2255 #ifdef SIDE_CHANNEL
 2256 
 2257 static void ParseSideChannelModule(SnortConfig *sc, SnortPolicy *p, char *args)
 2258 {
 2259     char **toks;
 2260     int num_toks;
 2261     char *opts = NULL;
 2262     SideChannelModuleConfig *config;
 2263 
 2264     toks = mSplit(args, ":", 2, &num_toks, '\\');
 2265 
 2266     if (num_toks > 1)
 2267         opts = toks[1];
 2268 
 2269     config = (SideChannelModuleConfig *) SnortAlloc(sizeof(SideChannelModuleConfig));
 2270 
 2271     if (sc->side_channel_config.module_configs == NULL)
 2272     {
 2273         sc->side_channel_config.module_configs = config;
 2274     }
 2275     else
 2276     {
 2277         SideChannelModuleConfig *tmp = sc->side_channel_config.module_configs;
 2278 
 2279         while (tmp->next != NULL)
 2280             tmp = tmp->next;
 2281 
 2282         tmp->next = config;
 2283     }
 2284 
 2285     config->keyword = SnortStrdup(toks[0]);
 2286     if (opts != NULL)
 2287         config->opts = SnortStrdup(opts);
 2288 
 2289     /* This could come from parsing the command line (No, actually, I don't think that it could...) */
 2290     if (file_name != NULL)
 2291     {
 2292         config->file_name = SnortStrdup(file_name);
 2293         config->file_line = file_line;
 2294     }
 2295 
 2296     mSplitFree(&toks, num_toks);
 2297 }
 2298 
 2299 void ConfigureSideChannelModules(SnortConfig *sc)
 2300 {
 2301     SideChannelModuleConfig *config;
 2302     char *stored_file_name = file_name;
 2303     int stored_file_line = file_line;
 2304     int rval;
 2305 
 2306     for (config = sc->side_channel_config.module_configs; config != NULL; config = config->next)
 2307     {
 2308         file_name = config->file_name;
 2309         file_line = config->file_line;
 2310 
 2311         rval = ConfigureSideChannelModule(config->keyword, config->opts);
 2312         if (rval == -ENOENT)
 2313             ParseError("Unknown side channel plugin: \"%s\"", config->keyword);
 2314     }
 2315 
 2316     /* Reset these since we're done with configuring side channels */
 2317     file_name = stored_file_name;
 2318     file_line = stored_file_line;
 2319 }
 2320 
 2321 #endif /* SIDE_CHANNEL */
 2322 
 2323 /* Parses standalone rate_filter configuration.
 2324  *
 2325  * Parses rate_filter configuration in the following format and populates internal
 2326  * structures:
 2327  * @code
 2328  * rate_filter gid <gen-id>, sid <sig-id>,
 2329  *     track <by_src|by_dst|by_rule>,
 2330  *     count <c> , seconds <s>,
 2331  *     new_action <alert|drop|pass|drop|reject|sdrop>,
 2332  *     timeout <t> [, apply_to <cidr>];
 2333  * @endcode
 2334  * And then adds it into pContext.
 2335  *
 2336  * @param rule - string containing rate_filter configuration from snort.conf file.
 2337  *
 2338  * @returns void
 2339 */
 2340 static void ParseRateFilter(SnortConfig *sc, SnortPolicy *p, char *args)
 2341 {
 2342     char **toks;
 2343     int num_toks;
 2344     int count_flag = 0;
 2345     int new_action_flag = 0;
 2346     int timeout_flag = 0;
 2347     int seconds_flag = 0;
 2348     int tracking_flag = 0;
 2349     int genid_flag = 0;
 2350     int sigid_flag = 0;
 2351     int apply_flag = 0;
 2352     int i;
 2353     const char* ERR_KEY = "rate_filter";
 2354 
 2355     tSFRFConfigNode thdx;
 2356 
 2357     memset( &thdx, 0, sizeof(thdx) );
 2358 
 2359     /* Potential IP list might be present so we can't split on commas
 2360      * Change commas to semi-colons */
 2361     args = FixSeparators(args, ';', "rate_filter");
 2362     toks = mSplit(args, ";", 0, &num_toks, 0);  /* get rule option pairs */
 2363 
 2364     for (i = 0; i < num_toks; i++)
 2365     {
 2366         char **pairs;
 2367         int num_pairs;
 2368 
 2369         pairs = mSplit(toks[i], " \t", 2, &num_pairs, 0);  /* get rule option pairs */
 2370 
 2371         if (num_pairs != 2)
 2372         {
 2373             ParseError(ERR_NOT_PAIRED);
 2374         }
 2375 
 2376         if (!strcasecmp(pairs[0], "gen_id"))
 2377         {
 2378             if ( genid_flag++ )
 2379             {
 2380                 ParseError(ERR_EXTRA_OPTION);
 2381             }
 2382 
 2383             thdx.gid = xatou(pairs[1], "rate_filter: gen_id");
 2384         }
 2385         else if (!strcasecmp(pairs[0], "sig_id"))
 2386         {
 2387             if ( sigid_flag++ )
 2388             {
 2389                 ParseError(ERR_EXTRA_OPTION);
 2390             }
 2391 
 2392             thdx.sid = xatou(pairs[1], "rate_filter: sig_id");
 2393         }
 2394         else if (!strcasecmp(pairs[0], "track"))
 2395         {
 2396             if ( tracking_flag++ )
 2397             {
 2398                 ParseError(ERR_EXTRA_OPTION);
 2399             }
 2400 
 2401             if (!strcasecmp(pairs[1], "by_src"))
 2402             {
 2403                 thdx.tracking = SFRF_TRACK_BY_SRC;
 2404             }
 2405             else if (!strcasecmp(pairs[1], "by_dst"))
 2406             {
 2407                 thdx.tracking = SFRF_TRACK_BY_DST;
 2408             }
 2409             else if (!strcasecmp(pairs[1], "by_rule"))
 2410             {
 2411                 thdx.tracking = SFRF_TRACK_BY_RULE;
 2412             }
 2413             else
 2414             {
 2415                 ParseError(ERR_BAD_VALUE);
 2416             }
 2417         }
 2418         else if (!strcasecmp(pairs[0], "count"))
 2419         {
 2420             if ( count_flag++ )
 2421             {
 2422                 ParseError(ERR_EXTRA_OPTION);
 2423             }
 2424 
 2425             thdx.count = xatoup(pairs[1], "rate_filter: count");
 2426         }
 2427         else if (!strcasecmp(pairs[0], "seconds"))
 2428         {
 2429             if ( seconds_flag++ )
 2430             {
 2431                 ParseError(ERR_EXTRA_OPTION);
 2432             }
 2433 
 2434             thdx.seconds = xatou(pairs[1], "rate_filter: seconds");
 2435         }
 2436         else if (!strcasecmp(pairs[0], "new_action"))
 2437         {
 2438             if ( new_action_flag++ )
 2439             {
 2440                 ParseError(ERR_EXTRA_OPTION);
 2441             }
 2442 
 2443             if (!strcasecmp(pairs[1], "alert"))
 2444             {
 2445                 thdx.newAction = RULE_TYPE__ALERT;
 2446             }
 2447             else if (!strcasecmp(pairs[1], "drop"))
 2448             {
 2449                 thdx.newAction = RULE_TYPE__DROP;
 2450             }
 2451             else if (!strcasecmp(pairs[1], "pass"))
 2452             {
 2453                 thdx.newAction = RULE_TYPE__PASS;
 2454             }
 2455             else if (!strcasecmp(pairs[1], "log"))
 2456             {
 2457                 thdx.newAction = RULE_TYPE__LOG;
 2458             }
 2459             else if (!strcasecmp(pairs[1], "reject"))
 2460             {
 2461                 thdx.newAction = RULE_TYPE__REJECT;
 2462             }
 2463             else if (!strcasecmp(pairs[1], "sdrop"))
 2464             {
 2465                 thdx.newAction = RULE_TYPE__SDROP;
 2466             }
 2467             else
 2468             {
 2469                 ParseError(ERR_BAD_VALUE);
 2470             }
 2471         }
 2472         else if (!strcasecmp(pairs[0], "timeout"))
 2473         {
 2474             if ( timeout_flag++ )
 2475             {
 2476                 ParseError(ERR_EXTRA_OPTION);
 2477             }
 2478 
 2479             thdx.timeout = xatou(pairs[1],"rate_filter: timeout");
 2480         }
 2481         else if (!strcasecmp(pairs[0], "apply_to"))
 2482         {
 2483             char *ip_list = pairs[1];
 2484 
 2485             if ( apply_flag++ )
 2486             {
 2487                 ParseError(ERR_EXTRA_OPTION);
 2488             }
 2489 
 2490             thdx.applyTo = IpAddrSetParse(sc, ip_list);
 2491         }
 2492         else
 2493         {
 2494             ParseError(ERR_BAD_OPTION);
 2495         }
 2496 
 2497         mSplitFree(&pairs, num_pairs);
 2498     }
 2499 
 2500     if ( (genid_flag != 1) || (sigid_flag != 1) || (tracking_flag != 1)
 2501       || (count_flag != 1) || (seconds_flag != 1) || (new_action_flag != 1)
 2502       || (timeout_flag != 1) || (apply_flag > 1) )
 2503     {
 2504         ParseError(ERR_BAD_ARG_COUNT);
 2505     }
 2506     if ( !thdx.seconds
 2507         && (thdx.gid != GENERATOR_INTERNAL
 2508          || thdx.sid != INTERNAL_EVENT_SESSION_ADD) )
 2509     {
 2510         ParseError("rate_filter: seconds must be > 0");
 2511     }
 2512 
 2513     if (RateFilter_Create(sc, sc->rate_filter_config,  &thdx))
 2514     {
 2515         ParseError(ERR_CREATE);
 2516     }
 2517 
 2518     mSplitFree(&toks, num_toks);
 2519 }
 2520 
 2521 static void ParseRuleTypeOutput(SnortConfig *sc, char *args, ListHead *list)
 2522 {
 2523     char **toks;
 2524     int num_toks;
 2525     char *opts = NULL;
 2526     OutputConfig *config;
 2527 
 2528     toks = mSplit(args, ":", 2, &num_toks, '\\');
 2529 
 2530     if (num_toks > 1)
 2531         opts = toks[1];
 2532 
 2533     config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
 2534 
 2535     if (sc->rule_type_output_configs == NULL)
 2536     {
 2537         sc->rule_type_output_configs = config;
 2538     }
 2539     else
 2540     {
 2541         OutputConfig *tmp = sc->rule_type_output_configs;
 2542 
 2543         while (tmp->next != NULL)
 2544             tmp = tmp->next;
 2545 
 2546         tmp->next = config;
 2547     }
 2548 
 2549     config->keyword = SnortStrdup(toks[0]);
 2550     if (opts != NULL)
 2551         config->opts = SnortStrdup(opts);
 2552     config->rule_list = list;
 2553 
 2554     if (file_name != NULL)
 2555     {
 2556         config->file_name = SnortStrdup(file_name);
 2557         config->file_line = file_line;
 2558     }
 2559 
 2560     mSplitFree(&toks, num_toks);
 2561 }
 2562 
 2563 void ParseOutput(SnortConfig *sc, SnortPolicy *p, char *args)
 2564 {
 2565     char **toks;
 2566     int num_toks;
 2567     char *opts = NULL;
 2568     OutputConfig *config;
 2569 
 2570     toks = mSplit(args, ":", 2, &num_toks, '\\');
 2571 
 2572     if (num_toks > 1)
 2573         opts = toks[1];
 2574 
 2575     config = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
 2576 
 2577     if (sc->output_configs == NULL)
 2578     {
 2579         sc->output_configs = config;
 2580     }
 2581     else
 2582     {
 2583         OutputConfig *tmp = sc->output_configs;
 2584 
 2585         while (tmp->next != NULL)
 2586             tmp = tmp->next;
 2587 
 2588         tmp->next = config;
 2589     }
 2590 
 2591     config->keyword = SnortStrdup(toks[0]);
 2592     if (opts != NULL)
 2593         config->opts = SnortStrdup(opts);
 2594 
 2595     /* This could come from parsing the command line */
 2596     if (file_name != NULL)
 2597     {
 2598         config->file_name = SnortStrdup(file_name);
 2599         config->file_line = file_line;
 2600     }
 2601 
 2602     mSplitFree(&toks, num_toks);
 2603 }
 2604 
 2605 static void TransferOutputConfigs(OutputConfig *from_list, OutputConfig **to_list)
 2606 {
 2607     if ((from_list == NULL) || (to_list == NULL))
 2608         return;
 2609 
 2610     for (; from_list != NULL; from_list = from_list->next)
 2611     {
 2612         if (*to_list == NULL)
 2613         {
 2614             *to_list = DupOutputConfig(from_list);
 2615         }
 2616         else
 2617         {
 2618             OutputConfig *tmp = DupOutputConfig(from_list);
 2619 
 2620             if (tmp != NULL)
 2621             {
 2622                 tmp->next = *to_list;
 2623                 *to_list = tmp;
 2624             }
 2625         }
 2626     }
 2627 }
 2628 
 2629 static OutputConfig * DupOutputConfig(OutputConfig *dupme)
 2630 {
 2631     OutputConfig *medup;
 2632 
 2633     if (dupme == NULL)
 2634         return NULL;
 2635 
 2636     medup = (OutputConfig *)SnortAlloc(sizeof(OutputConfig));
 2637 
 2638     if (dupme->keyword != NULL)
 2639         medup->keyword = SnortStrdup(dupme->keyword);
 2640 
 2641     if (dupme->opts != NULL)
 2642         medup->opts = SnortStrdup(dupme->opts);
 2643 
 2644     if (dupme->file_name != NULL)
 2645         medup->file_name = SnortStrdup(dupme->file_name);
 2646 
 2647     medup->file_line = dupme->file_line;
 2648     medup->rule_list = dupme->rule_list;
 2649 
 2650     return medup;
 2651 }
 2652 
 2653 static void RemoveOutputConfigs(OutputConfig **head, int remove_flags)
 2654 {
 2655     OutputConfig *config;
 2656     OutputConfig *last = NULL;
 2657 
 2658     if (head == NULL)
 2659         return;
 2660 
 2661     config = *head;
 2662 
 2663     while (config != NULL)
 2664     {
 2665         int type_flags = GetOutputTypeFlags(config->keyword);
 2666 
 2667         if (type_flags & remove_flags)
 2668         {
 2669             OutputConfig *tmp = config;
 2670 
 2671             config = config->next;
 2672 
 2673             if (last == NULL)
 2674                 *head = config;
 2675             else
 2676                 last->next = config;
 2677 
 2678             free(tmp->keyword);
 2679 
 2680             if (tmp->opts != NULL)
 2681                 free(tmp->opts);
 2682 
 2683             if (tmp->file_name != NULL)
 2684                 free(tmp->file_name);
 2685 
 2686             free(tmp);
 2687         }
 2688         else
 2689         {
 2690             last = config;
 2691             config = config->next;
 2692         }
 2693     }
 2694 }
 2695 
 2696 void ResolveOutputPlugins(SnortConfig *cmd_line, SnortConfig *config_file)
 2697 {
 2698     int cmd_line_type_flags = 0;
 2699 
 2700     if (cmd_line == NULL)
 2701         return;
 2702 
 2703     if (cmd_line->no_log)
 2704     {
 2705         /* Free any log output plugins in both lists */
 2706         RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__LOG);
 2707 
 2708         if (config_file != NULL)
 2709         {
 2710             RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
 2711             RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
 2712         }
 2713     }
 2714     else if ((config_file != NULL) && config_file->no_log)
 2715     {
 2716         /* Free any log output plugins in config list */
 2717         RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__LOG);
 2718         RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__LOG);
 2719     }
 2720 
 2721     if (cmd_line->no_alert)
 2722     {
 2723         /* Free any alert output plugins in both lists */
 2724         RemoveOutputConfigs(&cmd_line->output_configs, OUTPUT_TYPE__ALERT);
 2725 
 2726         if (config_file != NULL)
 2727         {
 2728             RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
 2729             RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
 2730         }
 2731     }
 2732     else if ((config_file != NULL) && config_file->no_alert)
 2733     {
 2734         /* Free any alert output plugins in config list */
 2735         RemoveOutputConfigs(&config_file->output_configs, OUTPUT_TYPE__ALERT);
 2736         RemoveOutputConfigs(&config_file->rule_type_output_configs, OUTPUT_TYPE__ALERT);
 2737     }
 2738 
 2739     /* Command line overrides configuration file output */
 2740     if (cmd_line->output_configs != NULL)
 2741     {
 2742         OutputConfig *config = cmd_line->output_configs;
 2743 
 2744         for (; config != NULL; config = config->next)
 2745         {
 2746             int type_flags = GetOutputTypeFlags(config->keyword);
 2747 
 2748             cmd_line_type_flags |= type_flags;
 2749 
 2750             if (config_file != NULL)
 2751             {
 2752                 RemoveOutputConfigs(&config_file->output_configs, type_flags);
 2753                 RemoveOutputConfigs(&config_file->rule_type_output_configs, type_flags);
 2754             }
 2755         }
 2756 
 2757         /* Put what's in the command line output into the config file output */
 2758         if (config_file != NULL)
 2759             TransferOutputConfigs(cmd_line->output_configs, &config_file->output_configs);
 2760     }
 2761 
 2762     if (config_file != NULL)
 2763     {
 2764         if (cmd_line->no_log)
 2765             config_file->no_log = cmd_line->no_log;
 2766 
 2767         if (cmd_line->no_alert)
 2768             config_file->no_alert = cmd_line->no_alert;
 2769     }
 2770 
 2771     /* Don't try to configure defaults if running in test mode */
 2772     if (!ScTestModeNewConf(cmd_line))
 2773     {
 2774         if (config_file == NULL)
 2775         {
 2776             if (!cmd_line->no_log && !(cmd_line_type_flags & OUTPUT_TYPE__LOG))
 2777                 ParseOutput(cmd_line, NULL, "log_tcpdump");
 2778 
 2779             if (!cmd_line->no_alert && !(cmd_line_type_flags & OUTPUT_TYPE__ALERT))
 2780                 ParseOutput(cmd_line, NULL, "alert_full");
 2781         }
 2782         else
 2783         {
 2784             int config_file_type_flags = 0;
 2785             OutputConfig *config = config_file->output_configs;
 2786 
 2787             for (; config != NULL; config = config->next)
 2788                 config_file_type_flags |= GetOutputTypeFlags(config->keyword);
 2789 
 2790             if (!config_file->no_log && !(config_file_type_flags & OUTPUT_TYPE__LOG))
 2791                 ParseOutput(config_file, NULL, "log_tcpdump");
 2792 
 2793             if (!config_file->no_alert && !(config_file_type_flags & OUTPUT_TYPE__ALERT))
 2794                 ParseOutput(config_file, NULL, "alert_full");
 2795         }
 2796     }
 2797 }
 2798 
 2799 void ConfigureOutputPlugins(SnortConfig *sc)
 2800 {
 2801     OutputConfig *config;
 2802     char *stored_file_name = file_name;
 2803     int stored_file_line = file_line;
 2804 
 2805     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Output Plugin\n"););
 2806 
 2807     for (config = sc->output_configs; config != NULL; config = config->next)
 2808     {
 2809         OutputConfigFunc oc_func;
 2810 
 2811         file_name = config->file_name;
 2812         file_line = config->file_line;
 2813 
 2814         oc_func = GetOutputConfigFunc(config->keyword);
 2815         if (oc_func == NULL)
 2816             ParseError("Unknown output plugin: \"%s\"", config->keyword);
 2817 
 2818         oc_func(sc, config->opts);
 2819     }
 2820 
 2821     /* Configure output plugins for user defined rule types */
 2822     for (config = sc->rule_type_output_configs; config != NULL; config = config->next)
 2823     {
 2824         OutputConfigFunc oc_func;
 2825 
 2826         file_name = config->file_name;
 2827         file_line = config->file_line;
 2828 
 2829         oc_func = GetOutputConfigFunc(config->keyword);
 2830         if (oc_func == NULL)
 2831             ParseError("Unknown output plugin \"%s\"", config->keyword);
 2832 
 2833         /* Each user defined rule type has it's own rule list and output plugin is
 2834          * attached to it's Alert and/or Log lists */
 2835         sc->head_tmp = config->rule_list;
 2836         oc_func(sc, config->opts);
 2837         sc->head_tmp = NULL;
 2838     }
 2839 
 2840     /* Reset these since we're done with configuring dynamic preprocessors */
 2841     file_name = stored_file_name;
 2842     file_line = stored_file_line;
 2843 }
 2844 
 2845 static void FreeRuleTreeNode(RuleTreeNode *rtn)
 2846 {
 2847     RuleFpList *idx, *tmp;
 2848     if (!rtn)
 2849         return;
 2850 
 2851     if (rtn->sip)
 2852     {
 2853         sfvar_free(rtn->sip);
 2854     }
 2855 
 2856     if (rtn->dip)
 2857     {
 2858         sfvar_free(rtn->dip);
 2859     }
 2860 
 2861     idx = rtn->rule_func;
 2862     while (idx)
 2863     {
 2864         tmp = idx;
 2865         idx = idx->next;
 2866         free(tmp);
 2867     }
 2868 }
 2869 
 2870 static void DestroyRuleTreeNode(RuleTreeNode *rtn)
 2871 {
 2872     if (!rtn)
 2873         return;
 2874 
 2875     rtn->otnRefCount--;
 2876     if (rtn->otnRefCount != 0)
 2877         return;
 2878 
 2879     FreeRuleTreeNode(rtn);
 2880 
 2881     free(rtn);
 2882 }
 2883 
 2884 /****************************************************************************
 2885  *
 2886  * Function: mergeDuplicateOtn()
 2887  *
 2888  * Purpose:  Conditionally removes duplicate SID/GIDs. Keeps duplicate with
 2889  *           higher revision.  If revision is the same, keeps newest rule.
 2890  *
 2891  * Arguments: otn_dup => The existing duplicate
 2892  *            rtn => the RTN chain to check
 2893  *            char => String describing the rule
 2894  *            rule_type => enumerated rule type (alert, pass, log)
 2895  *
 2896  * Returns: 0 if original rule stays, 1 if new rule stays
 2897  *
 2898  ***************************************************************************/
 2899 static int mergeDuplicateOtn(SnortConfig *sc, OptTreeNode *otn_dup,
 2900                              OptTreeNode *otn_new, RuleTreeNode *rtn_new)
 2901 {
 2902     RuleTreeNode *rtn_dup = NULL;
 2903     RuleTreeNode *rtnTmp2 = NULL;
 2904     unsigned i;
 2905 
 2906     if (otn_dup->proto != otn_new->proto)
 2907     {
 2908         ParseError("GID %d SID %d in rule duplicates previous rule, with "
 2909                    "different protocol.",
 2910                    otn_new->sigInfo.generator, otn_new->sigInfo.id);
 2911     }
 2912 
 2913     rtn_dup = getParserRtnFromOtn(sc, otn_dup);
 2914 
 2915     if((rtn_dup != NULL) && (rtn_dup->type != rtn_new->type))
 2916     {
 2917         ParseError("GID %d SID %d in rule duplicates previous rule, with "
 2918                    "different type.",
 2919                    otn_new->sigInfo.generator, otn_new->sigInfo.id);
 2920     }
 2921 
 2922     if((otn_new->sigInfo.shared < otn_dup->sigInfo.shared)
 2923         || ((otn_new->sigInfo.shared == otn_dup->sigInfo.shared)
 2924             && (otn_new->sigInfo.rev < otn_dup->sigInfo.rev)))
 2925     {
 2926         //existing OTN is newer version. Keep existing and discard the new one.
 2927         //OTN is for new policy group, salvage RTN
 2928         deleteRtnFromOtn(sc, otn_new, getParserPolicy(sc));
 2929 
 2930         ParseMessage("GID %d SID %d duplicates previous rule. Using %s.",
 2931                      otn_new->sigInfo.generator, otn_new->sigInfo.id,
 2932                      otn_dup->sigInfo.shared ? "SO rule.":"higher revision");
 2933 
 2934         /* delete the data for each rule option in this OTN */
 2935         OtnDeleteData(otn_new);
 2936 
 2937         /* Now free the OTN itself -- this function is also used
 2938          * by the hash-table calls out of OtnRemove, so it cannot
 2939          * be modified to delete data for rule options */
 2940         OtnFree(otn_new);
 2941 
 2942         //Add rtn to existing otn for the first rule instance in a policy,
 2943         //otherwise ignore it
 2944         if (rtn_dup == NULL)
 2945         {
 2946             addRtnToOtn(sc, otn_dup, getParserPolicy(sc), rtn_new);
 2947         }
 2948         else
 2949         {
 2950             DestroyRuleTreeNode(rtn_new);
 2951         }
 2952 
 2953         return 0;
 2954     }
 2955 
 2956     //delete existing rule instance and keep the new one
 2957 
 2958     for (i = 0; i < otn_dup->proto_node_num; i++)
 2959     {
 2960         rtnTmp2 = deleteRtnFromOtn(sc, otn_dup, i);
 2961 
 2962         if ((rtnTmp2 && (i != getParserPolicy(sc))))
 2963         {
 2964             addRtnToOtn(sc, otn_new, i, rtnTmp2);
 2965         }
 2966     }
 2967 
 2968     if (rtn_dup)
 2969     {
 2970         if (ScConfErrorOutNewConf(sc))
 2971         {
 2972             ParseError("GID %d SID %d in rule duplicates previous rule.",
 2973                     otn_new->sigInfo.generator, otn_new->sigInfo.id);
 2974         }
 2975         else
 2976         {
 2977             ParseWarning("GID %d SID %d in rule duplicates previous "
 2978                     "rule. Ignoring old rule.\n",
 2979                     otn_new->sigInfo.generator, otn_new->sigInfo.id);
 2980         }
 2981 
 2982         switch (otn_new->sigInfo.rule_type)
 2983         {
 2984             case SI_RULE_TYPE_DETECT:
 2985                 detect_rule_count--;
 2986                 break;
 2987             case SI_RULE_TYPE_DECODE:
 2988                 decode_rule_count--;
 2989                 break;
 2990             case SI_RULE_TYPE_PREPROC:
 2991                 preproc_rule_count--;
 2992                 break;
 2993             default:
 2994                 break;
 2995         }
 2996     }
 2997 
 2998     otn_count--;
 2999 
 3000     OtnRemove(sc->otn_map, sc->so_rule_otn_map, otn_dup);
 3001     DestroyRuleTreeNode(rtn_dup);
 3002 
 3003     return 1;
 3004 }
 3005 
 3006 /* createDynamicRuleTypeRtn
 3007  *
 3008  * This api is only getting called whenever will see those
 3009  * GID/SID pairs whose rule action type is getting modulated 
 3010  * from code depending upon few runtime parameters. 
 3011  *
 3012  * In present scenario for 
 3013  * GID - GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE, rule action 
 3014  * type is getting modified depending upon file verdict.
 3015  * 
 3016  * I/P - SnortConfig -
 3017  *       old_rtn     -   This is the old RTN which has been created
 3018  *                       irrespective of above mentioned scenario.
 3019  *                       As a new RTN will be created with type NONE,
 3020  *                       will destroy this old RTN.
 3021  *
 3022  * O/P - rtn         -   This is RTN which has been created with 
 3023  *                       RULE_TYPE_NONE specify that rule type will 
 3024  *                       be decided at the run time.
 3025  */
 3026 static inline RuleTreeNode * createDynamicRuleTypeRtn(SnortConfig *sc, RuleTreeNode *old_rtn)
 3027 {
 3028     RuleTreeNode test_rtn;
 3029     RuleTreeNode *rtn;
 3030     ListHead *list = old_rtn->listhead;
 3031 
 3032     memset(&test_rtn, 0, sizeof(RuleTreeNode));
 3033 
 3034     /* Making own key by changing the type to NONE */
 3035     test_rtn.flags |= ANY_DST_PORT;
 3036     test_rtn.flags |= ANY_SRC_PORT;
 3037     test_rtn.flags |= ANY_DST_IP;
 3038     test_rtn.flags |= ANY_SRC_IP;
 3039     test_rtn.flags |= BIDIRECTIONAL;
 3040 
 3041     /* 
 3042      * Initialising the rule type as NONE since type value will be 
 3043      * dynamic for GENERATOR_FILE_SIGNATURE/GENERATOR_FILE_TYPE
 3044      */
 3045     test_rtn.type = RULE_TYPE__NONE;
 3046     test_rtn.listhead = list;
 3047 
 3048     DestroyRuleTreeNode(old_rtn);
 3049 
 3050     /* Creating the RTN node for File policy internal IPS rules(147:1/146)*/
 3051     rtn = ProcessHeadNode(sc, &test_rtn, list);
 3052     return rtn;
 3053 }
 3054 
 3055 /****************************************************************************
 3056  *
 3057  * Function: ParseRuleOptions(char *, int)
 3058  *
 3059  * Purpose:  Process an individual rule's options and add it to the
 3060  *           appropriate rule chain
 3061  *
 3062  * Arguments: rule => rule string
 3063  *            rule_type => enumerated rule type (alert, pass, log)
 3064  *            *conflicts => Identifies whether there was a conflict due to duplicate
 3065  *                rule and whether existing otn was newer or not.
 3066  *                0 - no conflict
 3067  *                1 - existing otn is newer.
 3068  *                -1 - existing otn is older.
 3069  *
 3070  * Returns:
 3071  *  OptTreeNode *
 3072  *      The new OptTreeNode on success or NULL on error.
 3073  *
 3074  ***************************************************************************/
 3075 OptTreeNode * ParseRuleOptions(SnortConfig *sc, RuleTreeNode **rtn_addr,
 3076                                char *rule_opts, RuleType rule_type, int protocol)
 3077 {
 3078     OptTreeNode *otn;
 3079     RuleOptOtnHandler otn_handler = NULL;
 3080     int num_detection_opts = 0;
 3081     char *dopt_keyword = NULL;
 3082     OptFpList *fpl = NULL;
 3083     int got_sid = 0;
 3084     RuleTreeNode *rtn = *rtn_addr;
 3085 
 3086     otn = (OptTreeNode *)SnortAlloc(sizeof(OptTreeNode));
 3087 
 3088     otn->chain_node_number = otn_count;
 3089     otn->proto = protocol;
 3090     otn->event_data.sig_generator = GENERATOR_SNORT_ENGINE;
 3091     otn->sigInfo.generator        = GENERATOR_SNORT_ENGINE;
 3092     otn->sigInfo.rule_type        = SI_RULE_TYPE_DETECT; /* standard rule */
 3093     otn->sigInfo.rule_flushing    = SI_RULE_FLUSHING_ON; /* usually just standard rules cause a flush*/
 3094 #ifdef TARGET_BASED
 3095     otn->sigInfo.service_override = ServiceOverride_Nil;
 3096 #endif
 3097 
 3098     /* Set the default rule state */
 3099     otn->rule_state = ScDefaultRuleStateNewConf(sc);
 3100 
 3101     if (rule_opts == NULL)
 3102     {
 3103         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "No rule options.\n"););
 3104 
 3105         if (ScRequireRuleSidNewConf(sc))
 3106             ParseError("Each rule must contain a Rule-sid.");
 3107 
 3108         addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
 3109 
 3110         otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
 3111                                          otn->sigInfo.generator,
 3112                                          otn->sigInfo.id);
 3113     }
 3114     else
 3115     {
 3116         char **toks;
 3117         int num_toks;
 3118         char configured[sizeof(rule_options) / sizeof(RuleOptFunc)];
 3119         int i;
 3120         OptTreeNode *otn_dup;
 3121 
 3122         if ((rule_opts[0] != '(') || (rule_opts[strlen(rule_opts) - 1] != ')'))
 3123         {
 3124             ParseError("Rule options must be enclosed in '(' and ')'.");
 3125         }
 3126 
 3127         /* Move past '(' and zero out ')' */
 3128         rule_opts++;
 3129         rule_opts[strlen(rule_opts) - 1] = '\0';
 3130 
 3131         /* Used to determine if a rule option has already been configured
 3132          * in the rule.  Some can only be configured once */
 3133         memset(configured, 0, sizeof(configured));
 3134 
 3135         toks = mSplit(rule_opts, ";", 0, &num_toks, '\\');
 3136 
 3137         for (i = 0; i < num_toks; i++)
 3138         {
 3139             char **opts;
 3140             int num_opts;
 3141             char *option_args = NULL;
 3142             int j;
 3143 
 3144             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option: %s\n", toks[i]););
 3145 
 3146             /* break out the option name from its data */
 3147             opts = mSplit(toks[i], ":", 2, &num_opts, '\\');
 3148 
 3149             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option name: %s\n", opts[0]););
 3150 
 3151             if (num_opts == 2)
 3152             {
 3153                 option_args = opts[1];
 3154                 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option args: %s\n", option_args););
 3155             }
 3156 
 3157             for (j = 0; rule_options[j].name != NULL; j++)
 3158             {
 3159                 if (strcasecmp(opts[0], rule_options[j].name) == 0)
 3160                 {
 3161                     if (configured[j] && rule_options[j].only_once)
 3162                     {
 3163                         ParseError("Only one '%s' rule option per rule.",
 3164                                    opts[0]);
 3165                     }
 3166 
 3167                     if ((option_args == NULL) && rule_options[j].args_required)
 3168                     {
 3169                         ParseError("No argument passed to keyword \"%s\".  "
 3170                                    "Make sure you didn't forget a ':' or the "
 3171                                    "argument to this keyword.\n", opts[0]);
 3172                     }
 3173 
 3174                     rule_options[j].parse_func(sc, rtn, otn, rule_type, option_args);
 3175                     configured[j] = 1;
 3176 
 3177                     if ( !dopt_keyword && rule_options[j].detection )
 3178                         dopt_keyword = SnortStrdup(opts[0]);
 3179                     break;
 3180                 }
 3181             }
 3182 
 3183             /* Because we actually allow an sid of 0 */
 3184             if ((rule_options[j].name != NULL) &&
 3185                 (strcasecmp(rule_options[j].name, RULE_OPT__SID) == 0))
 3186             {
 3187                 got_sid = 1;
 3188             }
 3189 
 3190             /* It's possibly a detection option plugin */
 3191             if (rule_options[j].name == NULL)
 3192             {
 3193                 RuleOptConfigFuncNode *dopt = rule_opt_config_funcs;
 3194 
 3195                 for (; dopt != NULL; dopt = dopt->next)
 3196                 {
 3197                     if (strcasecmp(opts[0], dopt->keyword) == 0)
 3198                     {
 3199                         dopt->func(sc, option_args, otn, protocol);
 3200 
 3201                         /* If this option contains an OTN handler, save it for
 3202                            use after the rule is done parsing. */
 3203                         if (dopt->otn_handler != NULL)
 3204                             otn_handler = dopt->otn_handler;
 3205 
 3206                         /* This is done so if we have a preprocessor/decoder
 3207                          * rule, we can tell the user that detection options
 3208                          * are not supported with those types of rules, and
 3209                          * what the detection option is */
 3210                         if ((dopt_keyword == NULL) &&
 3211                             (dopt->type == OPT_TYPE_DETECTION))
 3212                         {
 3213                             dopt_keyword = SnortStrdup(opts[0]);
 3214                         }
 3215 
 3216                         break;
 3217                     }
 3218                 }
 3219 
 3220                 if (dopt == NULL)
 3221                 {
 3222                     /* Maybe it's a preprocessor rule option */
 3223                     PreprocOptionInit initFunc = NULL;
 3224                     PreprocOptionEval evalFunc = NULL;
 3225                     PreprocOptionFastPatternFunc fpFunc = NULL;
 3226                     PreprocOptionOtnHandler preprocOtnHandler = NULL;
 3227                     PreprocOptionCleanup cleanupFunc = NULL;
 3228                     void *opt_data = NULL;
 3229 
 3230                     int ret = GetPreprocessorRuleOptionFuncs
 3231                         (sc, opts[0], &initFunc, &evalFunc,
 3232                          &preprocOtnHandler, &fpFunc, &cleanupFunc);
 3233 
 3234                     if (ret && (initFunc != NULL))
 3235                     {
 3236                         initFunc(sc, opts[0], option_args, &opt_data);
 3237                         AddPreprocessorRuleOption(sc, opts[0], otn, opt_data, evalFunc);
 3238                         if (preprocOtnHandler != NULL)
 3239                             otn_handler = (RuleOptOtnHandler)preprocOtnHandler;
 3240 
 3241                         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "%s->", opts[0]););
 3242                     }
 3243                     else
 3244                     {
 3245                         /* Unrecognized rule option */
 3246                         ParseError("Unknown rule option: '%s'.", opts[0]);
 3247                     }
 3248                 }
 3249 
 3250                 if (dopt_keyword == NULL)
 3251                     dopt_keyword = SnortStrdup(opts[0]);
 3252 
 3253                 num_detection_opts++;
 3254             }
 3255 
 3256             mSplitFree(&opts, num_opts);
 3257         }
 3258 
 3259         if ((dopt_keyword != NULL) &&
 3260             (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT))
 3261         {
 3262             /* Preprocessor and decoder rules can not have
 3263              * detection options */
 3264             ParseError("Preprocessor and decoder rules do not support "
 3265                        "detection options: %s.", dopt_keyword);
 3266         }
 3267 
 3268         if (dopt_keyword != NULL)
 3269             free(dopt_keyword);
 3270 
 3271         /* Each rule must have a sid irrespective of snort
 3272          * in test mode or IPS/IDS mode.*/
 3273         if (!got_sid)
 3274             ParseError("Each rule must contain a rule sid.");
 3275 
 3276         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd\n"););
 3277 
 3278         if ((otn->sigInfo.generator == GENERATOR_FILE_SIGNATURE &&
 3279             otn->sigInfo.id == FILE_SIGNATURE_SHA256) ||
 3280             otn->sigInfo.generator == GENERATOR_FILE_TYPE)
 3281         {
 3282             rtn = createDynamicRuleTypeRtn(sc, rtn);
 3283             *rtn_addr = rtn;
 3284         }
 3285         addRtnToOtn(sc, otn, getParserPolicy(sc), rtn);
 3286 
 3287         /* Check for duplicate SID */
 3288         otn_dup = OtnLookup(sc->otn_map, otn->sigInfo.generator, otn->sigInfo.id);
 3289         if (otn_dup != NULL)
 3290         {
 3291             otn->ruleIndex = otn_dup->ruleIndex;
 3292 
 3293             if (mergeDuplicateOtn(sc, otn_dup, otn, rtn) == 0)
 3294             {
 3295                 /* We are keeping the old/dup OTN and trashing the new one
 3296                  * we just created - it's free'd in the remove dup function */
 3297                 mSplitFree(&toks, num_toks);
 3298                 return NULL;
 3299             }
 3300         }
 3301         else
 3302         {
 3303             otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
 3304                                              otn->sigInfo.generator,
 3305                                              otn->sigInfo.id);
 3306         }
 3307 
 3308         mSplitFree(&toks, num_toks);
 3309     }
 3310 
 3311     otn->num_detection_opts += num_detection_opts;
 3312     otn_count++;
 3313 
 3314     if (otn->sigInfo.rule_type == SI_RULE_TYPE_DETECT)
 3315     {
 3316         detect_rule_count++;
 3317     }
 3318     else if (otn->sigInfo.rule_type == SI_RULE_TYPE_DECODE)
 3319     {
 3320         //Set the bit if the decoder rule is enabled in the policies
 3321         UpdateDecodeRulesArray(otn->sigInfo.id, ENABLE_RULE, ENABLE_ONE_RULE);
 3322         decode_rule_count++;
 3323     }
 3324     else if (otn->sigInfo.rule_type == SI_RULE_TYPE_PREPROC)
 3325     {
 3326         preproc_rule_count++;
 3327     }
 3328 
 3329     fpl = AddOptFuncToList(OptListEnd, otn);
 3330     fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
 3331 
 3332     if (otn_handler != NULL)
 3333     {
 3334         otn_handler(sc, otn);
 3335     }
 3336 
 3337     FinalizeContentUniqueness(sc, otn);
 3338     ValidateFastPattern(otn);
 3339 
 3340     if ((thdx_tmp != NULL) && (otn->detection_filter != NULL))
 3341     {
 3342         ParseError("The \"detection_filter\" rule option and the \"threshold\" "
 3343                    "rule option cannot be used in the same rule.\n");
 3344     }
 3345 
 3346     if (thdx_tmp != NULL)
 3347     {
 3348         int rstat;
 3349 
 3350         thdx_tmp->sig_id = otn->sigInfo.id;
 3351         thdx_tmp->gen_id = otn->sigInfo.generator;
 3352         rstat = sfthreshold_create(sc, sc->threshold_config, thdx_tmp);
 3353 
 3354         if (rstat)
 3355         {
 3356             if (rstat == THD_TOO_MANY_THDOBJ)
 3357             {
 3358                 ParseError("threshold (in rule): could not create threshold - "
 3359                            "only one per sig_id=%u.", thdx_tmp->sig_id);
 3360             }
 3361             else
 3362             {
 3363                 ParseError("threshold (in rule): could not add threshold "
 3364                            "for sig_id=%u!\n", thdx_tmp->sig_id);
 3365             }
 3366         }
 3367 
 3368         thdx_tmp = NULL;
 3369     }
 3370 
 3371     /* setup gid,sid->otn mapping */
 3372     SoRuleOtnLookupAdd(sc->so_rule_otn_map, otn);
 3373     OtnLookupAdd(sc->otn_map, otn);
 3374 
 3375     return otn;
 3376 }
 3377 
 3378 /****************************************************************************
 3379  *
 3380  * Function: GetRuleProtocol(char *)
 3381  *
 3382  * Purpose: Figure out which protocol the current rule is talking about
 3383  *
 3384  * Arguments: proto_str => the protocol string
 3385  *
 3386  * Returns: The integer value of the protocol
 3387  *
 3388  ***************************************************************************/
 3389 static int GetRuleProtocol(char *proto_str)
 3390 {
 3391     if (strcasecmp(proto_str, RULE_PROTO_OPT__TCP) == 0)
 3392     {
 3393         return IPPROTO_TCP;
 3394     }
 3395     else if (strcasecmp(proto_str, RULE_PROTO_OPT__UDP) == 0)
 3396     {
 3397         return IPPROTO_UDP;
 3398     }
 3399     else if (strcasecmp(proto_str, RULE_PROTO_OPT__ICMP) == 0)
 3400     {
 3401         return IPPROTO_ICMP;
 3402     }
 3403     else if (strcasecmp(proto_str, RULE_PROTO_OPT__IP) == 0)
 3404     {
 3405         return ETHERNET_TYPE_IP;
 3406     }
 3407     else
 3408     {
 3409         /* If we've gotten here, we have a protocol string we didn't recognize
 3410          * and should exit */
 3411         ParseError("Bad protocol: %s.", proto_str);
 3412     }
 3413 
 3414     return -1;
 3415 }
 3416 
 3417 
 3418 static int ProcessIP(SnortConfig *sc, char *addr, RuleTreeNode *rtn, int mode, int neg_list)
 3419 {
 3420     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
 3421 
 3422     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got address string: %s\n",
 3423                 addr););
 3424     assert(rtn);
 3425     /* If a rule has a variable in it, we want to copy that variable's
 3426      * contents to the IP variable (IP list) stored with the rtn.
 3427      * This code tries to look up the variable, and if found, will copy it
 3428      * to the rtn->{sip,dip} */
 3429     if(mode == SRC)
 3430     {
 3431         int ret;
 3432 
 3433         if (rtn->sip == NULL)
 3434         {
 3435             sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
 3436             if (tmp != NULL)
 3437             {
 3438                 rtn->sip = sfvar_create_alias(tmp, tmp->name);
 3439                 if (rtn->sip == NULL)
 3440                     ret = SFIP_FAILURE;
 3441                 else
 3442                     ret = SFIP_SUCCESS;
 3443             }
 3444             else
 3445             {
 3446                 rtn->sip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
 3447                 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
 3448             }
 3449         }
 3450         else
 3451         {
 3452             ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
 3453         }
 3454 
 3455         /* The function sfvt_add_to_var adds 'addr' to the variable 'rtn->sip' */
 3456         if (ret != SFIP_SUCCESS)
 3457         {
 3458             if(ret == SFIP_LOOKUP_FAILURE)
 3459             {
 3460                 ParseError("Undefined variable in the string: %s.", addr);
 3461             }
 3462             else if(ret == SFIP_CONFLICT)
 3463             {
 3464                 ParseError("Negated IP ranges that are more general than "
 3465                            "non-negated ranges are not allowed. Consider "
 3466                            "inverting the logic: %s.", addr);
 3467             }
 3468             else if(ret == SFIP_NOT_ANY)
 3469             {
 3470                 ParseError("!any is not allowed: %s.", addr);
 3471             }
 3472             else
 3473             {
 3474                 ParseError("Unable to process the IP address: %s.", addr);
 3475             }
 3476         }
 3477 
 3478         if(rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
 3479         {
 3480             rtn->flags |= ANY_SRC_IP;
 3481         }
 3482     }
 3483     /* mode == DST */
 3484     else
 3485     {
 3486         int ret;
 3487 
 3488         if (rtn->dip == NULL)
 3489         {
 3490             sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
 3491             if (tmp != NULL)
 3492             {
 3493                 rtn->dip = sfvar_create_alias(tmp, tmp->name);
 3494                 if (rtn->dip == NULL)
 3495                     ret = SFIP_FAILURE;
 3496                 else
 3497                     ret = SFIP_SUCCESS;
 3498             }
 3499             else
 3500             {
 3501                 rtn->dip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
 3502                 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
 3503             }
 3504         }
 3505         else
 3506         {
 3507             ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
 3508         }
 3509 
 3510         if (ret != SFIP_SUCCESS)
 3511         {
 3512             if(ret == SFIP_LOOKUP_FAILURE)
 3513             {
 3514                 ParseError("Undefined variable in the string: %s.", addr);
 3515             }
 3516             else if(ret == SFIP_CONFLICT)
 3517             {
 3518                 ParseError("Negated IP ranges that are more general than "
 3519                            "non-negated ranges are not allowed. Consider "
 3520                            "inverting the logic: %s.", addr);
 3521             }
 3522             else if(ret == SFIP_NOT_ANY)
 3523             {
 3524                 ParseError("!any is not allowed: %s.", addr);
 3525             }
 3526             else
 3527             {
 3528                 ParseError("Unable to process the IP address: %s.", addr);
 3529             }
 3530         }
 3531 
 3532         if(rtn->dip->head && rtn->dip->head->flags & SFIP_ANY)
 3533         {
 3534             rtn->flags |= ANY_DST_IP;
 3535         }
 3536     }
 3537 
 3538     /* Make sure the IP lists provided by the user are valid */
 3539     if (mode == SRC)
 3540         ValidateIPList(rtn->sip, addr);
 3541     else
 3542         ValidateIPList(rtn->dip, addr);
 3543 
 3544     return 0;
 3545 }
 3546 
 3547 
 3548 /****************************************************************************
 3549  *
 3550  * Function: ParsePort(SnortConfig *, char *, u_short *)
 3551  *
 3552  * Purpose:  Convert the port string over to an integer value
 3553  *
 3554  * Arguments: prule_port => port rule string
 3555  *            port => converted integer value of the port
 3556  *
 3557  * Returns: 0 for a normal port number, 1 for an "any" port
 3558  *
 3559  ***************************************************************************/
 3560 int ParsePort(SnortConfig *sc, char *prule_port, uint16_t *hi_port, uint16_t *lo_port, char *proto, int *not_flag)
 3561 {
 3562     char **toks;        /* token dbl buffer */
 3563     int num_toks;       /* number of tokens found by mSplit() */
 3564     char *rule_port;    /* port string */
 3565 
 3566     *not_flag = 0;
 3567 
 3568     /* check for variable */
 3569     if(!strncmp(prule_port, "$", 1))
 3570     {
 3571         if((rule_port = VarGet(sc, prule_port + 1)) == NULL)
 3572         {
 3573             ParseError("Undefined variable %s.", prule_port);
 3574         }
 3575     }
 3576     else
 3577         rule_port = prule_port;
 3578 
 3579     if(rule_port[0] == '(')
 3580     {
 3581         /* user forgot to put a port number in for this rule */
 3582         ParseError("Bad port number: \"%s\".", rule_port);
 3583     }
 3584 
 3585 
 3586     /* check for wildcards */
 3587     if(!strcasecmp(rule_port, "any"))
 3588     {
 3589         *hi_port = 0;
 3590         *lo_port = 0;
 3591         return 1;
 3592     }
 3593 
 3594     if(rule_port[0] == '!')
 3595     {
 3596         if(!strcasecmp(&rule_port[1], "any"))
 3597         {
 3598             ParseWarning("Negating \"any\" is invalid. Rule "
 3599                          "will be ignored.");
 3600             return -1;
 3601         }
 3602 
 3603         *not_flag = 1;
 3604         rule_port++;
 3605     }
 3606 
 3607     if(rule_port[0] == ':')
 3608     {
 3609         *lo_port = 0;
 3610     }
 3611 
 3612     toks = mSplit(rule_port, ":", 2, &num_toks, 0);
 3613 
 3614     switch(num_toks)
 3615     {
 3616         case 1:
 3617             *hi_port = (u_short)ConvPort(toks[0], proto);
 3618 
 3619             if(rule_port[0] == ':')
 3620             {
 3621                 *lo_port = 0;
 3622             }
 3623             else
 3624             {
 3625                 *lo_port = *hi_port;
 3626 
 3627                 if(strchr(rule_port, ':') != NULL)
 3628                 {
 3629                     *hi_port = MAXPORTS-1;
 3630                 }
 3631             }
 3632 
 3633             break;
 3634 
 3635         case 2:
 3636             *lo_port = (u_short)ConvPort(toks[0], proto);
 3637 
 3638             if(toks[1][0] == 0)
 3639                 *hi_port = MAXPORTS-1;
 3640             else
 3641                 *hi_port = (u_short)ConvPort(toks[1], proto);
 3642 
 3643             break;
 3644 
 3645         default:
 3646             ParseError("Port conversion failed on \"%s\".", rule_port);
 3647     }
 3648 
 3649     mSplitFree(&toks, num_toks);
 3650 
 3651     return 0;
 3652 }
 3653 
 3654 /****************************************************************************
 3655  *
 3656  * Function: ConvPort(char *, char *)
 3657  *
 3658  * Purpose:  Convert the port string over to an integer value
 3659  *
 3660  * Arguments: port => port string
 3661  *            proto => converted integer value of the port
 3662  *
 3663  * Returns:  the port number
 3664  *
 3665  ***************************************************************************/
 3666 uint16_t ConvPort(char *port, char *proto)
 3667 {
 3668     int conv;           /* storage for the converted number */
 3669     char *digit;      /* used to check for a number */
 3670     struct servent *service_info;
 3671 
 3672     /*
 3673      * convert a "word port" (http, ftp, imap, whatever) to its corresponding
 3674      * numeric port value
 3675      */
 3676     if(isalpha((int) port[0]) != 0)
 3677     {
 3678         service_info = getservbyname(port, proto);
 3679 
 3680         if(service_info != NULL)
 3681         {
 3682             conv = ntohs(service_info->s_port);
 3683             return conv;
 3684         }
 3685         else
 3686         {
 3687             ParseError("getservbyname() failed on \"%s\".", port);
 3688         }
 3689     }
 3690     digit = port;
 3691     while (*digit) {
 3692 
 3693         if(!isdigit((int) *digit))
 3694         {
 3695             ParseError("Invalid port: %s.", port);
 3696         }
 3697         digit++;
 3698     }
 3699     /* convert the value */
 3700     conv = atoi(port);
 3701 
 3702     /* make sure it's in bounds */
 3703     if ((conv < 0) || (conv > MAXPORTS-1))
 3704     {
 3705         ParseError("Bad port number: %s.", port);
 3706     }
 3707 
 3708     return (uint16_t)conv;
 3709 }
 3710 
 3711 /****************************************************************************
 3712  *
 3713  * Function: XferHeader(RuleTreeNode *, RuleTreeNode *)
 3714  *
 3715  * Purpose: Transfer the rule block header data from point A to point B
 3716  *
 3717  * Arguments: rule => the place to xfer from
 3718  *            rtn => the place to xfer to
 3719  *
 3720  * Returns: void function
 3721  *
 3722  ***************************************************************************/
 3723 static void XferHeader(RuleTreeNode *test_node, RuleTreeNode *rtn)
 3724 {
 3725     rtn->flags = test_node->flags;
 3726     rtn->type = test_node->type;
 3727     rtn->sip = test_node->sip;
 3728     rtn->dip = test_node->dip;
 3729 
 3730     rtn->proto = test_node->proto;
 3731 
 3732     rtn->src_portobject = test_node->src_portobject;
 3733     rtn->dst_portobject = test_node->dst_portobject;
 3734 }
 3735 
 3736 /****************************************************************************
 3737  *
 3738  * Function: CompareIPNodes(RuleTreeNode *, RuleTreeNode *).  Support function
 3739  *           for CompareIPLists.
 3740  *
 3741  * Purpose: Checks if the node's contents equal.
 3742  *
 3743  * Returns: 1 if they match, 0 if they don't
 3744  *
 3745  ***************************************************************************/
 3746 int CompareIPNodes(IpAddrNode *one, IpAddrNode *two)
 3747 {
 3748      if( (sfip_compare(&one->ip->addr, &two->ip->addr) != SFIP_EQUAL) ||
 3749          (sfip_bits(one->ip) != sfip_bits(two->ip)) ||
 3750          (sfvar_flags(one) != sfvar_flags(two)) )
 3751          return 0;
 3752     return 1;
 3753 }
 3754 
 3755 
 3756 /****************************************************************************
 3757  *
 3758  * Function: TestHeader(RuleTreeNode *, RuleTreeNode *)
 3759  *
 3760  * Purpose: Check to see if the two header blocks are identical
 3761  *
 3762  * Arguments: rule => uh
 3763  *            rtn  => uuuuhhhhh....
 3764  *
 3765  * Returns: 1 if they match, 0 if they don't
 3766  *
 3767  ***************************************************************************/
 3768 static int TestHeader(RuleTreeNode * rule, RuleTreeNode * rtn)
 3769 {
 3770     if ((rule == NULL) || (rtn == NULL))
 3771         return 0;
 3772 
 3773     if (rule->type != rtn->type)
 3774         return 0;
 3775 
 3776     if (rule->proto != rtn->proto)
 3777         return 0;
 3778 
 3779     /* For custom rule type declarations */
 3780     if (rule->listhead != rtn->listhead)
 3781         return 0;
 3782 
 3783     if (rule->flags != rtn->flags)
 3784         return 0;
 3785 
 3786     if ((rule->sip != NULL) && (rtn->sip != NULL) &&
 3787             (sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL))
 3788     {
 3789         return 0;
 3790     }
 3791 
 3792     if ((rule->dip != NULL) && (rtn->dip != NULL) &&
 3793             (sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL))
 3794     {
 3795         return 0;
 3796     }
 3797 
 3798     /* compare the port group pointers - this prevents confusing src/dst port objects
 3799      * with the same port set, and it's quicker. It does assume that we only have
 3800      * one port object and pointer for each unique port set...this is handled by the
 3801      * parsing and initial port object storage and lookup.  This must be consistent during
 3802      * the rule parsing phase. - man */
 3803     if ((rule->src_portobject != rtn->src_portobject)
 3804             || (rule->dst_portobject != rtn->dst_portobject))
 3805     {
 3806         return 0;
 3807     }
 3808 
 3809     return 1;
 3810 }
 3811 
 3812 /*
 3813  * PortVarDefine
 3814  *
 3815  *  name - portlist name, i.e. http, smtp, ...
 3816  *  s    - port number, port range, or a list of numbers/ranges in brackets
 3817  *
 3818  *  examples:
 3819  *  portvar http [80,8080,8138,8700:8800,!8711]
 3820  *  portvar http $http_basic
 3821  */
 3822 static int PortVarDefine(SnortConfig *sc, char *name, char *s)
 3823 {
 3824     PortObject *po;
 3825     POParser pop;
 3826     char *errstr="unknown";
 3827     int   rstat;
 3828     PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
 3829     char *end;
 3830     bool invalidvar = true;
 3831 
 3832     DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__PORTVAR);
 3833 
 3834     for(end = name; *end && !isspace((int)*end) && *end != '\\'; end++)
 3835     {
 3836        if(isalpha((int)*end))
 3837                invalidvar = false;
 3838     }
 3839 
 3840     if(invalidvar)
 3841     ParseError("Can not define variable name - %s. Use different name", name);
 3842 
 3843     if( SnortStrcasestr(s,strlen(s),"any") ) /* this allows 'any' or '[any]' */
 3844     {
 3845         if(strstr(s,"!"))
 3846         {
 3847             ParseError("Illegal use of negation and 'any': %s.", s);
 3848         }
 3849 
 3850         po = PortObjectNew();
 3851         if( !po )
 3852         {
 3853             ParseError("PortVarTable missing an 'any' variable.\n");
 3854         }
 3855         PortObjectSetName( po, name );
 3856         PortObjectAddPortAny( po );
 3857     }
 3858     else
 3859     {
 3860         /* Parse the Port List info into a PortObject  */
 3861         po = PortObjectParseString(portVarTable, &pop, name, s, 0);
 3862         if(!po)
 3863         {
 3864             errstr = PortObjectParseError( &pop );
 3865             ParseError("*** PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s.",
 3866                        pop.pos,errstr,s,pop.pos,"^");
 3867         }
 3868     }
 3869 
 3870     /* Add The PortObject to the PortList Table */
 3871     rstat = PortVarTableAdd(portVarTable, po);
 3872     if( rstat < 0 )
 3873     {
 3874         ParseError("***PortVarTableAdd failed with '%s', exiting.", po->name);
 3875     }
 3876     else if( rstat > 0 )
 3877     {
 3878         ParseMessage("PortVar '%s', already defined.", po->name);
 3879     }
 3880 
 3881     /* Print the PortList - PortObjects */
 3882     LogMessage("PortVar '%s' defined : ",po->name);
 3883     PortObjectPrintPortsRaw(po);
 3884     LogMessage("\n");
 3885 
 3886     return 0;
 3887 }
 3888 
 3889 /****************************************************************************
 3890  *
 3891  * Function: VarAlloc()
 3892  *
 3893  * Purpose: allocates memory for a variable
 3894  *
 3895  * Arguments: none
 3896  *
 3897  * Returns: pointer to new VarEntry
 3898  *
 3899  ***************************************************************************/
 3900 VarEntry *VarAlloc()
 3901 {
 3902     VarEntry *new;
 3903 
 3904     new = (VarEntry *)SnortAlloc(sizeof(VarEntry));
 3905 
 3906     return(new);
 3907 }
 3908 
 3909 /****************************************************************************
 3910  *
 3911  * Function: VarIsIpAddr(char *, char *)
 3912  *
 3913  * Purpose: Checks if a var is an IP address. Necessary since moving forward
 3914  *          we want all IP addresses handled by the IP variable table.
 3915  *          If a list is given, this checks each value.
 3916  *
 3917  * Arguments: value => the string to check
 3918  *
 3919  * Returns: 1 if IP address, 0 otherwise
 3920  *
 3921  ***************************************************************************/
 3922 static int VarIsIpAddr(vartable_t *ip_vartable, char *value)
 3923 {
 3924     char *tmp;
 3925 
 3926     /* empty list, consider this an IP address */
 3927     if ((*value == '[') && (*(value+1) == ']'))
 3928         return 1;
 3929 
 3930     while(*value == '!' || *value == '[') value++;
 3931 
 3932     /* Check for dotted-quad */
 3933     if( isdigit((int)*value) &&
 3934          ((tmp = strchr(value, (int)'.')) != NULL) &&
 3935          ((tmp = strchr(tmp+1, (int)'.')) != NULL) &&
 3936          (strchr(tmp+1, (int)'.') != NULL))
 3937         return 1;
 3938 
 3939     /* IPv4 with a mask, and fewer than 4 fields */
 3940     else if( isdigit((int)*value) &&
 3941          (strchr(value+1, (int)':') == NULL) &&
 3942          ((tmp = strchr(value+1, (int)'/')) != NULL) &&
 3943          isdigit((int)(*(tmp+1))) )
 3944         return 1;
 3945 
 3946     /* IPv6 */
 3947     else if((tmp = strchr(value, (int)':')) != NULL)
 3948     {
 3949         char *tmp2;
 3950 
 3951         if((tmp2 = strchr(tmp+1, (int)':')) == NULL)
 3952             return 0;
 3953 
 3954         for(tmp++; tmp < tmp2; tmp++)
 3955             if(!isxdigit((int)*tmp))
 3956                 return 0;
 3957 
 3958         return 1;
 3959     }
 3960 
 3961     /* Any */
 3962     else if(!strncmp(value, "any", 3))
 3963         return 1;
 3964 
 3965     /* Check if it's a variable containing an IP */
 3966     else if(sfvt_lookup_var(ip_vartable, value+1) || sfvt_lookup_var(ip_vartable, value))
 3967         return 1;
 3968 
 3969     return 0;
 3970 }
 3971 
 3972 /****************************************************************************
 3973  *
 3974  * Function: CheckBrackets(char *)
 3975  *
 3976  * Purpose: Check that the brackets match up in a string that
 3977  *          represents a list.
 3978  *
 3979  * Arguments: value => the string to check
 3980  *
 3981  * Returns: 1 if the brackets match correctly, 0 otherwise
 3982  *
 3983  ***************************************************************************/
 3984 static int CheckBrackets(char *value)
 3985 {
 3986     int num_brackets = 0;
 3987 
 3988     while (*value == '!')
 3989         value++;
 3990 
 3991     if ((value[0] != '[') || value[strlen(value)-1] != ']')
 3992     {
 3993         /* List does not begin or end with a bracket. */
 3994         return 0;
 3995     }
 3996 
 3997     while ((*value != '\0') && (num_brackets >= 0))
 3998     {
 3999         if (*value == '[')
 4000             num_brackets++;
 4001         else if (*value == ']')
 4002             num_brackets--;
 4003         value++;
 4004     }
 4005     if (num_brackets != 0)
 4006     {
 4007         /* Mismatched brackets */
 4008         return 0;
 4009     }
 4010 
 4011     return 1;
 4012 }
 4013 
 4014 /****************************************************************************
 4015  *
 4016  * Function: VarIsIpList(vartable_t *, char*)
 4017  *
 4018  * Purpose: Checks if a var is a list of IP addresses.
 4019  *
 4020  * Arguments: value => the string to check
 4021  *
 4022  * Returns: 1 if each item is an IP address, 0 otherwise
 4023  *
 4024  ***************************************************************************/
 4025 static int VarIsIpList(vartable_t *ip_vartable, char *value)
 4026 {
 4027     char *copy, *item;
 4028     int item_is_ip = 1;
 4029 
 4030     copy = SnortStrdup((const char*)value);
 4031 
 4032     /* Ensure that the brackets are correct. */
 4033     if (strchr((const char*)copy, ','))
 4034     {
 4035         /* This is a list! */
 4036         if (CheckBrackets(copy) == 0)
 4037         {
 4038             free(copy);
 4039             return 0;
 4040         }
 4041     }
 4042 
 4043     /* There's no need to worry about the list structure here.
 4044      * We just strip out the IP delimiters and process each one. */
 4045     item = strtok(copy, "[],!");
 4046     while ((item != NULL) && item_is_ip)
 4047     {
 4048         item_is_ip = VarIsIpAddr(ip_vartable, item);
 4049         item = strtok(NULL, "[],!");
 4050     }
 4051 
 4052     free(copy);
 4053     return item_is_ip;
 4054 }
 4055 
 4056 /****************************************************************************
 4057  *
 4058  * Function: DisallowCrossTableDuplicateVars(char *, int)
 4059  *
 4060  * Purpose: FatalErrors if the a variable name is redefined across variable
 4061  *          types.  Enforcing this mutual exclusion prevents the
 4062  *          catatrophe where the variable lookup fall-through (see VarSearch)
 4063  *          finds an unintended variable from the wrong table.  Note:  VarSearch
 4064  *          is only necessary for ExpandVars.
 4065  *
 4066  * Arguments: name => The name of the variable
 4067  *            var_type => The type of the variable that is about to be defined.
 4068  *                        The corresponding variable table will not be searched.
 4069  *
 4070  * Returns: void function
 4071  *
 4072  ***************************************************************************/
 4073 static void DisallowCrossTableDuplicateVars(SnortConfig *sc, char *name, VarType var_type)
 4074 {
 4075     VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
 4076     PortVarTable *portVarTable = sc->targeted_policies[getParserPolicy(sc)]->portVarTable;
 4077     VarEntry *p = var_table;
 4078     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
 4079 
 4080     /* If this is a faked Portvar, treat as a portvar */
 4081     if ((var_type == VAR_TYPE__DEFAULT) &&
 4082         (strstr(name, "_PORT") || strstr(name, "PORT_")))
 4083     {
 4084         var_type = VAR_TYPE__PORTVAR;
 4085     }
 4086 
 4087     switch (var_type)
 4088     {
 4089         case VAR_TYPE__DEFAULT:
 4090             if (PortVarTableFind(portVarTable, name)
 4091                     || sfvt_lookup_var(ip_vartable, name)
 4092                )
 4093             {
 4094                 ParseError("Can not redefine variable name %s to be of type "
 4095                            "'var'. Use a different name.", name);
 4096             }
 4097             break;
 4098 
 4099         case VAR_TYPE__PORTVAR:
 4100             if (var_table != NULL)
 4101             {
 4102                 do
 4103                 {
 4104                     if(strcasecmp(p->name, name) == 0)
 4105                     {
 4106                         ParseError("Can not redefine variable name %s to be of "
 4107                                    "type 'portvar'. Use a different name.", name);
 4108                     }
 4109                     p = p->next;
 4110                 } while(p != var_table);
 4111             }
 4112 
 4113             if(sfvt_lookup_var(ip_vartable, name))
 4114             {
 4115                 ParseError("Can not redefine variable name %s to be of type "
 4116                            "'portvar'. Use a different name.", name);
 4117             }
 4118 
 4119             break;
 4120 
 4121         case VAR_TYPE__IPVAR:
 4122             if (var_table != NULL)
 4123             {
 4124                 do
 4125                 {
 4126                     if(strcasecmp(p->name, name) == 0)
 4127                     {
 4128                         ParseError("Can not redefine variable name %s to be of "
 4129                                    "type 'ipvar'. Use a different name.", name);
 4130                     }
 4131 
 4132                     p = p->next;
 4133                 } while(p != var_table);
 4134             }
 4135 
 4136             if(PortVarTableFind(portVarTable, name))
 4137             {
 4138                 ParseError("Can not redefine variable name %s to be of type "
 4139                            "'ipvar'. Use a different name.", name);
 4140             }
 4141 
 4142         default:
 4143             /* Invalid function usage */
 4144             break;
 4145     }
 4146 }
 4147 
 4148 /****************************************************************************
 4149  *
 4150  * Function: VarDefine(char *, char *)
 4151  *
 4152  * Purpose: define the contents of a variable
 4153  *
 4154  * Arguments: name => the name of the variable
 4155  *            value => the contents of the variable
 4156  *
 4157  * Returns: void function
 4158  *
 4159  ***************************************************************************/
 4160 VarEntry * VarDefine(SnortConfig *sc, char *name, char *value)
 4161 {
 4162     VarEntry *var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
 4163     vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
 4164     VarEntry *p;
 4165     uint32_t var_id = 0;
 4166 
 4167     if(value == NULL)
 4168     {
 4169         ParseError("Bad value in variable definition!  Make sure you don't "
 4170                    "have a \"$\" in the var name.");
 4171     }
 4172 
 4173     if(VarIsIpList(ip_vartable, value))
 4174     {
 4175         SFIP_RET ret;
 4176 
 4177         if (ip_vartable == NULL)
 4178             return NULL;
 4179 
 4180         /* Verify a variable by this name is not already used as either a
 4181          * portvar or regular var.  Enforcing this mutual exclusion prevents the
 4182          * catatrophe where the variable lookup fall-through (see VarSearch)
 4183          * finds an unintended variable from the wrong table.  Note:  VarSearch
 4184          * is only necessary for ExpandVars. */
 4185         DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__IPVAR);
 4186 
 4187         if((ret = sfvt_define(ip_vartable, name, value)) != SFIP_SUCCESS)
 4188         {
 4189             switch(ret) {
 4190                 case SFIP_ARG_ERR:
 4191                     ParseError("The following is not allowed: %s.", value);
 4192                     break;
 4193 
 4194                 case SFIP_DUPLICATE:
 4195                     ParseMessage("Var '%s' redefined.", name);
 4196                     break;
 4197 
 4198                 case SFIP_CONFLICT:
 4199                     ParseError("Negated IP ranges that are more general than "
 4200                                "non-negated ranges are not allowed. Consider "
 4201                                "inverting the logic in %s.", name);
 4202                     break;
 4203 
 4204                 case SFIP_NOT_ANY:
 4205                     ParseError("!any is not allowed in %s.", name);
 4206                     break;
 4207 
 4208                 default:
 4209                     ParseError("Failed to parse the IP address: %s.", value);
 4210             }
 4211         }
 4212         return NULL;
 4213     }
 4214     /* Check if this is a variable that stores an IP */
 4215     else if(*value == '$')
 4216     {
 4217         sfip_var_t *var;
 4218         if((var = sfvt_lookup_var(ip_vartable, value)) != NULL)
 4219         {
 4220             sfvt_define(ip_vartable, name, value);
 4221             return NULL;
 4222         }
 4223     }
 4224 
 4225 
 4226     DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
 4227                "VarDefine: name=%s value=%s\n",name,value););
 4228 
 4229     /* Check to see if this variable is just being aliased */
 4230     if (var_table != NULL)
 4231     {
 4232         VarEntry *tmp = var_table;
 4233 
 4234         do
 4235         {
 4236             /* value+1 to move past $ */
 4237             if (strcmp(tmp->name, value+1) == 0)
 4238             {
 4239                 var_id = tmp->id;
 4240                 break;
 4241             }
 4242 
 4243             tmp = tmp->next;
 4244 
 4245         } while (tmp != var_table);
 4246     }
 4247 
 4248     value = ExpandVars(sc, value);
 4249     if(!value)
 4250     {
 4251         ParseError("Could not expand var('%s').", name);
 4252     }
 4253 
 4254     DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
 4255                "VarDefine: name=%s value=%s (expanded)\n",name,value););
 4256 
 4257     DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__DEFAULT);
 4258 
 4259     if (var_table == NULL)
 4260     {
 4261         p = VarAlloc();
 4262         p->name  = SnortStrdup(name);
 4263         p->value = SnortStrdup(value);
 4264 
 4265         p->prev = p;
 4266         p->next = p;
 4267 
 4268         sc->targeted_policies[getParserPolicy(sc)]->var_table = p;
 4269 
 4270         p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
 4271 
 4272         return p;
 4273     }
 4274 
 4275     /* See if an existing variable is being redefined */
 4276     p = var_table;
 4277 
 4278     do
 4279     {
 4280         if (strcasecmp(p->name, name) == 0)
 4281         {
 4282             if (p->value != NULL)
 4283                 free(p->value);
 4284 
 4285             p->value = SnortStrdup(value);
 4286             ParseWarning("Var '%s' redefined\n", p->name);
 4287             return p;
 4288         }
 4289 
 4290         p = p->next;
 4291 
 4292     } while (p != var_table);   /* List is circular */
 4293 
 4294     p = VarAlloc();
 4295     p->name  = SnortStrdup(name);
 4296     p->value = SnortStrdup(value);
 4297     p->prev = var_table;
 4298     p->next = var_table->next;
 4299     p->next->prev = p;
 4300     var_table->next = p;
 4301 
 4302     if (!var_id)
 4303         p->id = sc->targeted_policies[getParserPolicy(sc)]->var_id++;
 4304     else
 4305         p->id = var_id;
 4306 
 4307 #ifdef XXXXXXX
 4308     vlen = strlen(value);
 4309     LogMessage("Var '%s' defined, value len = %d chars", p->name, vlen  );
 4310 
 4311     if( vlen < 64 )
 4312     {
 4313       LogMessage(", value = %s\n", value );
 4314     }
 4315     else
 4316     {
 4317       LogMessage("\n");
 4318       n = 128;
 4319       s = value;
 4320       while(vlen)
 4321       {
 4322          if( n > vlen ) n = vlen;
 4323          LogMessage("   %.*s\n", n, s );
 4324          s    += n;
 4325          vlen -= n;
 4326       }
 4327     }
 4328 #endif
 4329 
 4330     return p;
 4331 }
 4332 
 4333 static void DeleteVars(VarEntry *var_table)
 4334 {
 4335     VarEntry *q, *p = var_table;
 4336 
 4337     while (p)
 4338     {
 4339         q = p->next;
 4340         if (p->name)
 4341             free(p->name);
 4342         if (p->value)
 4343             free(p->value);
 4344         if (p->addrset)
 4345         {
 4346             IpAddrSetDestroy(p->addrset);
 4347         }
 4348         free(p);
 4349         p = q;
 4350         if (p == var_table)
 4351             break;  /* Grumble, it's a friggin circular list */
 4352     }
 4353 }
 4354 
 4355 /****************************************************************************
 4356  *
 4357  * Function: VarGet(SnortConfig *, char *)
 4358  *
 4359  * Purpose: get the contents of a variable
 4360  *
 4361  * Arguments: name => the name of the variable
 4362  *
 4363  * Returns: char * to contents of variable or FatalErrors on an
 4364  *          undefined variable name
 4365  *
 4366  ***************************************************************************/
 4367 char *VarGet(SnortConfig *sc, char *name)
 4368 {
 4369     SnortPolicy *policy;
 4370     VarEntry *var_table;
 4371     vartable_t *ip_vartable;
 4372     sfip_var_t *var;
 4373 
 4374     if (sc == NULL)
 4375         return NULL;
 4376 
 4377     policy = sc->targeted_policies[getParserPolicy(sc)];
 4378     if (policy == NULL)
 4379         return NULL;
 4380 
 4381     var_table = sc->targeted_policies[getParserPolicy(sc)]->var_table;
 4382 
 4383 // XXX-IPv6 This function should never be used if IP6 support is enabled!
 4384 // Infact it won't presently even work for IP variables since the raw ASCII
 4385 // value is never stored, and is never meant to be used.
 4386     ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
 4387 
 4388     if((var = sfvt_lookup_var(ip_vartable, name)) == NULL) {
 4389         /* Do the old style lookup since it wasn't found in
 4390          * the variable table */
 4391         if(var_table != NULL)
 4392         {
 4393             VarEntry *p = var_table;
 4394             do
 4395             {
 4396                 if(strcasecmp(p->name, name) == 0)
 4397                     return p->value;
 4398                 p = p->next;
 4399             } while(p != var_table);
 4400         }
 4401 
 4402         ParseError("Undefined variable name: %s.", name);
 4403     }
 4404 
 4405     return name;
 4406 
 4407 }
 4408 
 4409 /****************************************************************************
 4410  *
 4411  * Function: ExpandVars()
 4412  *
 4413  * Purpose: expand all variables in a string
 4414  *
 4415  * Arguments:
 4416  *  SnortConfig *
 4417  *      The snort config that has the vartables.
 4418  *  char *
 4419  *      The name of the variable.
 4420  *
 4421  * Returns:
 4422  *  char *
 4423  *      The expanded string.  Note that the string is returned in a
 4424  *      static variable and most likely needs to be string dup'ed.
 4425  *
 4426  ***************************************************************************/
 4427 static char * ExpandVars(SnortConfig *sc, char *string)
 4428 {
 4429     static char estring[ PARSERULE_SIZE ];
 4430 
 4431     char rawvarname[128], varname[128], varaux[128], varbuffer[128];
 4432     char varmodifier, *varcontents;
 4433     int varname_completed, c, i, j, iv, jv, l_string, name_only;
 4434     int quote_toggle = 0;
 4435 
 4436     if(!string || !*string || !strchr(string, '$'))
 4437         return(string);
 4438 
 4439     memset((char *) estring, 0, PARSERULE_SIZE);
 4440 
 4441     i = j = 0;
 4442     l_string = strlen(string);
 4443     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, Before: %s\n", string););
 4444 
 4445     while(i < l_string && j < (int)sizeof(estring) - 1)
 4446     {
 4447         c = string[i++];
 4448 
 4449         if(c == '"')
 4450         {
 4451             /* added checks to make sure that we are inside a quoted string
 4452              */
 4453             quote_toggle ^= 1;
 4454         }
 4455 
 4456         if(c == '$' && !quote_toggle)
 4457         {
 4458             memset((char *) rawvarname, 0, sizeof(rawvarname));
 4459             varname_completed = 0;
 4460             name_only = 1;
 4461             iv = i;
 4462             jv = 0;
 4463 
 4464             if(string[i] == '(')
 4465             {
 4466                 name_only = 0;
 4467                 iv = i + 1;
 4468             }
 4469 
 4470             while(!varname_completed
 4471                   && iv < l_string
 4472                   && jv < (int)sizeof(rawvarname) - 1)
 4473             {
 4474                 c = string[iv++];
 4475 
 4476                 if((name_only && !(isalnum(c) || c == '_'))
 4477                    || (!name_only && c == ')'))
 4478                 {
 4479                     varname_completed = 1;
 4480 
 4481                     if(name_only)
 4482                         iv--;
 4483                 }
 4484                 else
 4485                 {
 4486                     rawvarname[jv++] = (char)c;
 4487                 }
 4488             }
 4489 
 4490             if(varname_completed || iv == l_string)
 4491             {
 4492                 char *p;
 4493 
 4494                 i = iv;
 4495 
 4496                 varcontents = NULL;
 4497 
 4498                 memset((char *) varname, 0, sizeof(varname));
 4499                 memset((char *) varaux, 0, sizeof(varaux));
 4500                 varmodifier = ' ';
 4501 
 4502                 p = strchr(rawvarname, ':');
 4503                 if (p)
 4504                 {
 4505                     SnortStrncpy(varname, rawvarname, p - rawvarname);
 4506 
 4507                     if(strlen(p) >= 2)
 4508                     {
 4509                         varmodifier = *(p + 1);
 4510                         SnortStrncpy(varaux, p + 2, sizeof(varaux));
 4511                     }
 4512                 }
 4513                 else
 4514                     SnortStrncpy(varname, rawvarname, sizeof(varname));
 4515 
 4516                 memset((char *) varbuffer, 0, sizeof(varbuffer));
 4517 
 4518                 varcontents = VarSearch(sc, varname);
 4519 
 4520                 switch(varmodifier)
 4521                 {
 4522                     case '-':
 4523                         if(!varcontents || !strlen(varcontents))
 4524                             varcontents = varaux;
 4525                         break;
 4526 
 4527                     case '?':
 4528                         if(!varcontents || !strlen(varcontents))
 4529                         {
 4530                             ErrorMessage("%s(%d): ", file_name, file_line);
 4531 
 4532                             if(strlen(varaux))
 4533                                 ParseError("%s", varaux);
 4534                             else
 4535                                 ParseError("Undefined variable \"%s\".", varname);
 4536                         }
 4537                         break;
 4538                 }
 4539 
 4540                 /* If variable not defined now, we're toast */
 4541                 if(!varcontents || !strlen(varcontents))
 4542                     ParseError("Undefined variable name: %s.", varname);
 4543 
 4544                 if(varcontents)
 4545                 {
 4546                     int l_varcontents = strlen(varcontents);
 4547 
 4548                     iv = 0;
 4549 
 4550                     while(iv < l_varcontents && j < (int)sizeof(estring) - 1)
 4551                         estring[j++] = varcontents[iv++];
 4552                 }
 4553             }
 4554             else
 4555             {
 4556                 estring[j++] = '$';
 4557             }
 4558         }
 4559         else
 4560         {
 4561             estring[j++] = (char)c;
 4562         }
 4563     }
 4564 
 4565     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "ExpandVars, After: %s\n", estring););
 4566 
 4567     return estring;
 4568 }
 4569 
 4570 char * ProcessFileOption(SnortConfig *sc, const char *filespec)
 4571 {
 4572     char *filename = NULL;
 4573     char buffer[STD_BUF];
 4574 
 4575     if (sc == NULL)
 4576         sc = snort_conf;
 4577 
 4578     if(filespec == NULL)
 4579     {
 4580         ParseError("no argument in this file option, remove extra ':' at the end of the alert option\n");
 4581     }
 4582 
 4583     /* look for ".." in the string and complain and exit if it is found */
 4584     if(strstr(filespec, "..") != NULL)
 4585     {
 4586         ParseError("file definition contains \"..\".  Do not do that!\n");
 4587     }
 4588 
 4589     if(filespec[0] == '/')
 4590     {
 4591         /* absolute filespecs are saved as is */
 4592         filename = SnortStrdup(filespec);
 4593     }
 4594     else
 4595     {
 4596         /* relative filespec is considered relative to the log directory */
 4597         /* or /var/log if the log directory has not been set */
 4598         /* Make sure this function isn't called before log dir is set */
 4599         if ((sc != NULL) && (sc->log_dir != NULL))
 4600         {
 4601             strlcpy(buffer, snort_conf->log_dir, STD_BUF);
 4602         }
 4603         else
 4604         {
 4605             strlcpy(buffer, "/var/log/snort", STD_BUF);
 4606         }
 4607 
 4608         strlcat(buffer, "/", STD_BUF - strlen(buffer));
 4609         strlcat(buffer, filespec, STD_BUF - strlen(buffer));
 4610         buffer[sizeof(buffer) - 1] = '\0';
 4611         filename = SnortStrdup(buffer);
 4612     }
 4613 
 4614     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ProcessFileOption: %s\n", filename););
 4615 
 4616     return filename;
 4617 }
 4618 
 4619 
 4620 #ifdef TARGET_BASED
 4621 static void ParseAttributeTable(SnortConfig *sc, SnortPolicy *p, char *args)
 4622 {
 4623     tSfPolicyId currentPolicyId = getParserPolicy(sc);
 4624     tSfPolicyId defaultPolicyId = sfGetDefaultPolicy(sc->policy_config);
 4625     TargetBasedConfig *defTbc = &sc->targeted_policies[defaultPolicyId]->target_based_config;
 4626 
 4627     /* Save for configuring after configuration is parsed in case
 4628      * config max_attribute_hosts is configured after this */
 4629     if ((currentPolicyId != defaultPolicyId)
 4630             && ((defTbc->args == NULL) || (strcmp(args, defTbc->args) != 0)))
 4631     {
 4632         //arguments should be same as in default policy. Ignoring the arguments
 4633         ParseError("Attribute table must be configured in default policy if "
 4634                    "it is to be used in other policies and attribute table "
 4635                    "filename must be the same across policies.");
 4636     }
 4637 
 4638     if(p->target_based_config.args) 
 4639         free(p->target_based_config.args);
 4640     p->target_based_config.args = SnortStrdup(args);
 4641 
 4642     if (file_name != NULL)
 4643     {
 4644         if(p->target_based_config.file_name)
 4645             free(p->target_based_config.file_name);
 4646         p->target_based_config.file_name = SnortStrdup(file_name);
 4647         p->target_based_config.file_line = file_line;
 4648     }
 4649 }
 4650 #endif
 4651 
 4652 static void ParseConfig(SnortConfig *sc, SnortPolicy *p, char *args)
 4653 {
 4654     char **toks;
 4655     int num_toks;
 4656     char *opts = NULL;
 4657     int i;
 4658 
 4659     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule file config\n"););
 4660 
 4661     toks = mSplit(args, ":", 2, &num_toks, 0);
 4662 
 4663     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Opt: %s\n", toks[0]););
 4664 
 4665     if (num_toks > 1)
 4666     {
 4667         /* Dup the opts because we're putting into hash table */
 4668         opts = SnortStrdup(toks[1]);
 4669         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Args: %s\n", opts););
 4670     }
 4671 
 4672     switch (sfghash_add(sc->config_table, toks[0], opts))
 4673     {
 4674         case SFGHASH_NOMEM:
 4675             ParseError("%s(%d) No memory to add entry to config table.\n",
 4676                        __FILE__, __LINE__);
 4677             break;
 4678 
 4679         case SFGHASH_INTABLE:
 4680             /* Only reference and classifications are likely dup candidates
 4681              * right now and we're not too worried about keeping track of
 4682              * all of them */
 4683             if (opts != NULL)
 4684             {
 4685                 free(opts);
 4686                 opts = toks[1];
 4687             }
 4688 
 4689             break;
 4690 
 4691         default:
 4692             break;
 4693     }
 4694 
 4695     for (i = 0; config_opts[i].name != NULL; i++)
 4696     {
 4697         if (strcasecmp(toks[0], config_opts[i].name) == 0)
 4698         {
 4699                 if ((getParserPolicy(sc) != getDefaultPolicy()) &&
 4700                 config_opts[i].default_policy_only)
 4701                 {
 4702                         /* Config option configurable on by the default policy*/
 4703                 /**Dont raise parse error, ignore any config that is not allowed in non-default
 4704                  * policy.
 4705                  */
 4706                 DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config option \"%s\" "
 4707                     "configurable only by default policy. Ignoring it\n", toks[0]));
 4708                 break;
 4709                 }
 4710 
 4711             if (config_opts[i].only_once && config_opt_configured[i])
 4712             {
 4713                 /* Configured already and set to only configure once
 4714                  * This array is reset for each policy read in so this is
 4715                  * on a per policy basis */
 4716                 ParseError("Config option \"%s\" can only be "
 4717                            "configured once.", toks[0]);
 4718             }
 4719 
 4720             if (config_opts[i].args_required && (opts == NULL))
 4721             {
 4722                 /* Need arguments and there are none */
 4723                  ParseError("Config option \"%s\" requires arguments.", toks[0]);
 4724             }
 4725 
 4726             config_opts[i].parse_func(sc, opts);
 4727             config_opt_configured[i] = 1;
 4728             break;
 4729         }
 4730     }
 4731 
 4732     if (config_opts[i].name == NULL)
 4733     {
 4734         /* Didn't find a matching config option */
 4735         ParseError("Unknown config directive: %s.", toks[0]);
 4736     }
 4737 
 4738     mSplitFree(&toks, num_toks);
 4739 }
 4740 
 4741 /****************************************************************************
 4742  *
 4743  * Purpose: Check that special rules have an OTN.
 4744  *          TODO: Free up memory associated with disabled rules.
 4745  *
 4746  * Arguments: list => Pointer for a list of rules
 4747  *
 4748  * Returns: void function
 4749  *
 4750  * Notes: man - modified to used .shared flag in otn sigInfo instead of specialGID
 4751  *        sas - removed specialGID
 4752  *
 4753  *****************************************************************************/
 4754 int CheckRuleStates(SnortConfig *sc)
 4755 {
 4756     RuleTreeNode *rtn;
 4757     OptTreeNode *otn;
 4758     SFGHASH_NODE *hashNode;
 4759     int oneErr = 0;
 4760     tSfPolicyId policyId = 0;
 4761 
 4762     if (sc == NULL)
 4763         return 0;
 4764 
 4765     for (hashNode = sfghash_findfirst(sc->otn_map);
 4766          hashNode;
 4767          hashNode = sfghash_findnext(sc->otn_map))
 4768     {
 4769         otn = (OptTreeNode *)hashNode->data;
 4770         for (policyId = 0;
 4771              policyId < otn->proto_node_num;
 4772              policyId++)
 4773         {
 4774             rtn = otn->proto_nodes[policyId];
 4775 
 4776             if (!rtn)
 4777             {
 4778                 continue;
 4779             }
 4780 
 4781             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP) ||
 4782                 (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
 4783             {
 4784                 //do operation
 4785                 if ( otn->sigInfo.shared )
 4786                 {
 4787                     if (otn->ds_list[PLUGIN_DYNAMIC] == NULL)
 4788                     {
 4789                         // Have a dynamic rule but no dynamic plugin
 4790                         if (otn->sigInfo.id != otn->sigInfo.otnKey.sid)
 4791                         {
 4792                             // If its a different SID, but same soid metadata as something
 4793                             // else, try to find it
 4794                             OptTreeNode *otn_original;
 4795                             otn_original = SoRuleOtnLookup(sc->so_rule_otn_map,
 4796                                 otn->sigInfo.otnKey.gid, otn->sigInfo.otnKey.sid);
 4797 
 4798                             if ( otn_original && (otn != otn_original) &&
 4799                                 !otn->sigInfo.dup_opt_func )
 4800                             {
 4801                                 OptFpList *opt_func = otn->opt_func;
 4802                                 while (opt_func != NULL)
 4803                                 {
 4804                                     /* Delete the option functions that came from the
 4805                                      * parsing -- this rule will be identical to its
 4806                                      * "cloned" brother. */
 4807                                     OptFpList *tmp = opt_func;
 4808                                     opt_func = opt_func->next;
 4809                                     free(tmp);
 4810                                 }
 4811                                 if (otn_original->sigInfo.shared)
 4812                                 {
 4813                                     /* Its still a shared object -- has its own detection function.  */
 4814                                     otn->ds_list[PLUGIN_DYNAMIC] = otn_original->ds_list[PLUGIN_DYNAMIC];
 4815                                 }
 4816                                 else
 4817                                 {
 4818                                     /* It was back-converted from a shared object */
 4819                                     int i;
 4820                                     for (i=PLUGIN_CLIENTSERVER; i<PLUGIN_MAX; i++)
 4821                                     {
 4822                                         otn->ds_list[i] = otn_original->ds_list[i];
 4823                                     }
 4824                                     otn->sigInfo.shared = 0; /* no longer shared */
 4825                                 }
 4826                                 otn->opt_func = otn_original->opt_func;
 4827                                 otn->sigInfo.dup_opt_func = 1;
 4828                             }
 4829                         }
 4830                     }
 4831 
 4832                     if (otn->sigInfo.shared && (otn->ds_list[PLUGIN_DYNAMIC] == NULL))
 4833                     {
 4834                         /* If still shared... */
 4835                         ParseWarning("Encoded Rule Plugin SID: %d, GID: %d not "
 4836                                    "registered properly.  Disabling this rule.\n",
 4837                                    otn->sigInfo.id, otn->sigInfo.generator);
 4838                         oneErr = 1;
 4839                         otn->rule_state = RULE_STATE_DISABLED;
 4840                     }
 4841                 }
 4842             }
 4843         }
 4844     }
 4845 
 4846     return oneErr;
 4847 }
 4848 
 4849 /****************************************************************************
 4850  *
 4851  * Purpose: Adjust the information for a given rule
 4852  *          relative to the Rule State list
 4853  *
 4854  * Arguments: None
 4855  *
 4856  * Returns: void function
 4857  *
 4858  * Notes:  specialGID is depracated, uses sigInfo.shared flag
 4859  *
 4860  *****************************************************************************/
 4861 void SetRuleStates(SnortConfig *sc)
 4862 {
 4863     RuleState *rule_state;
 4864 #if 0
 4865     int oneErr = 0, err;
 4866 #endif
 4867 
 4868     if (sc == NULL)
 4869         return;
 4870 
 4871     /* First, cycle through the rule state list and update the
 4872      * rule state for each one we find. */
 4873     for (rule_state = sc->rule_state_list; rule_state != NULL; rule_state = rule_state->next)
 4874     {
 4875         /* Lookup the OTN by ruleState->sid, ruleState->gid */
 4876         OptTreeNode *otn = OtnLookup(sc->otn_map, rule_state->gid, rule_state->sid);
 4877 
 4878         if (otn == NULL)
 4879         {
 4880             ParseError("Rule state specified for invalid SID: %d GID: %d\n",
 4881                        rule_state->sid, rule_state->gid);
 4882         }
 4883 
 4884         otn->rule_state = rule_state->state;
 4885     }
 4886 
 4887     /* Check TCP/UDP/ICMP/IP in one iteration for all rulelists and for all policies*/
 4888 #if 1
 4889     CheckRuleStates(sc);
 4890 #else
 4891     err = CheckRuleStates(sc);
 4892     if (err)
 4893         oneErr = 1;
 4894 
 4895     if (oneErr)
 4896     {
 4897         FatalError("Misconfigured or unregistered encoded rule plugins\n");
 4898     }
 4899 #endif
 4900 }
 4901 
 4902 /****************************************************************************
 4903  *
 4904  * Purpose: Parses a rule state line.
 4905  *          Format is sid, gid, state, action.
 4906  *          state should be "enabled" or "disabled"
 4907  *          action should be "alert", "drop", "sdrop", "log", etc.
 4908  *
 4909  * Arguments: args => string containing a single rule state entry
 4910  *
 4911  * Returns: void function
 4912  *
 4913  *****************************************************************************/
 4914 static void ParseRuleState(SnortConfig *sc, SnortPolicy *p, char *args)
 4915 {
 4916     char **toks;
 4917     int num_toks;
 4918     RuleState *state;
 4919     char *endptr;
 4920 
 4921     if (sc == NULL)
 4922         return;
 4923 
 4924     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"RuleState\n"););
 4925 
 4926     toks = mSplit(args, ", ", 0, &num_toks, 0);
 4927 
 4928     if (num_toks != 4)
 4929         ParseError("Config rule_state: Empty state info.");
 4930 
 4931     state = (RuleState *)SnortAlloc(sizeof(RuleState));
 4932 
 4933     state->sid = SnortStrtoul(toks[0], &endptr, 0);
 4934     if ((errno == ERANGE) || (*endptr != '\0'))
 4935     {
 4936         ParseError("Invalid sid for rule state: %s.  Sid must be between 0 and "
 4937                    "%u inclusive.", args, UINT32_MAX);
 4938     }
 4939 
 4940     state->gid = SnortStrtoul(toks[1], &endptr, 0);
 4941     if ((errno == ERANGE) || (*endptr != '\0'))
 4942     {
 4943         ParseError("Invalid gid for rule state: %s.  Gid must be between 0 and "
 4944                    "%u inclusive.", args, UINT32_MAX);
 4945     }
 4946 
 4947     if (strcasecmp(toks[2], RULE_STATE_OPT__DISABLED) == 0)
 4948     {
 4949         state->state = RULE_STATE_DISABLED;
 4950     }
 4951     else if (strcasecmp(toks[2], RULE_STATE_OPT__ENABLED) == 0)
 4952     {
 4953         state->state = RULE_STATE_ENABLED;
 4954     }
 4955     else
 4956     {
 4957         ParseError("Rule_state: Invalid state - must be either "
 4958                    "'enabled' or 'disabled'.");
 4959     }
 4960 
 4961     state->action = GetRuleType(toks[3]);
 4962     if (state->action == RULE_TYPE__NONE)
 4963     {
 4964         ParseError("Rule_state: Invalid action - must be a valid "
 4965                    "rule type.");
 4966     }
 4967 
 4968     mSplitFree(&toks, num_toks);
 4969 
 4970     if (sc->rule_state_list == NULL)
 4971     {
 4972         sc->rule_state_list = state;
 4973     }
 4974     else
 4975     {
 4976         state->next = sc->rule_state_list;
 4977         sc->rule_state_list = state;
 4978     }
 4979 }
 4980 
 4981 static void ParseDynamicLibInfo(DynamicLibInfo *dylib_info, char *args)
 4982 {
 4983     char getcwd_path[PATH_MAX];
 4984     char **toks = NULL;
 4985     int num_toks = 0;
 4986     char *path = NULL;
 4987     PathType ptype = PATH_TYPE__FILE;
 4988     DynamicLibPath *dylib_path;
 4989     struct stat buf;
 4990 
 4991     if (dylib_info == NULL)
 4992         return;
 4993 
 4994     if (dylib_info->count >= MAX_DYNAMIC_LIBS)
 4995     {
 4996         ParseError("Maximum number of loaded libriaries of this dynamic "
 4997                    "library type exceeded: %d.", MAX_DYNAMIC_LIBS);
 4998     }
 4999 
 5000     if (args == NULL)
 5001     {
 5002         if (getcwd(getcwd_path, sizeof(getcwd_path)) == NULL)
 5003         {
 5004             ParseError("Dynamic library path too long.  If you really "
 5005                        "think your path needs to be as long as it is, please "
 5006                        "submit a bug to bugs@snort.org.");
 5007         }
 5008 
 5009         path = getcwd_path;
 5010         ptype = PATH_TYPE__DIRECTORY;
 5011     }
 5012     else
 5013     {
 5014         toks = mSplit(args, " \t", 0, &num_toks, 0);
 5015 
 5016         if (num_toks == 1)
 5017         {
 5018             path = toks[0];
 5019             ptype = PATH_TYPE__FILE;
 5020         }
 5021         else if (num_toks == 2)
 5022         {
 5023             if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
 5024             {
 5025                 ptype = PATH_TYPE__FILE;
 5026             }
 5027             else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
 5028             {
 5029                 ptype = PATH_TYPE__DIRECTORY;
 5030             }
 5031             else
 5032             {
 5033                 ParseError("Invalid specifier for Dynamic library specifier.  "
 5034                            "Should be file|directory pathname.");
 5035             }
 5036 
 5037             path = toks[1];
 5038         }
 5039         else
 5040         {
 5041             ParseError("Missing/incorrect dynamic engine lib specifier.");
 5042         }
 5043     }
 5044 
 5045     dylib_path = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath));
 5046     dylib_path->ptype = ptype;
 5047     dylib_path->path = SnortStrdup(path);
 5048 
 5049     dylib_info->lib_paths[dylib_info->count] = dylib_path;
 5050     dylib_info->count++;
 5051 
 5052     if (toks != NULL)
 5053         mSplitFree(&toks, num_toks);
 5054 
 5055     if (stat(dylib_path->path, &buf) == -1)
 5056     {
 5057         ParseError("Could not stat dynamic module path \"%s\": %s.\n",
 5058                    dylib_path->path, strerror(errno));
 5059     }
 5060 
 5061     dylib_path->last_mod_time = buf.st_mtime;
 5062 }
 5063 
 5064 /****************************************************************************
 5065  *
 5066  * Purpose: Parses a dynamic engine line
 5067  *          Format is full path of dynamic engine
 5068  *
 5069  * Arguments: args => string containing a single dynamic engine
 5070  *
 5071  * Returns: void function
 5072  *
 5073  *****************************************************************************/
 5074 static void ParseDynamicEngineInfo(SnortConfig *sc, SnortPolicy *p, char *args)
 5075 {
 5076     if (sc == NULL)
 5077         return;
 5078 
 5079     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicEngine\n"););
 5080 
 5081     if (sc->dyn_engines == NULL)
 5082     {
 5083         sc->dyn_engines = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
 5084         sc->dyn_engines->type = DYNAMIC_TYPE__ENGINE;
 5085     }
 5086 
 5087     ParseDynamicLibInfo(sc->dyn_engines, args);
 5088 }
 5089 
 5090 /****************************************************************************
 5091  *
 5092  * Purpose: Parses a dynamic detection lib line
 5093  *          Format is full path of dynamic engine
 5094  *
 5095  * Arguments: args => string containing a single dynamic engine
 5096  *
 5097  * Returns: void function
 5098  *
 5099  *****************************************************************************/
 5100 static void ParseDynamicDetectionInfo(SnortConfig *sc, SnortPolicy *p, char *args)
 5101 {
 5102     if (sc == NULL)
 5103         return;
 5104 
 5105     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicDetection\n"););
 5106 
 5107     if (sc->dyn_rules == NULL)
 5108     {
 5109         sc->dyn_rules = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
 5110         sc->dyn_rules->type = DYNAMIC_TYPE__DETECTION;
 5111     }
 5112 
 5113     ParseDynamicLibInfo(sc->dyn_rules, args);
 5114 }
 5115 
 5116 /****************************************************************************
 5117  *
 5118  * Purpose: Parses a dynamic preprocessor lib line
 5119  *          Format is full path of dynamic engine
 5120  *
 5121  * Arguments: args => string containing a single dynamic engine
 5122  *
 5123  * Returns: void function
 5124  *
 5125  *****************************************************************************/
 5126 static void ParseDynamicPreprocessorInfo(SnortConfig *sc, SnortPolicy *p, char *args)
 5127 {
 5128     if (sc == NULL)
 5129         return;
 5130 
 5131     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicPreprocessor\n"););
 5132 
 5133     if (sc->dyn_preprocs == NULL)
 5134     {
 5135         sc->dyn_preprocs = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
 5136         sc->dyn_preprocs->type = DYNAMIC_TYPE__PREPROCESSOR;
 5137     }
 5138 
 5139     ParseDynamicLibInfo(sc->dyn_preprocs, args);
 5140 }
 5141 
 5142 # ifdef SIDE_CHANNEL
 5143 
 5144 /****************************************************************************
 5145  *
 5146  * Purpose: Parses a dynamic side channel lib line
 5147  *          Format is full path of dynamic side channel
 5148  *
 5149  * Arguments: args => string containing a single dynamic side channel
 5150  *
 5151  * Returns: void function
 5152  *
 5153  *****************************************************************************/
 5154 static void ParseDynamicSideChannelInfo(SnortConfig *sc, SnortPolicy *p, char *args)
 5155 {
 5156     if (sc == NULL)
 5157         return;
 5158 
 5159     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicSideChannel\n"););
 5160 
 5161     if (sc->dyn_side_channels == NULL)
 5162     {
 5163         sc->dyn_side_channels = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo));
 5164         sc->dyn_side_channels->type = DYNAMIC_TYPE__SIDE_CHANNEL;
 5165     }
 5166 
 5167     ParseDynamicLibInfo(sc->dyn_side_channels, args);
 5168 }
 5169 
 5170 # endif /* SIDE_CHANNEL */
 5171 
 5172 /****************************************************************************
 5173  *
 5174  * Purpose: Parses a dynamic output lib line
 5175  *          Format is full path of dynamic output
 5176  *
 5177  * Arguments: args => string containing a single dynamic output
 5178  *
 5179  * Returns: void function
 5180  *
 5181  *****************************************************************************/
 5182 static void ParseDynamicOutputInfo(SnortConfig *sc, SnortPolicy *p, char *args)
 5183 {
 5184     char **toks = NULL;
 5185     int num_toks = 0;
 5186     char *path = NULL;
 5187     PathType ptype = PATH_TYPE__FILE;
 5188     if (sc == NULL)
 5189         return;
 5190 
 5191     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"DynamicOutput\n"););
 5192 
 5193     if (args == NULL)
 5194     {
 5195         char *getcwd_path = SnortAlloc(PATH_MAX);
 5196 
 5197         if (getcwd(getcwd_path, PATH_MAX) == NULL)
 5198         {
 5199             ParseError("Dynamic library path too long.  If you really "
 5200                     "think your path needs to be as long as it is, please "
 5201                     "submit a bug to bugs@snort.org.");
 5202         }
 5203 
 5204         path = getcwd_path;
 5205         ptype = PATH_TYPE__DIRECTORY;
 5206     }
 5207     else
 5208     {
 5209         toks = mSplit(args, " \t", 0, &num_toks, 0);
 5210 
 5211         if (num_toks == 1)
 5212         {
 5213             path = SnortStrdup(toks[0]);
 5214             ptype = PATH_TYPE__FILE;
 5215         }
 5216         else if (num_toks == 2)
 5217         {
 5218             if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__FILE) == 0)
 5219             {
 5220                 ptype = PATH_TYPE__FILE;
 5221             }
 5222             else if (strcasecmp(toks[0], DYNAMIC_LIB_OPT__DIRECTORY) == 0)
 5223             {
 5224                 ptype = PATH_TYPE__DIRECTORY;
 5225             }
 5226             else
 5227             {
 5228                 ParseError("Invalid specifier for Dynamic library specifier.  "
 5229                         "Should be file|directory pathname.");
 5230             }
 5231 
 5232             path = SnortStrdup(toks[1]);
 5233         }
 5234         else
 5235         {
 5236             ParseError("Missing/incorrect dynamic engine lib specifier.");
 5237         }
 5238         mSplitFree(&toks, num_toks);
 5239     }
 5240     if (ptype == PATH_TYPE__DIRECTORY)
 5241         output_load(path);
 5242     else if (ptype == PATH_TYPE__FILE)
 5243         output_load_module(path);
 5244     if (path)
 5245         free(path);
 5246 
 5247 }
 5248 
 5249 /* verify that we are not reusing some other keyword */
 5250 static int ValidateUserDefinedRuleType(SnortConfig *sc, char *keyword)
 5251 {
 5252     RuleListNode *node;
 5253 
 5254     if ((sc == NULL) || (sc->rule_lists == NULL))
 5255         return 0;
 5256 
 5257     node = sc->rule_lists;
 5258 
 5259     /* This keyword cannot match any of our predefined rule types */
 5260     if (GetRuleType(keyword) != RULE_TYPE__NONE)
 5261         return 0;
 5262 
 5263     /* Walk through the rule list to make sure the user didn't already
 5264      * define this one */
 5265     while (node != NULL)
 5266     {
 5267         if (strcasecmp(node->name, keyword) == 0)
 5268             return 0;
 5269 
 5270         node = node->next;
 5271     }
 5272 
 5273     return 1;
 5274 }
 5275 
 5276 /* This function does nothing.  It is just a place holder in the snort conf
 5277  * keyword array so the keyword can be matched.  Its's a special configuration
 5278  * case in that multiple non-escaped lines need to be read and the current
 5279  * file pointer needs to be passed in. */
 5280 static void ParseRuleTypeDeclaration(SnortConfig *sc, SnortPolicy *p, char *arg)
 5281 {
 5282     return;
 5283 }
 5284 
 5285 static void _ParseRuleTypeDeclaration(SnortConfig *sc, FILE *fp, char *arg, int prules)
 5286 {
 5287     char **toks;
 5288     int num_toks;
 5289     char *input;
 5290     char *rule_type_name;
 5291     RuleType type;
 5292     int rval = 1;
 5293     ListHead *listhead = NULL;
 5294     int got_output = 0;
 5295 
 5296     if ((sc == NULL) || (fp == NULL) || (arg == NULL))
 5297         return;
 5298 
 5299     /* Already parsed this or ignoring for any non-default policy, but need to move past
 5300      * the rule declaration because it doesn't have continuation characters
 5301      */
 5302     if (prules  /* parsing rules */
 5303             || (getParserPolicy(sc) != getDefaultPolicy()))
 5304     {
 5305         while (1)
 5306         {
 5307             input = ReadLine(fp);
 5308             if (input == NULL)
 5309                 ParseError("Rule type declaration syntax error: %s.", arg);
 5310 
 5311             toks = mSplit(input, " \t", 2, &num_toks, 0);
 5312 
 5313             /* Just continue for blank line */
 5314             if (toks == NULL)
 5315             {
 5316                 free (input);
 5317                 continue;
 5318             }
 5319 
 5320             /* Got end of rule type */
 5321             if ((num_toks == 1) && (strcmp(toks[0], "}") == 0))
 5322             {
 5323                 free(input);
 5324                 mSplitFree(&toks, num_toks);
 5325                 break;
 5326             }
 5327 
 5328             free(input);
 5329             mSplitFree(&toks, num_toks);
 5330         }
 5331 
 5332         return;
 5333     }
 5334 
 5335 
 5336     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Rule type declaration\n"););
 5337 
 5338     toks = mSplit(arg, " \t", 2, &num_toks, 0);
 5339 
 5340     /* Need rule type name for creating new node in rule list */
 5341     rule_type_name = SnortStrdup(ExpandVars(sc, toks[0]));
 5342 
 5343     /* Verify keyword is unique */
 5344     if (!ValidateUserDefinedRuleType(sc, rule_type_name))
 5345     {
 5346         ParseError("Duplicate rule type declaration found: %s.", rule_type_name);
 5347     }
 5348 
 5349     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Declaring new rule type: %s\n",
 5350                             rule_type_name););
 5351 
 5352     if (num_toks == 2)
 5353     {
 5354         /* User put '{' on the same line, which is okay */
 5355         if ((toks[1] != NULL) && (strcmp(toks[1], "{") != 0))
 5356         {
 5357             ParseError("Rule type declaration syntax error: %s.", arg);
 5358         }
 5359     }
 5360     else
 5361     {
 5362         /* Get next line.  It should only be '{' */
 5363         input = ReadLine(fp);
 5364         if ((input == NULL) || (strcmp(input, "{") != 0))
 5365         {
 5366             ParseError("Rule type declaration syntax error: %s.", arg);
 5367         }
 5368 
 5369         free(input);
 5370     }
 5371 
 5372     mSplitFree(&toks, num_toks);
 5373 
 5374     input = ReadLine(fp);
 5375     if (input == NULL)
 5376         ParseError("Rule type declaration syntax error: %s.", arg);
 5377 
 5378     toks = mSplit(input, " \t", 2, &num_toks, 0);
 5379     if ((num_toks != 2) ||
 5380         (strcasecmp(toks[0], RULE_TYPE_OPT__TYPE) != 0))
 5381     {
 5382         ParseError("Rule type declaration syntax error: %s.", arg);
 5383     }
 5384 
 5385     type = GetRuleType(toks[1]);
 5386     if (type == RULE_TYPE__NONE)
 5387         ParseError("Invalid type for rule type declaration: %s.", toks[1]);
 5388 
 5389     DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"\ttype(%i): %s\n", type, toks[1]););
 5390 
 5391     if (type == RULE_TYPE__PASS)
 5392         rval = 0;
 5393 
 5394     listhead = CreateRuleType(sc, rule_type_name, type, rval, NULL);
 5395 
 5396     free(rule_type_name);
 5397     free(input);
 5398     mSplitFree(&toks, num_toks);
 5399 
 5400     /* Get output plugin declarations
 5401      * This