"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/detection-plugins/sp_pattern_match.c" (16 Oct 2020, 101695 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 "sp_pattern_match.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 **
    7 ** This program is free software; you can redistribute it and/or modify
    8 ** it under the terms of the GNU General Public License Version 2 as
    9 ** published by the Free Software Foundation.  You may not use, modify or
   10 ** distribute this program under any other version of the GNU General
   11 ** Public License.
   12 **
   13 ** This program is distributed in the hope that it will be useful,
   14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16 ** GNU General Public License for more details.
   17 **
   18 ** You should have received a copy of the GNU General Public License
   19 ** along with this program; if not, write to the Free Software
   20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   21 */
   22 
   23 /*
   24  * 06/07/2007 - tw
   25  * Commented out 'content-list' code since it's considered broken and there
   26  * are no plans to fix it
   27  */
   28 
   29 #ifdef HAVE_CONFIG_H
   30 # include "config.h"
   31 #endif
   32 
   33 #include <errno.h>
   34 #ifdef HAVE_STRINGS_H
   35 # include <strings.h>
   36 #endif
   37 #ifdef DEBUG_MSGS
   38 # include <assert.h>
   39 #endif
   40 
   41 #include "sf_types.h"
   42 #include "sp_pattern_match.h"
   43 #include "sp_replace.h"
   44 #include "snort_bounds.h"
   45 #include "rules.h"
   46 #include "treenodes.h"
   47 #include "plugbase.h"
   48 #include "snort_debug.h"
   49 #include "mstring.h"
   50 #include "hashstring.h"
   51 #include "util.h"
   52 #include "parser.h"
   53 #include "plugin_enum.h"
   54 #include "checksum.h"
   55 #include "sfhashfcn.h"
   56 #include "spp_httpinspect.h"
   57 #include "snort.h"
   58 #include "profiler.h"
   59 #include "sfhashfcn.h"
   60 #include "detection_options.h"
   61 #include "sp_byte_extract.h"
   62 #include "sp_byte_math.h"
   63 #include "detection_util.h"
   64 #include "sf_sechash.h"
   65 
   66 /********************************************************************
   67  * Macros
   68  ********************************************************************/
   69 #define MAX_PATTERN_SIZE 2048
   70 #define PM_FP_ONLY  "only"
   71 
   72 /********************************************************************
   73  * Global variables
   74  ********************************************************************/
   75 #ifdef PERF_PROFILING
   76 PreprocStats contentPerfStats;
   77 PreprocStats uricontentPerfStats;
   78 #endif
   79 int lastType = PLUGIN_PATTERN_MATCH;
   80 
   81 #if 0
   82 /* For OR patterns - not currently used */
   83 int list_file_line;     /* current line being processed in the list file */
   84 #endif
   85 
   86 /********************************************************************
   87  * Extern variables
   88  ********************************************************************/
   89 #ifdef PERF_PROFILING
   90 extern PreprocStats ruleOTNEvalPerfStats;
   91 #endif
   92 
   93 /********************************************************************
   94  * Private function prototypes
   95  ********************************************************************/
   96 static void PayloadSearchInit(struct _SnortConfig *, char *, OptTreeNode *, int);
   97 static void PayloadSearchUri(struct _SnortConfig *, char *, OptTreeNode *, int);
   98 static void PayloadSearchHttpMethod(struct _SnortConfig *, char *, OptTreeNode *, int);
   99 static void PayloadSearchHttpUri(struct _SnortConfig *, char *, OptTreeNode *, int);
  100 static void PayloadSearchHttpHeader(struct _SnortConfig *, char *, OptTreeNode *, int);
  101 static void PayloadSearchHttpCookie(struct _SnortConfig *, char *, OptTreeNode *, int);
  102 static void PayloadSearchHttpBody(struct _SnortConfig *, char *, OptTreeNode *, int);
  103 static void PayloadSearchHttpRawUri(struct _SnortConfig *, char *, OptTreeNode *, int);
  104 static void PayloadSearchHttpRawHeader(struct _SnortConfig *, char *, OptTreeNode *, int);
  105 //static void PayloadSearchHttpRawBody(struct _SnortConfig *, char *, OptTreeNode *, int);
  106 static void PayloadSearchHttpRawCookie(struct _SnortConfig *, char *, OptTreeNode *, int);
  107 static void PayloadSearchHttpStatCode(struct _SnortConfig *, char *, OptTreeNode *, int);
  108 static void PayloadSearchHttpStatMsg(struct _SnortConfig *, char *, OptTreeNode *, int);
  109 static void PayloadSearchOffset(struct _SnortConfig *, char *, OptTreeNode *, int);
  110 static void PayloadSearchDepth(struct _SnortConfig *, char *, OptTreeNode *, int);
  111 static void PayloadSearchDistance(struct _SnortConfig *, char *, OptTreeNode *, int);
  112 static void PayloadSearchWithin(struct _SnortConfig *, char *, OptTreeNode *, int);
  113 static void PayloadSearchNocase(struct _SnortConfig *, char *, OptTreeNode *, int);
  114 static void PayloadSearchRawbytes(struct _SnortConfig *, char *, OptTreeNode *, int);
  115 static void PayloadSearchFastPattern(struct _SnortConfig *, char *, OptTreeNode *, int);
  116 static inline int HasFastPattern(OptTreeNode *, int);
  117 static int32_t ParseInt(const char *, const char *);
  118 static inline PatternMatchData * GetLastPmdError(OptTreeNode *, int, const char *);
  119 static inline PatternMatchData * GetLastPmd(OptTreeNode *, int);
  120 static void ValidateHttpContentModifiers(struct _SnortConfig *, PatternMatchData *);
  121 static void MovePmdToUriDsList(OptTreeNode *, PatternMatchData *);
  122 static char *PayloadExtractParameter(char *, int *);
  123 static inline void ValidateContent(struct _SnortConfig *, PatternMatchData *, int);
  124 static unsigned int GetMaxJumpSize(char *, int);
  125 static int uniSearch(const char *, int, PatternMatchData *);
  126 static int uniSearchReal(const char *data, int dlen, PatternMatchData *pmd, int nocase);
  127 static int uniSearchHash(const char *data, int dlen, PatternMatchData *pmd);
  128 static void PayloadSearchProtected(struct _SnortConfig *, char *, OptTreeNode *, int);
  129 static void PayloadSearchHash(struct _SnortConfig *, char *, OptTreeNode *, int);
  130 static void PayloadSearchLength(struct _SnortConfig *, char *, OptTreeNode *, int);
  131 
  132 #if 0
  133 /* Not currently used - DO NOT REMOVE */
  134 static inline int computeDepth(int dlen, PatternMatchData * pmd);
  135 static int uniSearchREG(char * data, int dlen, PatternMatchData * pmd);
  136 #endif
  137 
  138 #if 0
  139 static const char *format_uri_buffer_str(int, int, char *);
  140 static void PayloadSearchListInit(char *, OptTreeNode *, int);
  141 static void ParseContentListFile(char *, OptTreeNode *, int);
  142 static void PrintDupDOTPmds(PatternMatchData *pmd,
  143         PatternMatchData *pmd_dup, option_type_t type)
  144 #endif
  145 
  146 /********************************************************************
  147  * Setup and parsing functions
  148  ********************************************************************/
  149 void SetupPatternMatch(void)
  150 {
  151     /* initial pmd setup options */
  152     RegisterRuleOption("content", PayloadSearchInit, NULL, OPT_TYPE_DETECTION, NULL);
  153     RegisterRuleOption("uricontent", PayloadSearchUri, NULL, OPT_TYPE_DETECTION, NULL);
  154     RegisterRuleOption("protected_content", PayloadSearchProtected, NULL, OPT_TYPE_DETECTION, NULL);
  155 
  156     /* http content modifiers */
  157     RegisterRuleOption("http_method", PayloadSearchHttpMethod, NULL, OPT_TYPE_DETECTION, NULL);
  158     RegisterRuleOption("http_uri", PayloadSearchHttpUri, NULL, OPT_TYPE_DETECTION, NULL);
  159     RegisterRuleOption("http_header", PayloadSearchHttpHeader, NULL, OPT_TYPE_DETECTION, NULL);
  160     RegisterRuleOption("http_cookie", PayloadSearchHttpCookie, NULL, OPT_TYPE_DETECTION, NULL);
  161     RegisterRuleOption("http_client_body", PayloadSearchHttpBody, NULL, OPT_TYPE_DETECTION, NULL);
  162     RegisterRuleOption("http_raw_uri", PayloadSearchHttpRawUri, NULL, OPT_TYPE_DETECTION, NULL);
  163     RegisterRuleOption("http_raw_header", PayloadSearchHttpRawHeader, NULL, OPT_TYPE_DETECTION, NULL);
  164     /*RegisterRuleOption("http_raw_client_body", PayloadSearchHttpRawBody, NULL, OPT_TYPE_DETECTION, NULL);*/
  165     RegisterRuleOption("http_raw_cookie", PayloadSearchHttpRawCookie, NULL, OPT_TYPE_DETECTION, NULL);
  166     RegisterRuleOption("http_stat_code", PayloadSearchHttpStatCode, NULL, OPT_TYPE_DETECTION, NULL);
  167     RegisterRuleOption("http_stat_msg", PayloadSearchHttpStatMsg, NULL, OPT_TYPE_DETECTION, NULL);
  168 
  169     /* pattern offsets and depths */
  170     RegisterRuleOption("offset", PayloadSearchOffset, NULL, OPT_TYPE_DETECTION, NULL);
  171     RegisterRuleOption("depth", PayloadSearchDepth, NULL, OPT_TYPE_DETECTION, NULL);
  172 
  173     /* distance and within are offset and depth, but relative to last match */
  174     RegisterRuleOption("distance", PayloadSearchDistance, NULL, OPT_TYPE_DETECTION, NULL);
  175     RegisterRuleOption("within", PayloadSearchWithin, NULL, OPT_TYPE_DETECTION, NULL);
  176 
  177     /* other modifiers */
  178     RegisterRuleOption("hash", PayloadSearchHash, NULL, OPT_TYPE_DETECTION, NULL);
  179     RegisterRuleOption("length", PayloadSearchLength, NULL, OPT_TYPE_DETECTION, NULL);
  180     RegisterRuleOption("nocase", PayloadSearchNocase, NULL, OPT_TYPE_DETECTION, NULL);
  181     RegisterRuleOption("rawbytes", PayloadSearchRawbytes, NULL, OPT_TYPE_DETECTION, NULL);
  182     RegisterRuleOption("fast_pattern", PayloadSearchFastPattern, NULL, OPT_TYPE_DETECTION, NULL);
  183     RegisterRuleOption("replace", PayloadReplaceInit, NULL, OPT_TYPE_DETECTION, NULL);
  184 
  185 #if 0
  186     /* Not implemented yet */
  187     RegisterRuleOption("content-list", PayloadSearchListInit, NULL, OPT_TYPE_DETECTION, NULL);
  188 #endif
  189 
  190 #ifdef PERF_PROFILING
  191     RegisterPreprocessorProfile("content", &contentPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
  192     RegisterPreprocessorProfile("uricontent", &uricontentPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
  193 #endif
  194     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  195                 "Plugin: PatternMatch Initialized!\n"););
  196 }
  197 
  198 static void PayloadSearchInit(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  199 {
  200     OptFpList *fpl;
  201     PatternMatchData *pmd;
  202     char *data_end;
  203     char *data_dup;
  204     char *opt_data;
  205     int opt_len = 0;
  206     char *next_opt;
  207 
  208     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchInit()\n"););
  209 
  210     /* whack a new node onto the list */
  211     pmd = NewNode(otn, PLUGIN_PATTERN_MATCH);
  212     lastType = PLUGIN_PATTERN_MATCH;
  213 
  214     if (!data)
  215         ParseError("No Content Pattern specified!");
  216 
  217     data_dup = SnortStrdup(data);
  218     data_end = data_dup + strlen(data_dup);
  219 
  220     opt_data = PayloadExtractParameter(data_dup, &opt_len);
  221 
  222     /* set up the pattern buffer */
  223     ParsePattern(opt_data, otn, PLUGIN_PATTERN_MATCH);
  224     next_opt = opt_data + opt_len;
  225 
  226     /* link the plugin function in to the current OTN */
  227     fpl = AddOptFuncToList(CheckANDPatternMatch, otn);
  228     fpl->type = RULE_OPTION_TYPE_CONTENT;
  229     pmd->buffer_func = CHECK_AND_PATTERN_MATCH;
  230 
  231     fpl->context = pmd;
  232     pmd->fpl = fpl;
  233 
  234     // if content is followed by any comma separated options,
  235     // we have to parse them here.  content related options
  236     // separated by semicolons go straight to the callbacks.
  237     while (next_opt < data_end)
  238     {
  239         char **opts;        /* dbl ptr for mSplit call, holds rule tokens */
  240         int num_opts;       /* holds number of tokens found by mSplit */
  241         char* opt1;
  242 
  243         next_opt++;
  244         if (next_opt == data_end)
  245             break;
  246 
  247         opt_len = 0;
  248         opt_data = PayloadExtractParameter(next_opt, &opt_len);
  249         if (!opt_data)
  250             break;
  251 
  252         next_opt = opt_data + opt_len;
  253 
  254         opts = mSplit(opt_data, " \t", 2, &num_opts, 0);
  255 
  256         if (!opts)
  257             continue;
  258         opt1 = (num_opts == 2) ? opts[1] : NULL;
  259 
  260         if (!strcasecmp(opts[0], "offset"))
  261         {
  262             PayloadSearchOffset(sc, opt1, otn, protocol);
  263         }
  264         else if (!strcasecmp(opts[0], "depth"))
  265         {
  266             PayloadSearchDepth(sc, opt1, otn, protocol);
  267         }
  268         else if (!strcasecmp(opts[0], "nocase"))
  269         {
  270             PayloadSearchNocase(sc, opt1, otn, protocol);
  271         }
  272         else if (!strcasecmp(opts[0], "rawbytes"))
  273         {
  274             PayloadSearchRawbytes(sc, opt1, otn, protocol);
  275         }
  276         else if (!strcasecmp(opts[0], "http_uri"))
  277         {
  278             PayloadSearchHttpUri(sc, opt1, otn, protocol);
  279         }
  280         else if (!strcasecmp(opts[0], "http_client_body"))
  281         {
  282             PayloadSearchHttpBody(sc, opt1, otn, protocol);
  283         }
  284         else if (!strcasecmp(opts[0], "http_header"))
  285         {
  286             PayloadSearchHttpHeader(sc, opt1, otn, protocol);
  287         }
  288         else if (!strcasecmp(opts[0], "http_method"))
  289         {
  290             PayloadSearchHttpMethod(sc, opt1, otn, protocol);
  291         }
  292         else if (!strcasecmp(opts[0], "http_cookie"))
  293         {
  294             PayloadSearchHttpCookie(sc, opt1, otn, protocol);
  295         }
  296         else if (!strcasecmp(opts[0], "http_raw_uri"))
  297         {
  298             PayloadSearchHttpRawUri(sc, opt1, otn, protocol);
  299         }
  300         else if (!strcasecmp(opts[0], "http_raw_header"))
  301         {
  302             PayloadSearchHttpRawHeader(sc, opt1, otn, protocol);
  303         }
  304         else if (!strcasecmp(opts[0], "http_raw_cookie"))
  305         {
  306             PayloadSearchHttpRawCookie(sc, opt1, otn, protocol);
  307         }
  308         else if (!strcasecmp(opts[0], "http_stat_code"))
  309         {
  310             PayloadSearchHttpStatCode(sc, opt1, otn, protocol);
  311         }
  312         else if (!strcasecmp(opts[0], "http_stat_msg"))
  313         {
  314             PayloadSearchHttpStatMsg(sc, opt1, otn, protocol);
  315         }
  316         else if (!strcasecmp(opts[0], "fast_pattern"))
  317         {
  318             PayloadSearchFastPattern(sc, opt1, otn, protocol);
  319         }
  320         else if (!strcasecmp(opts[0], "distance"))
  321         {
  322             PayloadSearchDistance(sc, opt1, otn, protocol);
  323         }
  324         else if (!strcasecmp(opts[0], "within"))
  325         {
  326             PayloadSearchWithin(sc, opt1, otn, protocol);
  327         }
  328         else if (!strcasecmp(opts[0], "replace"))
  329         {
  330             PayloadReplaceInit(sc, opt1, otn, protocol);
  331         }
  332         else
  333         {
  334             ParseError("Invalid Content parameter specified!");
  335         }
  336         mSplitFree(&opts, num_opts);
  337     }
  338 
  339 
  340     free(data_dup);
  341 
  342     if(pmd->use_doe == 1)
  343         fpl->isRelative = 1;
  344 
  345     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  346                 "OTN function PatternMatch Added to rule!\n"););
  347 }
  348 
  349 static void PayloadSearchUri(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  350 {
  351     PatternMatchData *pmd = NewNode(otn, PLUGIN_PATTERN_MATCH_URI);
  352     OptFpList *fpl;
  353 
  354     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchUri()\n"););
  355 
  356     lastType = PLUGIN_PATTERN_MATCH_URI;
  357 
  358     /* set up the pattern buffer */
  359     ParsePattern(data, otn, PLUGIN_PATTERN_MATCH_URI);
  360 
  361     pmd->http_buffer = HTTP_BUFFER_URI;
  362 
  363     /* link the plugin function in to the current OTN */
  364     fpl = AddOptFuncToList(CheckUriPatternMatch, otn);
  365 
  366     fpl->type = RULE_OPTION_TYPE_CONTENT_URI;
  367     pmd->buffer_func = CHECK_URI_PATTERN_MATCH;
  368 
  369     fpl->context = pmd;
  370     pmd->fpl = fpl;
  371 
  372     if (pmd->use_doe == 1)
  373         fpl->isRelative = 1;
  374 
  375     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  376                 "OTN function PatternMatch Added to rule!\n"););
  377 }
  378 
  379 void PayloadSearchProtected(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  380 {
  381     OptFpList *fpl;
  382     PatternMatchData *pmd;
  383 
  384     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchProtected()\n"););
  385 
  386     /* whack a new node onto the list */
  387     pmd = NewNode(otn, PLUGIN_PATTERN_MATCH);
  388     lastType = PLUGIN_PATTERN_MATCH;
  389 
  390     if (!data)
  391         ParseError("No Protected Content Pattern specified!");
  392 
  393     /* The default secure hash type is set in the SnortConfig */
  394     pmd->pattern_type = sc->Default_Protected_Content_Hash_Type;
  395 
  396     /* set up the pattern buffer */
  397     ParseProtectedPattern(data, otn, PLUGIN_PATTERN_MATCH);
  398 
  399     /* link the plugin function in to the current OTN */
  400     fpl = AddOptFuncToList(CheckANDPatternMatch, otn);
  401     fpl->type = RULE_OPTION_TYPE_CONTENT;
  402     pmd->buffer_func = CHECK_AND_PATTERN_MATCH;
  403     pmd->protected_pattern = true;
  404 
  405     fpl->context = pmd;
  406     pmd->fpl = fpl;
  407 
  408     if(pmd->use_doe == 1)
  409         fpl->isRelative = 1;
  410 
  411     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
  412                 "OTN function PatternMatchProtected Added to rule!\n"););
  413 }
  414 static void PayloadSearchHttpMethod(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  415 {
  416     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_method");
  417 
  418     if (data != NULL)
  419         ParseError("'http_method' does not take an argument");
  420 
  421     if ( pmd->http_buffer )
  422         ParseWarning("at most one http buffer can be specified per content option");
  423 
  424     pmd->http_buffer = HTTP_BUFFER_METHOD;
  425     MovePmdToUriDsList(otn, pmd);
  426 }
  427 
  428 static void PayloadSearchHttpUri(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  429 {
  430     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_uri");
  431 
  432     if (data != NULL)
  433         ParseError("'http_uri' does not take an argument");
  434 
  435     if ( pmd->http_buffer )
  436         ParseWarning("at most one http buffer can be specified per content option");
  437 
  438     pmd->http_buffer = HTTP_BUFFER_URI;
  439     MovePmdToUriDsList(otn, pmd);
  440 }
  441 
  442 static void PayloadSearchHttpHeader(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  443 {
  444     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_header");
  445 
  446     if (data != NULL)
  447         ParseError("'http_header' does not take an argument");
  448 
  449     if ( pmd->http_buffer )
  450         ParseWarning("at most one http buffer can be specified per content option");
  451 
  452     pmd->http_buffer = HTTP_BUFFER_HEADER;
  453     MovePmdToUriDsList(otn, pmd);
  454 }
  455 
  456 static void PayloadSearchHttpCookie(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  457 {
  458     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_cookie");
  459 
  460     if (data != NULL)
  461         ParseError("'http_cookie' does not take an argument");
  462 
  463     if ( pmd->http_buffer )
  464         ParseWarning("at most one http buffer can be specified per content option");
  465 
  466     pmd->http_buffer = HTTP_BUFFER_COOKIE;
  467     MovePmdToUriDsList(otn, pmd);
  468 }
  469 
  470 static void PayloadSearchHttpBody(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  471 {
  472     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_client_body");
  473 
  474     if (data != NULL)
  475         ParseError("'http_client_body' does not take an argument");
  476 
  477     if ( pmd->http_buffer )
  478         ParseWarning("at most one http buffer can be specified per content option");
  479 
  480     pmd->http_buffer = HTTP_BUFFER_CLIENT_BODY;
  481     MovePmdToUriDsList(otn, pmd);
  482 }
  483 
  484 static void PayloadSearchHttpRawUri(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  485 {
  486     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_raw_uri");
  487 
  488     if (data != NULL)
  489         ParseError("'http_raw_uri' does not take an argument");
  490 
  491     if ( pmd->http_buffer )
  492         ParseWarning("at most one http buffer can be specified per content option");
  493 
  494     pmd->http_buffer = HTTP_BUFFER_RAW_URI;
  495     MovePmdToUriDsList(otn, pmd);
  496 }
  497 
  498 static void PayloadSearchHttpRawHeader(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  499 {
  500     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_raw_header");
  501 
  502     if (data != NULL)
  503         ParseError("'http_raw_header' does not take an argument");
  504 
  505     if ( pmd->http_buffer )
  506         ParseWarning("at most one http buffer can be specified per content option");
  507 
  508     pmd->http_buffer = HTTP_BUFFER_RAW_HEADER;
  509     MovePmdToUriDsList(otn, pmd);
  510 }
  511 static void PayloadSearchHttpRawCookie(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  512 {
  513     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_raw_cookie");
  514 
  515     if (data != NULL)
  516         ParseError("'http_raw_cookie' does not take an argument");
  517 
  518     if ( pmd->http_buffer )
  519         ParseWarning("at most one http buffer can be specified per content option");
  520 
  521     pmd->http_buffer = HTTP_BUFFER_RAW_COOKIE;
  522     MovePmdToUriDsList(otn, pmd);
  523 }
  524 static void PayloadSearchHttpStatCode(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  525 {
  526     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_stat_code");
  527 
  528     if (data != NULL)
  529         ParseError("'http_stat_code' does not take an argument");
  530 
  531     if ( pmd->http_buffer )
  532         ParseWarning("at most one http buffer can be specified per content option");
  533 
  534     pmd->http_buffer = HTTP_BUFFER_STAT_CODE;
  535     MovePmdToUriDsList(otn, pmd);
  536 }
  537 static void PayloadSearchHttpStatMsg(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  538 {
  539     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "http_stat_msg");
  540 
  541     if (data != NULL)
  542         ParseError("'http_stat_msg' does not take an argument");
  543 
  544     if ( pmd->http_buffer )
  545         ParseWarning("at most one http buffer can be specified per content option");
  546 
  547     pmd->http_buffer = HTTP_BUFFER_STAT_MSG;
  548     MovePmdToUriDsList(otn, pmd);
  549 }
  550 
  551 typedef enum {
  552     CMF_DISTANCE = 0x1, CMF_WITHIN = 0x2, CMF_OFFSET = 0x4, CMF_DEPTH = 0x8, CMF_PROT = 0x10
  553 } ContentModifierFlags;
  554 
  555 static unsigned GetCMF (PatternMatchData* pmd)
  556 {
  557     unsigned cmf = 0;
  558     if ( (pmd->distance != 0) || (pmd->distance_var != -1) ) cmf |= CMF_DISTANCE;
  559     if ( (pmd->within != PMD_WITHIN_UNDEFINED) || (pmd->within_var != -1) ) cmf |= CMF_WITHIN;
  560     if ( (pmd->offset != 0) || (pmd->offset_var != -1) ) cmf |= CMF_OFFSET;
  561     if ( (pmd->depth != 0) || (pmd->depth_var != -1) ) cmf |= CMF_DEPTH;
  562     if ( pmd->protected_pattern ) cmf |= CMF_PROT;
  563     return cmf;
  564 }
  565 
  566 #define BAD_DISTANCE (CMF_DISTANCE | CMF_OFFSET | CMF_DEPTH)
  567 #define BAD_WITHIN (CMF_WITHIN | CMF_OFFSET | CMF_DEPTH | CMF_PROT)
  568 #define BAD_OFFSET (CMF_OFFSET | CMF_DISTANCE | CMF_WITHIN)
  569 #define BAD_DEPTH (CMF_DEPTH | CMF_DISTANCE | CMF_WITHIN | CMF_PROT)
  570 
  571 static void PayloadSearchOffset(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  572 {
  573     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "offset");
  574 
  575     if ( GetCMF(pmd) & BAD_OFFSET )
  576         ParseError("offset can't be used with itself, distance, or within");
  577 
  578     if (data == NULL)
  579         ParseError("Missing argument to 'offset' option");
  580 
  581     if (isdigit(data[0]) || data[0] == '-')
  582     {
  583         pmd->offset = ParseInt(data, "offset");
  584     }
  585     else
  586     {
  587         pmd->offset_var = find_value(data);
  588         if (pmd->offset_var == BYTE_EXTRACT_NO_VAR)
  589         {
  590             ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "offset", data);
  591         }
  592     }
  593 
  594     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Pattern offset = %d\n",
  595                 pmd->offset););
  596 }
  597 
  598 static void PayloadSearchDepth(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  599 {
  600     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "depth");
  601 
  602     if ( GetCMF(pmd) & BAD_DEPTH )
  603         ParseError("depth can't be used with itself, protected, distance, or within");
  604 
  605     if (data == NULL)
  606         ParseError("Missing argument to 'depth' option");
  607 
  608     if (isdigit(data[0]) || data[0] == '-')
  609     {
  610         pmd->depth = ParseInt(data, "depth");
  611 
  612         /* check to make sure that this the depth allows this rule to fire */
  613         if ((!pmd->protected_pattern) && (pmd->depth < (int)pmd->pattern_size))
  614         {
  615             ParseError("The depth (%d) is less than the size of the content(%u)!",
  616                     pmd->depth, pmd->pattern_size);
  617         }
  618     }
  619     else
  620     {
  621         pmd->depth_var = find_value(data);
  622         if (pmd->depth_var == BYTE_EXTRACT_NO_VAR)
  623         {
  624             ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "depth", data);
  625         }
  626     }
  627 
  628     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern depth = %d\n",
  629                 pmd->depth););
  630 }
  631 
  632 static void PayloadSearchDistance(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
  633 {
  634     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "distance");
  635 
  636     if ( GetCMF(pmd) & BAD_DISTANCE )
  637         ParseError("distance can't be used with itself, offset, or depth");
  638 
  639     if (data == NULL)
  640         ParseError("Missing argument to 'distance' option");
  641 
  642     if (isdigit(data[0]) || data[0] == '-')
  643     {
  644         pmd->distance = ParseInt(data, "distance");
  645     }
  646     else
  647     {
  648         pmd->distance_var = find_value(data);
  649         if (pmd->distance_var == BYTE_EXTRACT_NO_VAR)
  650         {
  651             ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "distance", data);
  652         }
  653     }
  654 
  655     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern distance = %d\n",
  656                 pmd->distance););
  657 
  658     /* Only do a relative search if this is a normal content match. */
  659     if (lastType == PLUGIN_PATTERN_MATCH ||  lastType == PLUGIN_PATTERN_MATCH_URI)
  660     {
  661         pmd->use_doe = 1;
  662         pmd->fpl->isRelative = 1;
  663     }
  664 }
  665 
  666 static void PayloadSearchWithin(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
  667 {
  668     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "within");
  669 
  670     if ( GetCMF(pmd) & BAD_WITHIN )
  671         ParseError("within can't be used with itself, protected, offset, or depth");
  672 
  673     if (data == NULL)
  674         ParseError("Missing argument to 'within' option");
  675 
  676     if (isdigit(data[0]) || data[0] == '-')
  677     {
  678         pmd->within = ParseInt(data, "within");
  679 
  680         if (!pmd->protected_pattern && (pmd->within < pmd->pattern_size))
  681             ParseError("within (%d) is smaller than size of pattern", pmd->within);
  682     }
  683     else
  684     {
  685         pmd->within_var = find_value(data);
  686         if (pmd->within_var == BYTE_EXTRACT_NO_VAR)
  687         {
  688             ParseError(BYTE_EXTRACT_INVALID_ERR_FMT, "within", data);
  689         }
  690     }
  691 
  692     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern within = %d\n",
  693                 pmd->within););
  694 
  695     /* Only do a relative search if this is a normal content match. */
  696     if (lastType == PLUGIN_PATTERN_MATCH || lastType == PLUGIN_PATTERN_MATCH_URI)
  697     {
  698         pmd->use_doe = 1;
  699         pmd->fpl->isRelative = 1;
  700     }
  701 }
  702 
  703 static void PayloadSearchNocase(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  704 {
  705     unsigned int i;
  706     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "nocase");
  707 
  708     if (data != NULL)
  709         ParseError("'nocase' does not take an argument");
  710     if (pmd->protected_pattern)
  711         ParseError("'nocase' not useable with protected content");
  712 
  713    for (i = 0; i < pmd->pattern_size; i++)
  714         pmd->pattern_buf[i] = toupper((int)pmd->pattern_buf[i]);
  715 
  716     pmd->nocase = 1;
  717 
  718     pmd->search = uniSearchCI;
  719     make_precomp(pmd);
  720 }
  721 
  722 static void PayloadSearchRawbytes(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  723 {
  724     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "rawbytes");
  725 
  726     if (data != NULL)
  727         ParseError("'rawbytes' does not take an argument");
  728 
  729     /* mark this as inspecting a raw pattern match rather than a
  730      * decoded application buffer */
  731     pmd->rawbytes = 1;
  732 }
  733 
  734 static void PayloadSearchFastPattern(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
  735 {
  736     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "fast_pattern");
  737 
  738     /* There can only be one fast pattern content in the rule, whether
  739      * normal, http or other */
  740     if (pmd->fp)
  741     {
  742         ParseError("Cannot set fast_pattern modifier more than once "
  743                 "for the same \"content\".");
  744     }
  745     if( pmd->protected_pattern )
  746         ParseError("Cannot set fast_pattern modifier with protected content");
  747 
  748     if (HasFastPattern(otn, PLUGIN_PATTERN_MATCH))
  749         ParseError("Can only use the fast_pattern modifier once in a rule.");
  750     if (HasFastPattern(otn, PLUGIN_PATTERN_MATCH_URI))
  751         ParseError("Can only use the fast_pattern modifier once in a rule.");
  752     //if (HasFastPattern(otn, PLUGIN_PATTERN_MATCH_OR))
  753     //    ParseError("Can only use the fast_pattern modifier once in a rule.");
  754 
  755     pmd->fp = 1;
  756 
  757     if (data != NULL)
  758     {
  759         char *error_str = "Rule option \"fast_pattern\": Invalid parameter: "
  760             "\"%s\".  Valid parameters are: \"only\" | <offset>,<length>.  "
  761             "Offset and length must be integers less than 65536, offset cannot "
  762             "be negative, length must be positive and (offset + length) must "
  763             "evaluate to less than or equal to the actual pattern length.  "
  764             "Pattern length: %u";
  765 
  766         if (isdigit((int)*data))
  767         {
  768             /* Specifying offset and length of pattern to use for
  769              * fast pattern matcher */
  770 
  771             long int offset, length;
  772             char *endptr;
  773             char **toks;
  774             int num_toks;
  775 
  776             toks = mSplit(data, ",", 0, &num_toks, 0);
  777             if (num_toks != 2)
  778             {
  779                 mSplitFree(&toks, num_toks);
  780                 ParseError(error_str, data, pmd->pattern_size);
  781             }
  782 
  783             offset = SnortStrtol(toks[0], &endptr, 0);
  784             if ((errno == ERANGE) || (*endptr != '\0')
  785                     || (offset < 0) || (offset > UINT16_MAX))
  786             {
  787                 mSplitFree(&toks, num_toks);
  788                 ParseError(error_str, data, pmd->pattern_size);
  789             }
  790 
  791             length = SnortStrtol(toks[1], &endptr, 0);
  792             if ((errno == ERANGE) || (*endptr != '\0')
  793                     || (length <= 0) || (length > UINT16_MAX))
  794             {
  795                 mSplitFree(&toks, num_toks);
  796                 ParseError(error_str, data, pmd->pattern_size);
  797             }
  798 
  799             mSplitFree(&toks, num_toks);
  800 
  801             if ((int)pmd->pattern_size < (offset + length))
  802                 ParseError(error_str, data, pmd->pattern_size);
  803 
  804             pmd->fp_offset = (uint16_t)offset;
  805             pmd->fp_length = (uint16_t)length;
  806         }
  807         else
  808         {
  809             /* Specifies that this content should only be used for
  810              * fast pattern matching */
  811 
  812             if (strcasecmp(data, PM_FP_ONLY) != 0)
  813                 ParseError(error_str, data, pmd->pattern_size);
  814 
  815             pmd->fp_only = 1;
  816         }
  817     }
  818 }
  819 
  820 static void PayloadSearchHash(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  821 {
  822     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "hash");
  823 
  824     if (data == NULL)
  825         ParseError("Missing argument to 'hash' option");
  826 
  827     if (!pmd->protected_pattern)
  828         ParseError("hash modifier is only valid with protected_content");
  829 
  830     /* strip any whitespace for good measure */
  831     while( (*data != '\0') && isspace(*data) )
  832         data += 1;
  833 
  834     if( (pmd->pattern_type = SecHash_Name2Type((const char *)data)) == SECHASH_NONE )
  835         ParseError("Bad hash type: '%s'", data);
  836 
  837     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Hash type = %d\n",
  838                 pmd->pattern_type););
  839 }
  840 
  841 static void PayloadSearchLength(struct _SnortConfig *sc, char *data, OptTreeNode * otn, int protocol)
  842 {
  843     PatternMatchData *pmd = GetLastPmdError(otn, lastType, "length");
  844 
  845     if (data == NULL)
  846         ParseError("Missing argument to 'length' option");
  847 
  848     if (!pmd->protected_pattern)
  849         ParseError("length modifier is only valid with protected_content");
  850 
  851     if (isdigit(data[0]))
  852     {
  853         pmd->protected_length = ParseInt(data, "length");
  854         if( (pmd->protected_length <= 0) || (pmd->protected_length > 65536))
  855             ParseError("length must be greater than zero");
  856     }
  857     else
  858     {
  859         ParseError("Illegal length: %s", data);
  860     }
  861 
  862     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Plaintext length = %d\n",
  863                 pmd->protected_length););
  864 }
  865 
  866 static inline int HasFastPattern(OptTreeNode *otn, int list_type)
  867 {
  868     PatternMatchData *tmp;
  869 
  870     if ((otn == NULL) || (otn->ds_list[list_type] == NULL))
  871         return 0;
  872 
  873     for (tmp = otn->ds_list[list_type]; tmp != NULL; tmp = tmp->next)
  874     {
  875         if (tmp->fp)
  876             return 1;
  877     }
  878 
  879     return 0;
  880 }
  881 
  882 PatternMatchData * NewNode(OptTreeNode *otn, int type)
  883 {
  884     PatternMatchData *pmd = NULL;
  885 
  886     if (otn->ds_list[type] == NULL)
  887     {
  888         otn->ds_list[type] = (PatternMatchData *)SnortAlloc(sizeof(PatternMatchData));
  889         pmd = otn->ds_list[type];
  890     }
  891     else
  892     {
  893         pmd = GetLastPmd(otn, type);
  894         if (pmd != NULL)
  895         {
  896             pmd->next = (PatternMatchData *)SnortAlloc(sizeof(PatternMatchData));
  897             pmd->next->prev = pmd;
  898             pmd = pmd->next;
  899         }
  900         else
  901         {
  902             return NULL;
  903         }
  904     }
  905 
  906     /* Set any non-zero default values here. */
  907     pmd->offset_var = BYTE_EXTRACT_NO_VAR;
  908     pmd->depth_var = BYTE_EXTRACT_NO_VAR;
  909     pmd->distance_var = BYTE_EXTRACT_NO_VAR;
  910     pmd->within_var = BYTE_EXTRACT_NO_VAR;
  911     pmd->within = PMD_WITHIN_UNDEFINED;
  912 
  913     pmd->protected_pattern = false;
  914     pmd->protected_length = 0;
  915     return pmd;
  916 }
  917 
  918 void PatternMatchFree(void *d)
  919 {
  920     PatternMatchData *pmd = (PatternMatchData *)d;
  921 
  922     if (pmd == NULL)
  923         return;
  924 
  925     (void)RemovePmdFromList(pmd);
  926 
  927     if (pmd->pattern_buf)
  928         free(pmd->pattern_buf);
  929     if (pmd->replace_buf)
  930         free(pmd->replace_buf);
  931     if(pmd->skip_stride)
  932         free(pmd->skip_stride);
  933     if(pmd->shift_stride)
  934         free(pmd->shift_stride);
  935 
  936     free(pmd);
  937 }
  938 
  939 static int32_t ParseInt(const char* data, const char* tag)
  940 {
  941     int32_t value = 0;
  942     char *endptr = NULL;
  943 
  944     value = SnortStrtol(data, &endptr, 10);
  945 
  946     if (*endptr)
  947         ParseError("Invalid '%s' format.", tag);
  948 
  949     if (errno == ERANGE)
  950         ParseError("Range problem on '%s' value.", tag);
  951 
  952     if ((value > 65535) || (value < -65535))
  953         ParseError("'%s' must in -65535:65535", tag);
  954 
  955     return value;
  956 }
  957 
  958 /* Used for content modifiers that are used as rule options - need to get the
  959  * last pmd which is the one they are modifying.  If there isn't a last pmd
  960  * error that a content must be specified before the modifier */
  961 static inline PatternMatchData * GetLastPmdError(OptTreeNode *otn, int type, const char *option)
  962 {
  963     PatternMatchData *pmd = GetLastPmd(otn, type);
  964 
  965     if (pmd == NULL)
  966     {
  967         ParseError("Please place \"content\" rules before \"%s\" modifier",
  968                 option == NULL ? "unknown" : option);
  969     }
  970 
  971     return pmd;
  972 }
  973 
  974 /* Gets the last pmd in the ds_list specified */
  975 static inline PatternMatchData * GetLastPmd(OptTreeNode *otn, int type)
  976 {
  977     PatternMatchData *pmd;
  978 
  979     if ((otn == NULL) || (otn->ds_list[type] == NULL))
  980         return NULL;
  981 
  982     for (pmd = otn->ds_list[type]; pmd->next != NULL; pmd = pmd->next);
  983     return pmd;
  984 }
  985 
  986 static void ValidateProtectedContentModifiers(struct _SnortConfig *sc, PatternMatchData *pmd)
  987 {
  988     unsigned int length;
  989 
  990     if (pmd == NULL)
  991         ParseError("Please place \"content\" rules before protected content modifiers");
  992 
  993     if( (length = SecHash_Type2Length(pmd->pattern_type)) == 0 )
  994         ParseError("Bad pattern type");
  995 
  996     if( pmd->pattern_size != length )
  997         ParseError("Bad protected pattern hash digest length");
  998 
  999     /* We NEED a specified pattern length (for this implementation) */
 1000     if( (pmd->protected_length <= 0) || (pmd->protected_length > 65536))
 1001         ParseError("No length or invalid length specified for protected_content rule"); 
 1002 
 1003     /* At this point, we have a properly specified protected content rule with a pattern length.
 1004        Since have the pattern size, we can place it in ->pattern_size for the runtime
 1005        processing.  If/when protected content searching expands beyond fixed ('specified')
 1006        patterns, this approach needs to be revisted. */
 1007     pmd->pattern_size = pmd->protected_length;
 1008 
 1009 }
 1010 
 1011 /* Options that can't be used with http content modifiers.  Additionally
 1012  * http_inspect preprocessor needs to be enabled */
 1013 static void ValidateHttpContentModifiers(struct _SnortConfig *sc, PatternMatchData *pmd)
 1014 {
 1015     if (pmd == NULL)
 1016         ParseError("Please place \"content\" rules before http content modifiers");
 1017 
 1018 /* TBD-EDM - verify this is handled correctly */
 1019 #if 0
 1020     if (!IsPreprocEnabled(sc, PP_HTTPINSPECT))
 1021     {
 1022         ParseError("Please enable the HTTP Inspect preprocessor "
 1023                 "before using the http content modifiers");
 1024     }
 1025 #endif 
 1026 
 1027     if (pmd->replace_buf != NULL)
 1028     {
 1029         ParseError("\"replace\" option is not supported in conjunction with "
 1030                 "http content modifiers");
 1031     }
 1032 
 1033     if (pmd->rawbytes == 1)
 1034     {
 1035         ParseError("Cannot use 'rawbytes' and http content as modifiers for "
 1036                 "the same \"content\"");
 1037     }
 1038 }
 1039 
 1040 /* This is used if we get an http content modifier, since specifying "content"
 1041  * defaults to the PLUGIN_PATTERN_MATCH list.  We need to move the pmd to the
 1042  * PLUGIN_PATTERN_MATCH_URI list */
 1043 static void MovePmdToUriDsList(OptTreeNode *otn, PatternMatchData *pmd)
 1044 {
 1045     int type = PLUGIN_PATTERN_MATCH_URI;
 1046 
 1047     /* It's not currently in the correct list */
 1048     if (lastType != type)
 1049     {
 1050         /* Just in case it's moved from the middle of the list */
 1051         if (pmd->prev != NULL)
 1052             pmd->prev->next = pmd->next;
 1053         if (pmd->next != NULL)
 1054             pmd->next->prev = pmd->prev;
 1055 
 1056         /* Reset pointers */
 1057         pmd->next = NULL;
 1058         pmd->prev = NULL;
 1059 
 1060         if (otn->ds_list[type] == NULL)
 1061         {
 1062             otn->ds_list[type] = pmd;
 1063         }
 1064         else
 1065         {
 1066             /* Make it the last in the URI list */
 1067             PatternMatchData *tmp;
 1068             for (tmp = otn->ds_list[type]; tmp->next != NULL; tmp = tmp->next);
 1069             tmp->next = pmd;
 1070             pmd->prev = tmp;
 1071         }
 1072 
 1073         /* Set the last type to the URI list */
 1074         lastType = type;
 1075 
 1076         /* Reset these to URI type */
 1077         pmd->fpl->OptTestFunc = CheckUriPatternMatch;
 1078         pmd->fpl->type = RULE_OPTION_TYPE_CONTENT_URI;
 1079         pmd->buffer_func = CHECK_URI_PATTERN_MATCH;
 1080     }
 1081 }
 1082 
 1083 #if 0
 1084 /* Not currently used */
 1085 static void PrintDupDOTPmds(PatternMatchData *pmd,
 1086         PatternMatchData *pmd_dup, option_type_t type)
 1087 {
 1088     int i;
 1089 
 1090     if ((pmd == NULL) || (pmd_dup == NULL))
 1091         return;
 1092 
 1093     LogMessage("Duplicate %sContent:\n"
 1094             "%d %d %d %d %d %d %d %d %d %d\n"
 1095             "%d %d %d %d %d %d %d %d %d %d\n",
 1096             option_type == RULE_OPTION_TYPE_CONTENT ? "" : "Uri",
 1097             pmd->exception_flag,
 1098             pmd->offset,
 1099             pmd->depth,
 1100             pmd->distance,
 1101             pmd->within,
 1102             pmd->rawbytes,
 1103             pmd->nocase,
 1104             pmd->use_doe,
 1105             pmd->http_buffer,
 1106             pmd->pattern_max_jump_size,
 1107             pmd_dup->exception_flag,
 1108             pmd_dup->offset,
 1109             pmd_dup->depth,
 1110             pmd_dup->distance,
 1111             pmd_dup->within,
 1112             pmd_dup->rawbytes,
 1113             pmd_dup->nocase,
 1114             pmd_dup->use_doe,
 1115             pmd_dup->http_buffer,
 1116             pmd_dup->pattern_max_jump_size);
 1117 
 1118     for (i = 0; i < pmd->pattern_size; i++)
 1119         LogMessage("0x%x 0x%x", pmd->pattern_buf[i], pmd_dup->pattern_buf[i]);
 1120     LogMessage("\n");
 1121     for (i = 0; i < pmd->replace_size; i++)
 1122         LogMessage("0x%x 0x%x", pmd->replace_buf[i], pmd_dup->replace_buf[i]);
 1123     LogMessage("\n");
 1124     LogMessage("\n");
 1125 }
 1126 #endif
 1127 
 1128 /********************************************************************
 1129  * Functions for detection option tree hashing and comparison
 1130  * and other detection option tree uses
 1131  ********************************************************************/
 1132 uint32_t PatternMatchHash(void *d)
 1133 {
 1134     uint32_t a,b,c,tmp;
 1135     unsigned int i,j,k,l;
 1136     PatternMatchData *pmd = (PatternMatchData *)d;
 1137 
 1138     a = pmd->exception_flag;
 1139     b = pmd->offset;
 1140     c = pmd->depth;
 1141 
 1142     mix(a,b,c);
 1143 
 1144     a += pmd->distance;
 1145     b += pmd->within;
 1146     c += pmd->rawbytes;
 1147 
 1148     mix(a,b,c);
 1149 
 1150     a += pmd->nocase;
 1151     b += pmd->use_doe;
 1152     c += pmd->http_buffer;
 1153 
 1154     mix(a,b,c);
 1155 
 1156     a += pmd->pattern_size;
 1157     b += pmd->replace_size;
 1158     c += pmd->pattern_max_jump_size;
 1159 
 1160     mix(a,b,c);
 1161 
 1162     for (i=0,j=0;i<pmd->pattern_size;i+=4)
 1163     {
 1164         tmp = 0;
 1165         k = pmd->pattern_size - i;
 1166         if (k > 4)
 1167             k=4;
 1168 
 1169         for (l=0;l<k;l++)
 1170         {
 1171             tmp |= *(pmd->pattern_buf + i + l) << l*8;
 1172         }
 1173 
 1174         switch (j)
 1175         {
 1176             case 0:
 1177                 a += tmp;
 1178                 break;
 1179             case 1:
 1180                 b += tmp;
 1181                 break;
 1182             case 2:
 1183                 c += tmp;
 1184                 break;
 1185         }
 1186         j++;
 1187 
 1188         if (j == 3)
 1189         {
 1190             mix(a,b,c);
 1191             j = 0;
 1192         }
 1193     }
 1194 
 1195     for (i=0;i<pmd->replace_size;i+=4)
 1196     {
 1197         tmp = 0;
 1198         k = pmd->replace_size - i;
 1199         if (k > 4)
 1200             k=4;
 1201 
 1202         for (l=0;l<k;l++)
 1203         {
 1204             tmp |= *(pmd->replace_buf + i + l) << l*8;
 1205         }
 1206 
 1207         switch (j)
 1208         {
 1209             case 0:
 1210                 a += tmp;
 1211                 break;
 1212             case 1:
 1213                 b += tmp;
 1214                 break;
 1215             case 2:
 1216                 c += tmp;
 1217                 break;
 1218         }
 1219         j++;
 1220 
 1221         if (j == 3)
 1222         {
 1223             mix(a,b,c);
 1224             j = 0;
 1225         }
 1226     }
 1227 
 1228     if (j != 0)
 1229     {
 1230         mix(a,b,c);
 1231     }
 1232 
 1233     if (pmd->http_buffer)
 1234     {
 1235         a += RULE_OPTION_TYPE_CONTENT_URI;
 1236     }
 1237     else
 1238     {
 1239         a += RULE_OPTION_TYPE_CONTENT;
 1240     }
 1241 
 1242     b += pmd->fp;
 1243     c += pmd->fp_only;
 1244 
 1245     mix(a,b,c);
 1246 
 1247     a += pmd->fp_offset;
 1248     b += pmd->fp_length;
 1249     c += pmd->offset_var;
 1250 
 1251     mix(a,b,c);
 1252 
 1253     a += pmd->depth_var;
 1254     b += pmd->distance_var;
 1255     c += pmd->within_var;
 1256 
 1257     if( pmd->protected_pattern )
 1258     {
 1259         mix(a,b,c);
 1260         a += 1;
 1261         b += pmd->pattern_type;
 1262         c += pmd->protected_length;
 1263     }
 1264     final(a,b,c);
 1265 
 1266     return c;
 1267 }
 1268 
 1269 int PatternMatchCompare(void *l, void *r)
 1270 {
 1271     PatternMatchData *left = (PatternMatchData *)l;
 1272     PatternMatchData *right = (PatternMatchData *)r;
 1273     unsigned int i;
 1274 
 1275     if (!left || !right)
 1276         return DETECTION_OPTION_NOT_EQUAL;
 1277 
 1278     if (left->buffer_func != right->buffer_func)
 1279         return DETECTION_OPTION_NOT_EQUAL;
 1280 
 1281     /* Sizes will be most different, check that first */
 1282     if ((left->pattern_size != right->pattern_size) ||
 1283         (left->replace_size != right->replace_size) ||
 1284         (left->nocase != right->nocase))
 1285         return DETECTION_OPTION_NOT_EQUAL;
 1286 
 1287     /* Next compare the patterns for uniqueness */
 1288     if (left->pattern_size)
 1289     {
 1290         if (left->nocase)
 1291         {
 1292             /* If nocase is set, do case insensitive compare on pattern */
 1293             for (i=0;i<left->pattern_size;i++)
 1294             {
 1295                 if (toupper(left->pattern_buf[i]) != toupper(right->pattern_buf[i]))
 1296                 {
 1297                     return DETECTION_OPTION_NOT_EQUAL;
 1298                 }
 1299             }
 1300         }
 1301         else
 1302         {
 1303             /* If nocase is not set, do case sensitive compare on pattern */
 1304             if (memcmp(left->pattern_buf, right->pattern_buf, left->pattern_size) != 0)
 1305             {
 1306                 return DETECTION_OPTION_NOT_EQUAL;
 1307             }
 1308         }
 1309     }
 1310 
 1311     /* Check the replace pattern if exists */
 1312     if (left->replace_size)
 1313     {
 1314         if (memcmp(left->replace_buf, right->replace_buf, left->replace_size) != 0)
 1315         {
 1316             return DETECTION_OPTION_NOT_EQUAL;
 1317         }
 1318     }
 1319 
 1320     /* Now check the rest of the options */
 1321     if ((left->exception_flag == right->exception_flag) &&
 1322         (left->offset == right->offset) &&
 1323         (left->depth == right->depth) &&
 1324         (left->distance == right->distance) &&
 1325         (left->within == right->within) &&
 1326         (left->rawbytes == right->rawbytes) &&
 1327         (left->use_doe == right->use_doe) &&
 1328         (left->http_buffer == right->http_buffer) &&
 1329         (left->search == right->search) &&
 1330         (left->pattern_max_jump_size == right->pattern_max_jump_size) &&
 1331         (left->fp == right->fp) &&
 1332         (left->fp_only == right->fp_only) &&
 1333         (left->fp_offset == right->fp_offset) &&
 1334         (left->fp_length == right->fp_length) &&
 1335         (left->offset_var == right->offset_var) &&
 1336         (left->depth_var == right->depth_var) &&
 1337         (left->distance_var == right->distance_var) &&
 1338         (left->within_var == right->within_var) )
 1339     {
 1340         return DETECTION_OPTION_EQUAL;
 1341     }
 1342 
 1343     return DETECTION_OPTION_NOT_EQUAL;
 1344 }
 1345 
 1346 /* This function is called in parser.c after the rule has been
 1347  * completely parsed */
 1348 void FinalizeContentUniqueness(struct _SnortConfig *sc, OptTreeNode *otn)
 1349 {
 1350     OptFpList *opt_fp = otn->opt_func;
 1351 
 1352     while (opt_fp)
 1353     {
 1354         if ((opt_fp->type == RULE_OPTION_TYPE_CONTENT)
 1355                 || (opt_fp->type == RULE_OPTION_TYPE_CONTENT_URI))
 1356         {
 1357             PatternMatchData *pmd = (PatternMatchData *)opt_fp->context;
 1358             option_type_t option_type = opt_fp->type;
 1359             void *pmd_dup;
 1360 
 1361             /* Since each content modifier can be parsed as a rule option,
 1362              * do this check now that the entire rule has been parsed */
 1363             if (option_type == RULE_OPTION_TYPE_CONTENT_URI)
 1364                 ValidateContent(sc, pmd, PLUGIN_PATTERN_MATCH_URI);
 1365             else
 1366                 ValidateContent(sc, pmd, PLUGIN_PATTERN_MATCH);
 1367 
 1368             if (add_detection_option(sc, option_type, (void *)pmd, &pmd_dup) == DETECTION_OPTION_EQUAL)
 1369             {
 1370                  /* Don't do anything if they are the same pointer.  This might happen when
 1371                   * converting an so rule to a text rule via ConvertDynamicRule() in sf_convert_dynamic.c
 1372                   * since we need to iterate through the RTN list in the OTN to verify that for http
 1373                   * contents, the http_inspect preprocessor is enabled in the policy that is using a
 1374                   * rule with http contents. */
 1375                 if (pmd != pmd_dup)
 1376                 {
 1377 #if 0
 1378                  PrintDupDOTPmds(pmd, (PatternMatchData *)pmd_dup, option_type);
 1379 #endif
 1380 
 1381                     /* Hack since some places check for non-nullness of ds_list.
 1382                     * Beware of iterating the pmd lists after this point since
 1383                     * they'll be messed up - only check for non-nullness */
 1384                     if (option_type == RULE_OPTION_TYPE_CONTENT)
 1385                     {
 1386                         if (pmd == otn->ds_list[PLUGIN_PATTERN_MATCH])
 1387                             otn->ds_list[PLUGIN_PATTERN_MATCH] = pmd_dup;
 1388                     }
 1389                     else
 1390                     {
 1391                         if (pmd == otn->ds_list[PLUGIN_PATTERN_MATCH_URI])
 1392                             otn->ds_list[PLUGIN_PATTERN_MATCH_URI] = pmd_dup;
 1393                     }
 1394 
 1395                     PatternMatchFree(pmd);
 1396                     opt_fp->context = pmd_dup;
 1397                 }
 1398             }
 1399 #if 0
 1400             else
 1401             {
 1402                 LogMessage("Unique %sContent\n",
 1403                     (opt_fp->OptTestFunc == CheckANDPatternMatch) ? "" : "Uri");
 1404             }
 1405 #endif
 1406         }
 1407 
 1408         opt_fp = opt_fp->next;
 1409     }
 1410 }
 1411 
 1412 void ValidateFastPattern(OptTreeNode *otn)
 1413 {
 1414     OptFpList *fpl = NULL;
 1415     int fp_only = 0;
 1416 
 1417     for(fpl = otn->opt_func; fpl != NULL; fpl = fpl->next)
 1418     {
 1419         /* a relative option is following a fast_pattern:only and
 1420          * there was no resets.
 1421          */
 1422         if (fp_only == 1)
 1423         {
 1424             if (fpl->isRelative)
 1425                 ParseWarning("relative rule option used after "
 1426                     "fast_pattern:only");
 1427         }
 1428 
 1429         /* reset the check if one of these are present.
 1430          */
 1431         if ((fpl->type == RULE_OPTION_TYPE_FILE_DATA) ||
 1432             (fpl->type == RULE_OPTION_TYPE_PKT_DATA) ||
 1433             (fpl->type == RULE_OPTION_TYPE_BASE64_DATA) ||
 1434             (fpl->type == RULE_OPTION_TYPE_PCRE) ||
 1435             (fpl->type == RULE_OPTION_TYPE_BYTE_JUMP) ||
 1436             (fpl->type == RULE_OPTION_TYPE_BYTE_EXTRACT))
 1437         {
 1438             fp_only = 0;
 1439         }
 1440 
 1441         /* set/unset the check on content options.
 1442          */
 1443         if ((fpl->type == RULE_OPTION_TYPE_CONTENT) ||
 1444             (fpl->type == RULE_OPTION_TYPE_CONTENT_URI))
 1445         {
 1446             PatternMatchData *pmd = (PatternMatchData *)fpl->context;
 1447 
 1448             if (pmd->fp_only)
 1449                 fp_only = 1;
 1450             else
 1451                 fp_only = 0;
 1452         }
 1453     }
 1454 }
 1455 
 1456 void make_precomp(PatternMatchData * idx)
 1457 {
 1458     if(idx->skip_stride)
 1459        free(idx->skip_stride);
 1460     if(idx->shift_stride)
 1461        free(idx->shift_stride);
 1462 
 1463     idx->skip_stride = make_skip(idx->pattern_buf, idx->pattern_size);
 1464 
 1465     idx->shift_stride = make_shift(idx->pattern_buf, idx->pattern_size);
 1466 }
 1467 
 1468 static char *PayloadExtractParameter(char *data, int *result_len)
 1469 {
 1470     char *quote_one = NULL, *quote_two = NULL;
 1471     char *comma = NULL;
 1472 
 1473     quote_one = strchr(data, '"');
 1474     if (quote_one)
 1475     {
 1476         quote_two = strchr(quote_one+1, '"');
 1477         while ( quote_two && quote_two[-1] == '\\' )
 1478             quote_two = strchr(quote_two+1, '"');
 1479     }
 1480 
 1481     if (quote_one && quote_two)
 1482     {
 1483         comma = strchr(quote_two, ',');
 1484     }
 1485     else if (!quote_one)
 1486     {
 1487         comma = strchr(data, ',');
 1488     }
 1489 
 1490     if (comma)
 1491     {
 1492         *result_len = comma - data;
 1493         *comma = '\0';
 1494     }
 1495     else
 1496     {
 1497         *result_len = strlen(data);
 1498     }
 1499 
 1500     return data;
 1501 }
 1502 
 1503 /* Since each content modifier can be parsed as a rule option, do this check
 1504  * after parsing the entire rule in FinalizeContentUniqueness() */
 1505 static inline void ValidateContent(struct _SnortConfig *sc, PatternMatchData *pmd, int type)
 1506 {
 1507     if (pmd == NULL)
 1508         return;
 1509 
 1510     if (pmd->fp)
 1511     {
 1512         if( pmd->protected_pattern )
 1513         {
 1514             ParseError("Cannot use the fast pattern modifier with protected content");
 1515         }
 1516         if ((type == PLUGIN_PATTERN_MATCH_URI) && !IsHttpBufFpEligible(pmd->http_buffer))
 1517 
 1518         {
 1519             ParseError("Cannot use the fast_pattern content modifier for a lone "
 1520                     "http cookie/http raw uri /http raw header /http raw cookie /status code / status msg /http method buffer content.");
 1521         }
 1522 
 1523         if (pmd->use_doe || (pmd->offset != 0) || (pmd->depth != 0))
 1524         {
 1525             if (pmd->exception_flag)
 1526             {
 1527                 ParseError("Cannot use the fast_pattern modifier for negated, "
 1528                         "relative or non-zero offset/depth content searches.");
 1529             }
 1530 
 1531             if (pmd->fp_only)
 1532             {
 1533                 ParseError("Fast pattern only contents cannot be relative or "
 1534                         "have non-zero offset/depth content modifiers.");
 1535             }
 1536         }
 1537 
 1538         if (pmd->fp_only)
 1539         {
 1540             if (pmd->replace_buf != NULL)
 1541             {
 1542                 ParseError("Fast pattern only contents cannot use "
 1543                         "replace modifier.");
 1544             }
 1545 
 1546             if (pmd->exception_flag)
 1547                 ParseError("Fast pattern only contents cannot be negated.");
 1548         }
 1549     }
 1550 
 1551     if (type == PLUGIN_PATTERN_MATCH_URI)
 1552         ValidateHttpContentModifiers(sc, pmd);
 1553     if (pmd->protected_pattern)
 1554         ValidateProtectedContentModifiers(sc, pmd);
 1555 }
 1556 
 1557 /****************************************************************************
 1558  *
 1559  * Function: GetMaxJumpSize(char *, int)
 1560  *
 1561  * Purpose: Find the maximum number of characters we can jump ahead
 1562  *          from the current offset when checking for this pattern again.
 1563  *
 1564  * Arguments: data => the pattern string
 1565  *            data_len => length of pattern string
 1566  *
 1567  * Returns: int => number of bytes before pattern repeats within itself
 1568  *
 1569  ***************************************************************************/
 1570 static unsigned int GetMaxJumpSize(char *data, int data_len)
 1571 {
 1572     int i, j;
 1573 
 1574     j = 0;
 1575     for ( i = 1; i < data_len; i++ )
 1576     {
 1577         if ( data[j] != data[i] )
 1578         {
 1579             j = 0;
 1580             continue;
 1581         }
 1582         if ( i == (data_len - 1) )
 1583         {
 1584             return (data_len - j - 1);
 1585         }
 1586         j++;
 1587     }
 1588     return data_len;
 1589 }
 1590 
 1591 /****************************************************************************
 1592  *
 1593  * Function: ParsePattern(char *)
 1594  *
 1595  * Purpose: Process the application layer patterns and attach them to the
 1596  *          appropriate rule.  My god this is ugly code.
 1597  *
 1598  * Arguments: rule => the pattern string
 1599  *
 1600  * Returns: void function
 1601  *
 1602  ***************************************************************************/
 1603 void ParsePattern(char *rule, OptTreeNode * otn, int type)
 1604 {
 1605     char tmp_buf[MAX_PATTERN_SIZE];
 1606 
 1607     /* got enough ptrs for you? */
 1608     char *start_ptr;
 1609     char *end_ptr;
 1610     char *idx;
 1611     char *dummy_idx;
 1612     char *dummy_end;
 1613     char *tmp;
 1614     char hex_buf[3];
 1615     u_int dummy_size = 0;
 1616     int size;
 1617     int hexmode = 0;
 1618     int hexsize = 0;
 1619     int pending = 0;
 1620     int cnt = 0;
 1621     int literal = 0;
 1622     int exception_flag = 0;
 1623     PatternMatchData *ds_idx;
 1624 
 1625     /* clear out the temp buffer */
 1626     memset(tmp_buf, 0, MAX_PATTERN_SIZE);
 1627 
 1628     if (rule == NULL)
 1629         ParseError("ParsePattern Got Null enclosed in quotation marks (\")!");
 1630 
 1631     while(isspace((int)*rule))
 1632         rule++;
 1633 
 1634     if(*rule == '!')
 1635     {
 1636         exception_flag = 1;
 1637         while(isspace((int)*++rule));
 1638     }
 1639 
 1640     /* find the start of the data */
 1641     start_ptr = strchr(rule, '"');
 1642 
 1643     if (start_ptr != rule)
 1644         ParseError("Content data needs to be enclosed in quotation marks (\")!");
 1645 
 1646     /* move the start up from the beggining quotes */
 1647     start_ptr++;
 1648 
 1649     /* find the end of the data */
 1650     end_ptr = strrchr(start_ptr, '"');
 1651 
 1652     if (end_ptr == NULL)
 1653         ParseError("Content data needs to be enclosed in quotation marks (\")!");
 1654 
 1655     /* Move the null termination up a bit more */
 1656     *end_ptr = '\0';
 1657 
 1658     /* Is there anything other than whitespace after the trailing
 1659      * double quote? */
 1660     tmp = end_ptr + 1;
 1661     while (*tmp != '\0' && isspace ((int)*tmp))
 1662         tmp++;
 1663 
 1664     if (strlen (tmp) > 0)
 1665     {
 1666         ParseError("Bad data (possibly due to missing semicolon) after "
 1667                 "trailing double quote.");
 1668     }
 1669 
 1670     /* how big is it?? */
 1671     size = end_ptr - start_ptr;
 1672 
 1673     /* uh, this shouldn't happen */
 1674     if (size <= 0)
 1675         ParseError("Bad pattern length!");
 1676 
 1677     /* set all the pointers to the appropriate places... */
 1678     idx = start_ptr;
 1679 
 1680     /* set the indexes into the temp buffer */
 1681     dummy_idx = tmp_buf;
 1682     dummy_end = (dummy_idx + size);
 1683 
 1684     /* why is this buffer so small? */
 1685     memset(hex_buf, '0', 2);
 1686     hex_buf[2] = '\0';
 1687 
 1688     /* BEGIN BAD JUJU..... */
 1689     while(idx < end_ptr)
 1690     {
 1691         if (dummy_size >= MAX_PATTERN_SIZE-1)
 1692         {
 1693             /* Have more data to parse and pattern is about to go beyond end of buffer */
 1694             ParseError("ParsePattern() dummy buffer overflow, make a smaller "
 1695                     "pattern please! (Max size = %d)", MAX_PATTERN_SIZE-1);
 1696         }
 1697 
 1698         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "processing char: %c\n", *idx););
 1699         switch(*idx)
 1700         {
 1701             case '|':
 1702                 DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Got bar... "););
 1703                 if(!literal)
 1704                 {
 1705                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "not in literal mode... "););
 1706                     if(!hexmode)
 1707                     {
 1708                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Entering hexmode\n"););
 1709                         hexmode = 1;
 1710                     }
 1711                     else
 1712                     {
 1713                         DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Exiting hexmode\n"););
 1714 
 1715                         /*
 1716                         **  Hexmode is not even.
 1717                         */
 1718                         if(!hexsize || hexsize % 2)
 1719                         {
 1720                             ParseError("Content hexmode argument has invalid "
 1721                                     "number of hex digits.  The argument '%s' "
 1722                                     "must contain a full even byte string.", start_ptr);
 1723                         }
 1724 
 1725                         hexmode = 0;
 1726                         pending = 0;
 1727                     }
 1728 
 1729                     if(hexmode)
 1730                         hexsize = 0;
 1731                 }
 1732                 else
 1733                 {
 1734                     DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "literal set, Clearing\n"););
 1735                     literal = 0;
 1736                     tmp_buf[dummy_size] = start_ptr[cnt];
 1737                     dummy_size++;
 1738                 }
 1739 
 1740                 break;
 1741 
 1742             case '\\':
 1743                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Got literal char... "););
 1744 
 1745                 if(!literal)
 1746                 {
 1747                     /* Make sure the next char makes this a valid
 1748                      * escape sequence.
 1749                      */
 1750                     if (idx [1] != '\0' && strchr ("\\\":;", idx [1]) == NULL)
 1751                     {
 1752                         ParseError("Bad escape sequence starting with \"%s\".", idx);
 1753                     }
 1754 
 1755                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Setting literal\n"););
 1756 
 1757                     literal = 1;
 1758                 }
 1759                 else
 1760                 {
 1761                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Clearing literal\n"););
 1762                     tmp_buf[dummy_size] = start_ptr[cnt];
 1763                     literal = 0;
 1764                     dummy_size++;
 1765                 }
 1766 
 1767                 break;
 1768             case '"':
 1769                 if (!literal)
 1770                     ParseError("Non-escaped '\"' character!");
 1771                 /* otherwise process the character as default */
 1772             default:
 1773                 if(hexmode)
 1774                 {
 1775                     if(isxdigit((int) *idx))
 1776                     {
 1777                         hexsize++;
 1778 
 1779                         if(!pending)
 1780                         {
 1781                             hex_buf[0] = *idx;
 1782                             pending++;
 1783                         }
 1784                         else
 1785                         {
 1786                             hex_buf[1] = *idx;
 1787                             pending--;
 1788 
 1789                             if(dummy_idx < dummy_end)
 1790                             {
 1791                                 tmp_buf[dummy_size] = (u_char)
 1792                                     strtol(hex_buf, (char **) NULL, 16)&0xFF;
 1793 
 1794                                 dummy_size++;
 1795                                 memset(hex_buf, '0', 2);
 1796                                 hex_buf[2] = '\0';
 1797                             }
 1798                             else
 1799                             {
 1800                                 ParseError("ParsePattern() dummy buffer "
 1801                                         "overflow, make a smaller pattern "
 1802                                         "please! (Max size = %d)", MAX_PATTERN_SIZE-1);
 1803                             }
 1804                         }
 1805                     }
 1806                     else
 1807                     {
 1808                         if(*idx != ' ')
 1809                         {
 1810                             ParseError("What is this \"%c\"(0x%X) doing in "
 1811                                     "your binary buffer?  Valid hex values "
 1812                                     "only please! (0x0 - 0xF) Position: %d",
 1813                                     (char) *idx, (char) *idx, cnt);
 1814                         }
 1815                     }
 1816                 }
 1817                 else
 1818                 {
 1819                     if(*idx >= 0x1F && *idx <= 0x7e)
 1820                     {
 1821                         if(dummy_idx < dummy_end)
 1822                         {
 1823                             tmp_buf[dummy_size] = start_ptr[cnt];
 1824                             dummy_size++;
 1825                         }
 1826                         else
 1827                         {
 1828                             ParseError("ParsePattern() dummy buffer "
 1829                                     "overflow, make a smaller pattern "
 1830                                     "please! (Max size = %d)", MAX_PATTERN_SIZE-1);
 1831                         }
 1832 
 1833                         if(literal)
 1834                         {
 1835                             literal = 0;
 1836                         }
 1837                     }
 1838                     else
 1839                     {
 1840                         if(literal)
 1841                         {
 1842                             tmp_buf[dummy_size] = start_ptr[cnt];
 1843                             dummy_size++;
 1844                             DEBUG_WRAP(DebugMessage(DEBUG_PARSER, "Clearing literal\n"););
 1845                             literal = 0;
 1846                         }
 1847                         else
 1848                         {
 1849                             ParseError("Character value out of range, try a "
 1850                                     "binary buffer.");
 1851                         }
 1852                     }
 1853                 }
 1854 
 1855                 break;
 1856         }
 1857 
 1858         dummy_idx++;
 1859         idx++;
 1860         cnt++;
 1861     }
 1862     /* ...END BAD JUJU */
 1863 
 1864     /* error prunning */
 1865 
 1866     if (literal)
 1867         ParseError("Backslash escape is not completed.");
 1868 
 1869     if (hexmode)
 1870         ParseError("Hexmode is not completed.");
 1871 
 1872     ds_idx = (PatternMatchData *) otn->ds_list[type];
 1873 
 1874     while(ds_idx->next != NULL)
 1875         ds_idx = ds_idx->next;
 1876 
 1877     ds_idx->pattern_buf = (char *)SnortAlloc(dummy_size+1);
 1878     memcpy(ds_idx->pattern_buf, tmp_buf, dummy_size);
 1879 
 1880     ds_idx->pattern_size = dummy_size;
 1881     ds_idx->search = uniSearch;
 1882 
 1883     make_precomp(ds_idx);
 1884     ds_idx->exception_flag = exception_flag;
 1885 
 1886     ds_idx->pattern_max_jump_size = GetMaxJumpSize(ds_idx->pattern_buf, ds_idx->pattern_size);
 1887 }
 1888 
 1889 static bool HexToNybble( char Chr, uint8_t *Val )
 1890 {
 1891     if( !isxdigit( (int)Chr ) )
 1892     {
 1893         *Val = 0;
 1894         return( false );
 1895     }
 1896 
 1897     if( isdigit( Chr ) )
 1898         *Val = (uint8_t)(Chr - '0');
 1899     else
 1900         *Val = (uint8_t)(((char)toupper(Chr) - 'A') + 10);
 1901 
 1902     return( true );
 1903 }
 1904 
 1905 static bool HexToByte( char *Str, uint8_t *Val )
 1906 {
 1907     uint8_t nybble;
 1908 
 1909     *Val = 0;
 1910 
 1911     if( HexToNybble( *Str++, &nybble ) )
 1912     {
 1913         *Val = ((nybble & 0xf) << 4);
 1914         if( HexToNybble( *Str, &nybble ) )
 1915         {
 1916             *Val |= (nybble & 0xf);
 1917             return( true );
 1918         }
 1919     }
 1920 
 1921     return( false );
 1922 }
 1923 
 1924 /****************************************************************************
 1925  *
 1926  * Function: ParseProtectedPattern(char *)
 1927  *
 1928  * Purpose: Process the application layer patterns and attach them to the
 1929  *          appropriate rule.
 1930  *
 1931  * Arguments: rule => the pattern string
 1932  *
 1933  * Returns: void function
 1934  *
 1935  ***************************************************************************/
 1936 void ParseProtectedPattern(char *rule, OptTreeNode * otn, int type)
 1937 {
 1938     uint8_t tmp_buf[MAX_PATTERN_SIZE];
 1939 
 1940     char *tmp;
 1941     unsigned int pat_idx;
 1942     int exception_flag = 0;
 1943     PatternMatchData *ds_idx;
 1944 
 1945     /* clear out the temp buffer */
 1946     memset(tmp_buf, 0, MAX_PATTERN_SIZE);
 1947 
 1948     if (rule == NULL)
 1949         ParseError("ParsePattern Got Null enclosed in quotation marks (\")!");
 1950 
 1951     while(isspace((int)*rule))
 1952         rule++;
 1953 
 1954     if(  *rule == '!' )
 1955     {
 1956         exception_flag = 1;
 1957         rule++;
 1958     }
 1959     else
 1960         exception_flag = 0;
 1961 
 1962     /* find the start of the data */
 1963     while(isspace((int)*rule))
 1964         rule++;
 1965 
 1966     if (*rule++ != '"')
 1967         ParseError("Protected content data needs to be enclosed in quotation marks (\")!");
 1968 
 1969     /* find the end of the data */
 1970     tmp = strrchr(rule, '"');
 1971 
 1972     if (tmp == NULL)
 1973         ParseError("Protected content data needs to be enclosed in quotation marks (\")!");
 1974 
 1975     /* Terminate the pattern string */
 1976     *tmp = '\0';
 1977 
 1978     /* Is there anything other than whitespace after the trailing
 1979      * double quote? */
 1980     while (*++tmp != '\0')
 1981         if(!isspace ((int)*tmp))
 1982             ParseError("Bad data (possibly due to missing semicolon) after "
 1983                        "trailing double quote.");
 1984 
 1985     pat_idx = 0;    /* index into the pattern buffer */
 1986 
 1987     while((*rule != '\0') && (pat_idx < MAX_PATTERN_SIZE))
 1988     {
 1989         if( !HexToByte( rule, &(tmp_buf[pat_idx]) ) )
 1990             ParseError("Bad protected pattern");
 1991 
 1992         rule += 2;
 1993         pat_idx += 1;
 1994     }
 1995 
 1996     if( (*rule == '\0') && (pat_idx == 0) )
 1997         ParseError("Zero protected pattern size");
 1998 
 1999     if( (*rule != '\0') && (pat_idx == MAX_PATTERN_SIZE) )
 2000         ParseError("Protected pattern too long");
 2001 
 2002     ds_idx = (PatternMatchData *) otn->ds_list[type];
 2003 
 2004     while(ds_idx->next != NULL)
 2005         ds_idx = ds_idx->next;
 2006 
 2007     ds_idx->pattern_buf = (char *)SnortAlloc(pat_idx);
 2008     memcpy(ds_idx->pattern_buf, tmp_buf, pat_idx);
 2009 
 2010     ds_idx->pattern_size = pat_idx;
 2011     ds_idx->search = uniSearchHash;
 2012 
 2013     ds_idx->exception_flag = exception_flag;
 2014 
 2015 }
 2016 
 2017 /*
 2018  * hash search function.
 2019  *
 2020  * data = ptr to buffer to search
 2021  * dlen = distance to the back of the buffer being tested, validated
 2022  *        against offset + depth before function entry (not distance/within)
 2023  * pmd = pointer to pattern match data struct
 2024  *
 2025  * return  1 for found
 2026  * return  0 for not found
 2027  * return -1 for error (search out of bounds)
 2028  */
 2029 static int uniSearchHash(const char *data, int dlen, PatternMatchData *pmd)
 2030 {
 2031     /*
 2032      * in theory computeDepth doesn't need to be called because the
 2033      * depth + offset adjustments have been made by the calling function
 2034      */
 2035     int depth = dlen;
 2036     int success = 0;
 2037     const char *start_ptr = data;
 2038     const char *end_ptr = data + dlen;
 2039     const char *base_ptr = start_ptr;
 2040     uint32_t extract_offset, extract_distance;
 2041     int search_start = 0;
 2042 
 2043     if(pmd->use_doe != 1)
 2044     {
 2045         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "NOT Using Doe Ptr\n"););
 2046         UpdateDoePtr(NULL, 0); /* get rid of all our pattern match state */
 2047     }
 2048 
 2049     /* Get byte_math/byte_extract variables */
 2050     if (pmd->offset_var >= 0 )
 2051     {
 2052         if(pmd->offset_var == BYTE_MATH_VAR_INDEX)
 2053         {
 2054             pmd->offset = (int32_t) bytemath_variable;
 2055         }
 2056         else if(pmd->offset_var == COMMON_VAR_INDEX)
 2057         {
 2058             pmd->offset = (int32_t) common_var;
 2059         }
 2060         else if (pmd->offset_var < NUM_BYTE_EXTRACT_VARS)
 2061         {
 2062             GetByteExtractValue(&extract_offset, pmd->offset_var);
 2063             pmd->offset = (int32_t) extract_offset;
 2064         }
 2065     }
 2066     if (pmd->distance_var >= 0 )
 2067     {
 2068         if(pmd->distance_var == BYTE_MATH_VAR_INDEX)
 2069         {
 2070             pmd->distance = (int32_t) bytemath_variable;
 2071         }
 2072         else if(pmd->distance_var == COMMON_VAR_INDEX)
 2073         {
 2074             pmd->distance = (int32_t) common_var;
 2075         }
 2076         else if (pmd->distance_var < NUM_BYTE_EXTRACT_VARS)
 2077         {
 2078             GetByteExtractValue(&extract_distance, pmd->distance_var);
 2079             pmd->distance = (int32_t) extract_distance;
 2080         }
 2081     }
 2082 
 2083     // Set our initial starting point
 2084     if (doe_ptr)
 2085     {
 2086         // Sanity check to make sure the doe_ptr is within the buffer we're
 2087         // searching.  It could be at the very end of the buffer due to a
 2088         // previous match, but may have a negative distance here.
 2089         if (((char *)doe_ptr < start_ptr) || ((char *)doe_ptr > end_ptr))
 2090         {
 2091             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Returning because "
 2092                         "doe_ptr isn't within the buffer we're searching: "
 2093                         "start_ptr: %p, end_ptr: %p, doe_ptr: %p\n",
 2094                         start_ptr, end_ptr, doe_ptr););
 2095             return -1;
 2096         }
 2097 
 2098         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2099                     "Setting base_ptr to doe_ptr (%p)\n", doe_ptr););
 2100 
 2101         base_ptr = (const char *)doe_ptr;
 2102         depth = dlen - ((char *)doe_ptr - data);
 2103     }
 2104     else
 2105     {
 2106         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2107                     "Setting base_ptr to start_ptr (%p)\n", start_ptr););
 2108 
 2109         base_ptr = start_ptr;
 2110         depth = dlen;
 2111     }
 2112 
 2113     // Adjust base_ptr and depth based on distance
 2114     // or offset parameters.
 2115     if (pmd->distance != 0)
 2116     {
 2117         // This covers the pmd->distance > buffer case
 2118         if (pmd->distance > depth)
 2119         {
 2120             depth = 0;
 2121         }
 2122         else
 2123         {
 2124             search_start = (base_ptr - start_ptr) + pmd->distance;
 2125             base_ptr += pmd->distance;
 2126             depth -= pmd->distance;
 2127         }
 2128 
 2129         // If the distance is negative and puts us before start_ptr
 2130         // set base_ptr to start_ptr and adjust depth based on protected_length.
 2131         if (search_start < 0)
 2132         {
 2133             return -1;
 2134         }
 2135         else if ((int)pmd->pattern_size < depth)
 2136         {
 2137             depth = (int)pmd->pattern_size;
 2138         }
 2139         search_start = 0;
 2140     }
 2141     else if (pmd->offset != 0)
 2142     {
 2143         if (pmd->offset > depth)
 2144         {
 2145             depth = 0;
 2146         }
 2147         else
 2148         {
 2149             search_start = pmd->offset;
 2150             base_ptr += pmd->offset;
 2151             depth -= pmd->offset;
 2152         }
 2153 
 2154         // If the distance is negative and puts us before start_ptr
 2155         // set base_ptr to start_ptr and adjust depth based on pmd->protected_length.
 2156         if (search_start < 0)
 2157         {
 2158             return -1;
 2159         } 
 2160         else if ((int)pmd->pattern_size < depth)
 2161         {
 2162             depth = (int)pmd->pattern_size;
 2163         }
 2164     }
 2165 
 2166     // If the pattern size is greater than the amount of data we have to
 2167     // search, there's no way we can match, but return 0 here for the
 2168     // case where the match is inverted and there is at least some data.
 2169     if ((int)pmd->pattern_size > depth)
 2170     {
 2171         if (pmd->exception_flag && (depth > 0))
 2172             return 0;
 2173 
 2174         return -1;
 2175     }
 2176 
 2177 #ifdef DEBUG_MSGS
 2178     {
 2179         char *hexbuf;
 2180 
 2181         assert(depth <= dlen);
 2182 
 2183         DebugMessage(DEBUG_PATTERN_MATCH, "uniSearchHash:\n ");
 2184 
 2185         hexbuf = hex((u_char *)pmd->pattern_buf, pmd->pattern_size);
 2186         DebugMessage(DEBUG_PATTERN_MATCH, "   p->data: %p\n   doe_ptr: %p\n   "
 2187                 "base_ptr: %p\n   depth: %d\n   searching for: %s\n",
 2188                 data, doe_ptr, base_ptr, depth, hexbuf);
 2189         free(hexbuf);
 2190     }
 2191 #endif /* DEBUG_MSGS */
 2192 
 2193     success = hashSearchFixed(base_ptr, pmd->pattern_size,
 2194                               pmd->pattern_type, pmd->pattern_buf);
 2195 
 2196 #ifdef DEBUG_MSGS
 2197     if(success)
 2198     {
 2199         DebugMessage(DEBUG_PATTERN_MATCH, "matched, doe_ptr: %p (%d)\n",
 2200                      doe_ptr, ((char *)doe_ptr - data));
 2201     }
 2202 #endif
 2203 
 2204     return success;
 2205 }
 2206 
 2207 /********************************************************************
 2208  * Runtime functions
 2209  ********************************************************************/
 2210 /*
 2211  * case sensitive search
 2212  *
 2213  * data = ptr to buffer to search
 2214  * dlen = distance to the back of the buffer being tested, validated
 2215  *        against offset + depth before function entry (not distance/within)
 2216  * pmd = pointer to pattern match data struct
 2217  */
 2218 
 2219 static int uniSearch(const char *data, int dlen, PatternMatchData *pmd)
 2220 {
 2221     return uniSearchReal(data, dlen, pmd, 0);
 2222 }
 2223 
 2224 /*
 2225  * case insensitive search
 2226  *
 2227  * data = ptr to buffer to search
 2228  * dlen = distance to the back of the buffer being tested, validated
 2229  *        against offset + depth before function entry (not distance/within)
 2230  * pmd = pointer to pattern match data struct
 2231  *
 2232  * NOTE - this is used in sf_convert_dynamic.c so cannot be static
 2233  */
 2234 int uniSearchCI(const char *data, int dlen, PatternMatchData *pmd)
 2235 {
 2236     return uniSearchReal(data, dlen, pmd, 1);
 2237 }
 2238 
 2239 /*
 2240  * single search function.
 2241  *
 2242  * data = ptr to buffer to search
 2243  * dlen = distance to the back of the buffer being tested, validated
 2244  *        against offset + depth before function entry (not distance/within)
 2245  * pmd = pointer to pattern match data struct
 2246  * nocase = 0 means case sensitve, 1 means case insensitive
 2247  *
 2248  * return  1 for found
 2249  * return  0 for not found
 2250  * return -1 for error (search out of bounds)
 2251  */
 2252 static int uniSearchReal(const char *data, int dlen, PatternMatchData *pmd, int nocase)
 2253 {
 2254     /*
 2255      * in theory computeDepth doesn't need to be called because the
 2256      * depth + offset adjustments have been made by the calling function
 2257      */
 2258     int depth = dlen;
 2259     int success = 0;
 2260     const char *start_ptr = data;
 2261     const char *end_ptr = data + dlen;
 2262     const char *base_ptr = start_ptr;
 2263     uint32_t extract_offset, extract_depth, extract_distance, extract_within;
 2264     int search_start = 0;
 2265 
 2266     if(pmd->use_doe != 1)
 2267     {
 2268         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "NOT Using Doe Ptr\n"););
 2269         UpdateDoePtr(NULL, 0); /* get rid of all our pattern match state */
 2270     }
 2271 
 2272     /* Get byte_math/byte_extract variables */
 2273    if (pmd->offset_var >= 0)
 2274    {
 2275         if(pmd->offset_var == BYTE_MATH_VAR_INDEX)
 2276         {
 2277             pmd->offset = (int32_t) bytemath_variable;
 2278         }
 2279         else if(pmd->offset_var == COMMON_VAR_INDEX)
 2280         {
 2281             pmd->offset = (int32_t) common_var;
 2282         }
 2283         else if (pmd->offset_var < NUM_BYTE_EXTRACT_VARS)
 2284         {
 2285             GetByteExtractValue(&extract_offset, pmd->offset_var);
 2286             pmd->offset = (int32_t) extract_offset;
 2287         }
 2288     }
 2289     if (pmd->depth_var >= 0)
 2290     {
 2291         if(pmd->depth_var == BYTE_MATH_VAR_INDEX)
 2292         {
 2293             pmd->depth = (int32_t) bytemath_variable;
 2294         }
 2295         else if(pmd->depth_var == COMMON_VAR_INDEX)
 2296         {
 2297             pmd->depth = (int32_t) common_var;
 2298         }
 2299         else if (pmd->depth_var < NUM_BYTE_EXTRACT_VARS)
 2300         {
 2301             GetByteExtractValue(&extract_depth, pmd->depth_var);
 2302             pmd->depth = (int32_t) extract_depth;
 2303         }
 2304     }
 2305     if (pmd->distance_var >= 0)
 2306     {
 2307         if(pmd->distance_var == BYTE_MATH_VAR_INDEX)
 2308         { 
 2309             pmd->distance = (int32_t) bytemath_variable;
 2310         }
 2311         else if(pmd->distance == COMMON_VAR_INDEX)
 2312         {
 2313             pmd->distance = (int32_t) common_var;
 2314         }
 2315         else if (pmd->distance_var < NUM_BYTE_EXTRACT_VARS)
 2316         {
 2317             GetByteExtractValue(&extract_distance, pmd->distance_var);
 2318             pmd->distance = (int32_t) extract_distance;
 2319         }
 2320     }
 2321     if (pmd->within_var >= 0)
 2322     {
 2323         if(pmd->within_var == BYTE_MATH_VAR_INDEX)
 2324         {
 2325             pmd->within = (int32_t) bytemath_variable;
 2326         }
 2327         else if(pmd->within_var == COMMON_VAR_INDEX)
 2328         {
 2329             pmd->within = (int32_t) common_var;
 2330         }
 2331         else if (pmd->within_var < NUM_BYTE_EXTRACT_VARS)
 2332         {
 2333             GetByteExtractValue(&extract_within, pmd->within_var);
 2334             pmd->within = (int32_t) extract_within;
 2335         }
 2336     }
 2337 
 2338     // Set our initial starting point
 2339     if (doe_ptr)
 2340     {
 2341         // Sanity check to make sure the doe_ptr is within the buffer we're
 2342         // searching.  It could be at the very end of the buffer due to a
 2343         // previous match, but may have a negative distance here.
 2344         if (((char *)doe_ptr < start_ptr) || ((char *)doe_ptr > end_ptr))
 2345         {
 2346             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Returning because "
 2347                         "doe_ptr isn't within the buffer we're searching: "
 2348                         "start_ptr: %p, end_ptr: %p, doe_ptr: %p\n",
 2349                         start_ptr, end_ptr, doe_ptr););
 2350             return -1;
 2351         }
 2352 
 2353         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2354                     "Setting base_ptr to doe_ptr (%p)\n", doe_ptr););
 2355 
 2356         base_ptr = (const char *)doe_ptr;
 2357         depth = dlen - ((char *)doe_ptr - data);
 2358     }
 2359     else
 2360     {
 2361         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2362                     "Setting base_ptr to start_ptr (%p)\n", start_ptr););
 2363 
 2364         base_ptr = start_ptr;
 2365         depth = dlen;
 2366     }
 2367 
 2368     // Adjust base_ptr and depth based on distance/within
 2369     // or offset/depth parameters.
 2370     if ((pmd->distance != 0) || (pmd->within != PMD_WITHIN_UNDEFINED))
 2371     {
 2372         // This covers the pmd->distance > buffer case
 2373         if (pmd->distance > depth)
 2374         {
 2375             depth = 0;
 2376         }
 2377         else if (pmd->distance != 0)
 2378         {
 2379             search_start = (base_ptr - start_ptr) + pmd->distance;
 2380             base_ptr += pmd->distance;
 2381             depth -= pmd->distance;
 2382         }
 2383 
 2384         // If the distance is negative and puts us before start_ptr
 2385         // set base_ptr to start_ptr and adjust depth based on within.
 2386         if (search_start < 0)
 2387         {
 2388             int delta = search_start;
 2389             delta += (pmd->within == PMD_WITHIN_UNDEFINED) ? 0 : (int)pmd->within;
 2390             // base_ptr is before start_ptr and the within is before start_ptr as well. Cannot re-adjust.
 2391             if(delta < 0)
 2392                 return -1;
 2393             base_ptr = start_ptr;
 2394             depth = ((pmd->within == PMD_WITHIN_UNDEFINED) || (delta > dlen)) ? dlen : delta;
 2395         }
 2396         else if ((pmd->within != PMD_WITHIN_UNDEFINED) && ((int)pmd->within < depth))
 2397         {
 2398             depth = (int)pmd->within;
 2399         }
 2400         search_start = 0;
 2401     }
 2402     else if ((pmd->offset != 0) || (pmd->depth != 0))
 2403     {
 2404         if (pmd->offset > depth)
 2405         {
 2406             depth = 0;
 2407         }
 2408         else if (pmd->offset != 0)
 2409         {
 2410             search_start = pmd->offset;
 2411             base_ptr += pmd->offset;
 2412             depth -= pmd->offset;
 2413         }
 2414 
 2415         // If the distance is negative and puts us before start_ptr
 2416         // set base_ptr to start_ptr and adjust depth based on pmd->depth.
 2417         if (search_start < 0)
 2418         {
 2419             int delta = (int)pmd->depth + search_start;
 2420             // base_ptr is before start_ptr and the depth is before start_ptr as well. Cannot re-adjust.
 2421             if(delta < 0)
 2422                 return -1;
 2423             base_ptr = start_ptr;
 2424             depth = ((pmd->depth == 0) || (delta > dlen)) ? dlen : delta;
 2425         } 
 2426         else if ((pmd->depth != 0) && (pmd->depth < depth))
 2427         {
 2428             depth = pmd->depth;
 2429         }
 2430     }
 2431 
 2432     // If the pattern size is greater than the amount of data we have to
 2433     // search, there's no way we can match, but return 0 here for the
 2434     // case where the match is inverted and there is at least some data.
 2435     if ((int)pmd->pattern_size > depth)
 2436     {
 2437         // The condition ((char *)doe_ptr == end_ptr) is for the corner case,
 2438         // where the pattern match is exactly at the end of the payload and it
 2439         // is a negated content match.
 2440         if (pmd->exception_flag && (((char *)doe_ptr == end_ptr) || depth > 0))
 2441             return 0;
 2442 
 2443         return -1;
 2444     }
 2445 
 2446 #ifdef DEBUG_MSGS
 2447     {
 2448         char *hexbuf;
 2449 
 2450         assert(depth <= dlen);
 2451 
 2452         DebugMessage(DEBUG_PATTERN_MATCH, "uniSearchReal:\n ");
 2453 
 2454         hexbuf = hex((u_char *)pmd->pattern_buf, pmd->pattern_size);
 2455         DebugMessage(DEBUG_PATTERN_MATCH, "   p->data: %p\n   doe_ptr: %p\n   "
 2456                 "base_ptr: %p\n   depth: %d\n   searching for: %s\n",
 2457                 data, doe_ptr, base_ptr, depth, hexbuf);
 2458         free(hexbuf);
 2459     }
 2460 #endif /* DEBUG_MSGS */
 2461 
 2462     if(nocase)
 2463     {
 2464         success = mSearchCI(base_ptr, depth,
 2465                             pmd->pattern_buf,
 2466                             pmd->pattern_size,
 2467                             pmd->skip_stride,
 2468                             pmd->shift_stride);
 2469     }
 2470     else
 2471     {
 2472         success = mSearch(base_ptr, depth,
 2473                           pmd->pattern_buf,
 2474                           pmd->pattern_size,
 2475                           pmd->skip_stride,
 2476                           pmd->shift_stride);
 2477     }
 2478 
 2479 
 2480 #ifdef DEBUG_MSGS
 2481     if(success)
 2482     {
 2483         DebugMessage(DEBUG_PATTERN_MATCH, "matched, doe_ptr: %p (%d)\n",
 2484                      doe_ptr, ((char *)doe_ptr - data));
 2485     }
 2486 #endif
 2487 
 2488     return success;
 2489 }
 2490 
 2491 int CheckANDPatternMatch(void *option_data, Packet *p)
 2492 {
 2493     int rval = DETECTION_OPTION_NO_MATCH;
 2494     int found = -1;
 2495     int dsize;
 2496     const char *dp = NULL;
 2497 #if 0
 2498     int origUseDoe;
 2499     char *orig_doe;
 2500 #endif
 2501     PatternMatchData *idx;
 2502     PROFILE_VARS;
 2503 
 2504     PREPROC_PROFILE_START(contentPerfStats);
 2505 
 2506     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "CheckPatternANDMatch: "););
 2507 
 2508     idx = (PatternMatchData *)option_data;
 2509 #if 0
 2510     origUseDoe = idx->use_doe;
 2511 #endif
 2512 
 2513     if(idx->rawbytes == 0)
 2514     {
 2515         if(Is_DetectFlag(FLAG_ALT_DETECT))
 2516         {
 2517             dsize = DetectBuffer.len;
 2518             dp = (const char*) DetectBuffer.data;
 2519             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2520                         "Using Alternative Detect buffer!\n"););
 2521         }
 2522         else if(Is_DetectFlag(FLAG_ALT_DECODE))
 2523         {
 2524             dsize = DecodeBuffer.len;
 2525             dp = (const char *) DecodeBuffer.data;
 2526             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2527                         "Using Alternative Decode buffer!\n"););
 2528         }
 2529         else
 2530         {
 2531             if(IsLimitedDetect(p))
 2532             {
 2533                 dsize = p->alt_dsize;
 2534                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2535                     "Using Limited Packet Data!\n"););
 2536             }
 2537             else
 2538             {
 2539                 dsize = p->dsize;
 2540                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2541                     "Using Full Packet Data!\n"););
 2542             }
 2543             dp = (const char *) p->data;
 2544         }
 2545     }
 2546     else
 2547     {
 2548         dsize = p->dsize;
 2549         dp = (const char *) p->data;
 2550         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2551             "Using Full Packet Data!\n"););
 2552     }
 2553 
 2554 #if 0
 2555     /* this now takes care of all the special cases where we'd run
 2556      * over the buffer */
 2557     orig_doe = (char *)doe_ptr;
 2558 #endif
 2559 
 2560     if(doe_buf_flags & DOE_BUF_URI)
 2561         UpdateDoePtr(NULL, 0);
 2562 
 2563     doe_buf_flags = DOE_BUF_STD;
 2564 
 2565 #ifndef NO_FOUND_ERROR
 2566     if( p->dsize != 0 )
 2567     {
 2568          found = idx->search(dp, dsize, idx);
 2569     }
 2570     if ( found == -1 )
 2571     {
 2572         /* On error, mark as not found.  This is necessary to handle !content
 2573            cases.  In that case, a search that is outside the given buffer will
 2574            return 0, and !0 is 1, so a !content out of bounds will return true,
 2575            which is not what we want.  */
 2576         found = 0;
 2577     }
 2578     else
 2579     {
 2580         found ^= idx->exception_flag;
 2581     }
 2582 #else
 2583     /* Original code.  Does not account for searching outside the buffer. */
 2584     found = (idx->search(dp, dsize, idx) ^ idx->exception_flag);
 2585 #endif
 2586 
 2587     if ( found )
 2588     {
 2589         if ( idx->replace_buf && !PacketWasCooked(p) )
 2590         {
 2591             //fix the packet buffer to have the new string
 2592             int detect_depth = (char *)doe_ptr - idx->pattern_size - dp;
 2593 
 2594             if (detect_depth < 0)
 2595             {
 2596                 PREPROC_PROFILE_END(contentPerfStats);
 2597                 return rval;
 2598             }
 2599             Replace_StoreOffset(idx, detect_depth);
 2600         }
 2601         rval = DETECTION_OPTION_MATCH;
 2602         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match found\n"););
 2603     }
 2604     else
 2605     {
 2606         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match failed\n"););
 2607     }
 2608 #if 0
 2609     while (found)
 2610     {
 2611         /* save where we last did the pattern match */
 2612         tmp_doe = (char *)doe_ptr;
 2613 
 2614         /* save start doe as beginning of this pattern + non-repeating length*/
 2615         start_doe = (char *)doe_ptr - idx->pattern_size + idx->pattern_max_jump_size;
 2616 
 2617         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match successful!\n"););
 2618         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Check next functions!\n"););
 2619         /* PROFILING Don't count rest of options towards content */
 2620         PREPROC_PROFILE_TMPEND(contentPerfStats);
 2621 
 2622         /* Try evaluating the rest of the rules chain */
 2623         next_found= fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
 2624 
 2625         /* PROFILING Don't count rest of options towards content */
 2626         PREPROC_PROFILE_TMPSTART(contentPerfStats);
 2627 
 2628         if(next_found != 0)
 2629         {
 2630             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2631                                     "Next functions matched!\n"););
 2632 
 2633             /* We found a successful match, return that this rule has fired off */
 2634             PREPROC_PROFILE_END(contentPerfStats);
 2635             return next_found;
 2636         }
 2637         else if(tmp_doe != NULL)
 2638         {
 2639             int new_dsize = dsize-(start_doe-dp);
 2640 
 2641             /* if the next option isn't relative and it failed, we're done */
 2642             if (fp_list->next->isRelative == 0)
 2643             {
 2644                 PREPROC_PROFILE_END(contentPerfStats);
 2645                 return 0;
 2646             }
 2647 
 2648             if(new_dsize <= 0 || new_dsize > dsize)
 2649             {
 2650                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2651                                         "The new dsize is less than <= 0 or > "
 2652                                         "the the original dsize;returning "
 2653                                         "false\n"););
 2654                 idx->use_doe = origUseDoe;
 2655                 PREPROC_PROFILE_END(contentPerfStats);
 2656                 return 0;
 2657             }
 2658 
 2659             if (orig_doe)
 2660             {
 2661                 /* relative to a previously found pattern */
 2662                 if (((idx->distance != 0) && (start_doe - orig_doe > idx->distance)) ||
 2663                     ((idx->offset != 0) && (start_doe - orig_doe > idx->offset)) )
 2664                 {
 2665                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2666                                             "The next starting point to search "
 2667                                             "from is beyond the original "
 2668                                             "distance;returning false\n"););
 2669                     idx->use_doe = origUseDoe;
 2670                     PREPROC_PROFILE_END(contentPerfStats);
 2671                     return 0;
 2672                 }
 2673 
 2674                 if (((idx->within != 0) &&
 2675                      (start_doe - orig_doe + idx->pattern_size > (unsigned int)idx->within)) ||
 2676                     ((idx->depth != 0) &&
 2677                      (start_doe - orig_doe + idx->pattern_size > (unsigned int)idx->depth)) )
 2678                 {
 2679                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2680                                             "The next starting point to search "
 2681                                             "from is beyond the original "
 2682                                             "within;returning false\n"););
 2683                     idx->use_doe = origUseDoe;
 2684                     PREPROC_PROFILE_END(contentPerfStats);
 2685                     return 0;
 2686                 }
 2687             }
 2688             else
 2689             {
 2690                 /* relative to beginning of data */
 2691                 if (((idx->distance != 0) && (start_doe - dp > idx->distance)) ||
 2692                     ((idx->offset != 0) && (start_doe - dp > idx->offset)) )
 2693                 {
 2694                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2695                                             "The next starting point to search "
 2696                                             "from is beyond the original "
 2697                                             "distance;returning false\n"););
 2698                     idx->use_doe = origUseDoe;
 2699                     PREPROC_PROFILE_END(contentPerfStats);
 2700                     return 0;
 2701                 }
 2702 
 2703                 if (((idx->within != 0) &&
 2704                      (start_doe - dp + idx->pattern_size > (unsigned int)idx->within)) ||
 2705                     ((idx->depth != 0) &&
 2706                      (start_doe - dp + idx->pattern_size > (unsigned int)idx->depth)) )
 2707                 {
 2708                     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2709                                             "The next starting point to search "
 2710                                             "from is beyond the original "
 2711                                             "within;returning false\n"););
 2712                     idx->use_doe = origUseDoe;
 2713                     PREPROC_PROFILE_END(contentPerfStats);
 2714                     return 0;
 2715                 }
 2716             }
 2717 
 2718             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2719                                     "At least ONE of the next functions does to match!\n"););
 2720             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2721                                     "Start search again from a next point!\n"););
 2722 
 2723             /* Start the search again from the last set of contents, with a new depth and dsize */
 2724             doe_ptr = (uint8_t *)start_doe;
 2725             idx->use_doe = 1;
 2726             found = (idx->search(start_doe, new_dsize,idx) ^ idx->exception_flag);
 2727 
 2728             /*
 2729             **  If we haven't updated doe since we set it at the beginning
 2730             **  of the loop, then that means we have already done the exact
 2731             **  same search previously, and have nothing else to gain from
 2732             **  doing the same search again.
 2733             */
 2734             if(start_doe == (char *)doe_ptr)
 2735             {
 2736                 idx->use_doe = origUseDoe;
 2737                 PREPROC_PROFILE_END(contentPerfStats);
 2738                 return 0;
 2739             }
 2740         }
 2741         else
 2742         {
 2743             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2744                                     "Returning 0 because tmp_doe is NULL\n"););
 2745 
 2746             idx->use_doe = origUseDoe;
 2747             PREPROC_PROFILE_END(contentPerfStats);
 2748             return 0;
 2749         }
 2750 
 2751     }
 2752 #endif
 2753 
 2754     //idx->use_doe = origUseDoe;
 2755     PREPROC_PROFILE_END(contentPerfStats);
 2756     return rval;
 2757 }
 2758 
 2759 int CheckUriPatternMatch(void *option_data, Packet *p)
 2760 {
 2761     int rval = DETECTION_OPTION_NO_MATCH;
 2762     int found = 0;
 2763     PatternMatchData *idx = (PatternMatchData *)option_data;
 2764     const HttpBuffer* hb = GetHttpBuffer(idx->http_buffer);
 2765     PROFILE_VARS;
 2766 
 2767     if ( !hb )
 2768     {
 2769         DEBUG_WRAP(DebugMessage(DEBUG_HTTP_DECODE,"CheckUriPatternMatch: no "
 2770             "HTTP buffers set, retuning"););
 2771         return rval;
 2772     }
 2773 
 2774     PREPROC_PROFILE_START(uricontentPerfStats);
 2775 
 2776     /*
 2777     * have to reset the doe_ptr for each new UriBuf
 2778     */
 2779     if(idx->use_doe != 1)
 2780         UpdateDoePtr(NULL, 0);
 2781 
 2782     else if(!(doe_buf_flags & DOE_BUF_URI))
 2783         SetDoePtr(hb->buf, DOE_BUF_URI);
 2784 
 2785     /* this now takes care of all the special cases where we'd run
 2786      * over the buffer */
 2787     found = idx->search((const char *)hb->buf, hb->length, idx);
 2788 
 2789     if (found == -1)
 2790         found = 0;
 2791     else
 2792         found ^= idx->exception_flag;
 2793 
 2794     if(found > 0 )
 2795     {
 2796         doe_buf_flags = DOE_BUF_URI;
 2797         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match successful!\n"););
 2798 
 2799         /* call the next function in the OTN */
 2800         PREPROC_PROFILE_END(uricontentPerfStats);
 2801         return DETECTION_OPTION_MATCH;
 2802     }
 2803 
 2804     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Pattern match failed\n"););
 2805     PREPROC_PROFILE_END(uricontentPerfStats);
 2806     return rval;
 2807 }
 2808 
 2809 void PatternMatchDuplicatePmd(void *src, PatternMatchData *pmd_dup)
 2810 {
 2811     /* Oh, C++ where r u?  can't we have a friggin' copy constructor? */
 2812     PatternMatchData *pmd_src = (PatternMatchData *)src;
 2813     if (!pmd_src || !pmd_dup)
 2814         return;
 2815 
 2816     pmd_dup->exception_flag = pmd_src->exception_flag;
 2817     pmd_dup->offset = pmd_src->offset;
 2818     pmd_dup->depth = pmd_src->depth;
 2819     pmd_dup->distance = pmd_src->distance;
 2820     pmd_dup->within = pmd_src->within;
 2821     pmd_dup->offset_var = pmd_src->offset_var;
 2822     pmd_dup->depth_var = pmd_src->depth_var;
 2823     pmd_dup->distance_var = pmd_src->distance_var;
 2824     pmd_dup->within_var = pmd_src->within_var;
 2825     pmd_dup->rawbytes = pmd_src->rawbytes;
 2826     pmd_dup->nocase = pmd_src->nocase;
 2827     pmd_dup->use_doe = pmd_src->use_doe;
 2828     pmd_dup->http_buffer = pmd_src->http_buffer;
 2829     pmd_dup->buffer_func = pmd_src->buffer_func;
 2830     pmd_dup->pattern_size = pmd_src->pattern_size;
 2831     pmd_dup->replace_size = pmd_src->replace_size;
 2832     pmd_dup->replace_buf = pmd_src->replace_buf;
 2833     pmd_dup->pattern_buf = pmd_src->pattern_buf;
 2834     pmd_dup->search = pmd_src->search;
 2835     pmd_dup->skip_stride = pmd_src->skip_stride;
 2836     pmd_dup->shift_stride = pmd_src->shift_stride;
 2837     pmd_dup->pattern_max_jump_size = pmd_src->pattern_max_jump_size;
 2838     pmd_dup->fp = pmd_src->fp;
 2839     pmd_dup->fp_only = pmd_src->fp_only;
 2840     pmd_dup->fp_offset = pmd_src->fp_offset;
 2841     pmd_dup->fp_length = pmd_src->fp_length;
 2842     pmd_dup->pattern_type = pmd_src->pattern_type;
 2843     pmd_dup->protected_pattern = pmd_src->protected_pattern;
 2844     pmd_dup->protected_length = pmd_src->protected_length;
 2845 
 2846     pmd_dup->last_check.ts.tv_sec = pmd_src->last_check.ts.tv_sec;
 2847     pmd_dup->last_check.ts.tv_usec = pmd_src->last_check.ts.tv_usec;
 2848     pmd_dup->last_check.packet_number = pmd_src->last_check.packet_number;
 2849     pmd_dup->last_check.rebuild_flag = pmd_src->last_check.rebuild_flag;
 2850 
 2851     pmd_dup->prev = NULL;
 2852     pmd_dup->next = NULL;
 2853     pmd_dup->fpl = NULL;
 2854 
 2855     Replace_ResetOffset(pmd_dup);
 2856 }
 2857 
 2858 /* current_cursor should be the doe_ptr after this content rule option matched
 2859  * orig_cursor is the place from where we first did evaluation of this content */
 2860 int PatternMatchAdjustRelativeOffsets(PatternMatchData *orig_pmd, PatternMatchData *dup_pmd,
 2861         const uint8_t *current_cursor, const uint8_t *orig_cursor)
 2862 {
 2863     /* Adjust for repeating patterns, e.g. ABAB
 2864      * This is where the new search for this content should start */
 2865     const uint8_t *start_cursor =
 2866         (current_cursor - dup_pmd->pattern_size) + dup_pmd->pattern_max_jump_size;
 2867 
 2868     if (orig_pmd->depth != 0)
 2869     {
 2870         /* This was relative to a previously found pattern.  No space left to
 2871          * search, we're done */
 2872         if ((start_cursor + dup_pmd->pattern_size)
 2873                 > (orig_cursor + dup_pmd->offset + dup_pmd->depth))
 2874         {
 2875             return 0;
 2876         }
 2877 
 2878         /* Adjust offset and depth to reflect new position */
 2879         /* Lop off what we used */
 2880         dup_pmd->depth -= start_cursor - (orig_cursor + dup_pmd->offset);
 2881         /* Make offset where we will start the next search */
 2882         dup_pmd->offset = start_cursor - orig_cursor;
 2883     }
 2884     else if (orig_pmd->within != PMD_WITHIN_UNDEFINED)
 2885     {
 2886         /* This was relative to a previously found pattern.  No space left to
 2887          * search, we're done */
 2888         if ((start_cursor + dup_pmd->pattern_size)
 2889                 > (orig_cursor + dup_pmd->distance + dup_pmd->within))
 2890         {
 2891             return 0;
 2892         }
 2893 
 2894         /* Adjust distance and within to reflect new position */
 2895         /* Lop off what we used */
 2896         dup_pmd->within -= start_cursor - (orig_cursor + dup_pmd->distance);
 2897         /* Make distance where we will start the next search */
 2898         dup_pmd->distance = start_cursor - orig_cursor;
 2899     }
 2900     else if (orig_pmd->use_doe)
 2901     {
 2902         dup_pmd->distance = start_cursor - orig_cursor;
 2903     }
 2904     else
 2905     {
 2906         dup_pmd->offset = start_cursor - orig_cursor;
 2907     }
 2908 
 2909     return 1;
 2910 }
 2911 
 2912 #if 0
 2913 /* Not currently in use - DO NOT REMOVE */
 2914 static inline int computeDepth(int dlen, PatternMatchData * pmd)
 2915 {
 2916     /* do some tests to make sure we stay in bounds */
 2917     if((pmd->depth + pmd->offset) > dlen)
 2918     {
 2919         /* we want to check only depth bytes anyway */
 2920         int sub_depth = dlen - pmd->offset;
 2921 
 2922         if((sub_depth > 0) && (sub_depth >= (int)pmd->pattern_size))
 2923         {
 2924             return  sub_depth;
 2925         }
 2926         else
 2927         {
 2928             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 2929                         "Pattern Match failed -- sub_depth: %d < "
 2930                         "(int)pmd->pattern_size: %d!\n",
 2931                         sub_depth, (int)pmd->pattern_size););
 2932 
 2933             return -1;
 2934         }
 2935     }
 2936     else
 2937     {
 2938         if(pmd->depth && (dlen - pmd->offset > pmd->depth))
 2939         {
 2940             return pmd->depth;
 2941         }
 2942         else
 2943         {
 2944             return dlen - pmd->offset;
 2945         }
 2946     }
 2947 }
 2948 
 2949 static int uniSearchREG(char * data, int dlen, PatternMatchData * pmd)
 2950 {
 2951     int depth = computeDepth(dlen, pmd);
 2952     /* int distance_adjustment = 0;
 2953      *  int depth_adjustment = 0;
 2954      */
 2955     int success = 0;
 2956 
 2957     if (depth < 0)
 2958         return 0;
 2959 
 2960     /* XXX DESTROY ME */
 2961     /*success =  mSearchREG(data + pmd->offset + distance_adjustment,
 2962             depth_adjustment!=0?depth_adjustment:depth,
 2963             pmd->pattern_buf, pmd->pattern_size, pmd->skip_stride,
 2964             pmd->shift_stride);*/
 2965 
 2966     return success;
 2967 }
 2968 #endif
 2969 
 2970 #if 0
 2971 /* XXX Not completetly implemented */
 2972 static void PayloadSearchListInit(char *data, OptTreeNode * otn, int protocol)
 2973 {
 2974     char *sptr;
 2975     char *eptr;
 2976 
 2977     lastType = PLUGIN_PATTERN_MATCH_OR;
 2978 
 2979     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "In PayloadSearchListInit()\n"););
 2980 
 2981     /* get the path/file name from the data */
 2982     while(isspace((int) *data))
 2983         data++;
 2984 
 2985     /* grab everything between the starting " and the end one */
 2986     sptr = strchr(data, '"');
 2987     eptr = strrchr(data, '"');
 2988 
 2989     if(sptr != NULL && eptr != NULL)
 2990     {
 2991         /* increment past the first quote */
 2992         sptr++;
 2993 
 2994         /* zero out the second one */
 2995         *eptr = 0;
 2996     }
 2997     else
 2998     {
 2999         sptr = data;
 3000     }
 3001 
 3002     /* read the content keywords from the list file */
 3003     ParseContentListFile(sptr, otn, protocol);
 3004 
 3005     /* link the plugin function in to the current OTN */
 3006     AddOptFuncToList(CheckORPatternMatch, otn);
 3007 
 3008     return;
 3009 }
 3010 
 3011 /****************************************************************************
 3012  *
 3013  * Function: ParseContentListFile(char *, OptTreeNode *, int protocol)
 3014  *
 3015  * Purpose:  Read the content_list file a line at a time, put the content of
 3016  *           the line into buffer
 3017  *
 3018  * Arguments:otn => rule including the list
 3019  *           file => list file filename
 3020  *           protocol => protocol
 3021  *
 3022  * Returns: void function
 3023  *
 3024  ***************************************************************************/
 3025 static void ParseContentListFile(char *file, OptTreeNode * otn, int protocol)
 3026 {
 3027     FILE *thefp;                /* file pointer for the content_list file */
 3028     char buf[STD_BUF+1];        /* file read buffer */
 3029     char rule_buf[STD_BUF+1];   /* content keyword buffer */
 3030     int frazes_count;           /* frazes counter */
 3031 
 3032 
 3033 #ifdef DEBUG_MSGS
 3034     PatternMatchData *idx;
 3035     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Opening content_list file: %s\n", file););
 3036 #endif /* DEBUG_MSGS */
 3037     /* open the list file */
 3038     thefp = fopen(file, "r");
 3039     if (thefp == NULL)
 3040     {
 3041         ParseError("Unable to open list file: %s", file);
 3042     }
 3043 
 3044     /* clear the line and rule buffers */
 3045     memset((char *) buf, 0, STD_BUF);
 3046     memset((char *) rule_buf, 0, STD_BUF);
 3047     frazes_count = 0;
 3048 
 3049     /* loop thru each list_file line and content to the rule */
 3050     while((fgets(buf, STD_BUF-2, thefp)) != NULL)
 3051     {
 3052         /* inc the line counter */
 3053         list_file_line++;
 3054 
 3055         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Got line %d: %s",
 3056                 list_file_line, buf););
 3057 
 3058         /* if it's not a comment or a <CR>, send it to the parser */
 3059         if((buf[0] != '#') && (buf[0] != 0x0a) && (buf[0] != ';'))
 3060         {
 3061             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3062                     "Adding content keyword: %s", buf););
 3063 
 3064             frazes_count++;
 3065             strip(buf);
 3066 
 3067             NewNode(otn, PLUGIN_PATTERN_MATCH_OR);
 3068 
 3069             /* check and add content keyword */
 3070             ParsePattern(buf, otn, PLUGIN_PATTERN_MATCH_OR);
 3071 
 3072             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3073                         "Content keyword %s\" added!\n", buf););
 3074         }
 3075     }
 3076 #ifdef DEBUG_MSGS
 3077     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "%d frazes read...\n", frazes_count););
 3078     idx = (PatternMatchData *) otn->ds_list[PLUGIN_PATTERN_MATCH_OR];
 3079 
 3080     if(idx == NULL)
 3081     {
 3082         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "No patterns loaded\n"););
 3083     }
 3084     else
 3085     {
 3086         while(idx != NULL)
 3087         {
 3088             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern = %s\n",
 3089                     idx->pattern_buf););
 3090             idx = idx->next;
 3091         }
 3092     }
 3093 #endif /* DEBUG_MSGS */
 3094 
 3095     fclose(thefp);
 3096 
 3097     return;
 3098 }
 3099 
 3100 int CheckORPatternMatch(Packet * p, OptTreeNode * otn_idx, OptFpList * fp_list)
 3101 {
 3102     int found = 0;
 3103     int dsize;
 3104     char *dp;
 3105 
 3106 
 3107     PatternMatchData *idx;
 3108 
 3109     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "CheckPatternORMatch: "););
 3110 
 3111     idx = otn_idx->ds_list[PLUGIN_PATTERN_MATCH_OR];
 3112 
 3113     while(idx != NULL)
 3114     {
 3115         if (Is_DetectFlag(FLAG_ALT_DETECT) && (idx->rawbytes == 0))
 3116         {
 3117             dsize = DetectBuffer.len;
 3118             dp = (char *)DetectBufffer.data;
 3119             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3120                     "Using Alternative Detect buffer!\n"););
 3121         }
 3122         else if(Is_DetectFlag(FLAG_ALT_DECODE) && (idx->rawbytes == 0))
 3123         {
 3124             dsize = DecodeBuffer.len;
 3125             dp = (char *) DecodeBuffer.data;
 3126             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3127                                     "Using Alternative Decode buffer!\n"););
 3128         }
 3129         else
 3130         {
 3131             if(IsLimitedDetect(p))
 3132                 dsize = p->alt_dsize;
 3133             else
 3134                 dsize = p->dsize;
 3135             dp = (char *) p->data;
 3136         }
 3137 
 3138 
 3139         if(idx->offset > dsize)
 3140         {
 3141             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3142                         "Initial offset larger than payload!\n"););
 3143 
 3144             goto sizetoosmall;
 3145         }
 3146         else
 3147         {
 3148             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3149                         "testing pattern: %s\n", idx->pattern_buf););
 3150             found = idx->search(dp, dsize, idx);
 3151 
 3152             if(!found)
 3153             {
 3154                 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3155                             "Pattern Match failed!\n"););
 3156             }
 3157         }
 3158 
 3159         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3160                     "Checking the results\n"););
 3161 
 3162         if(found)
 3163         {
 3164             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Pattern Match "
 3165                     "successful: %s!\n", idx->pattern_buf););
 3166 
 3167             return fp_list->next->OptTestFunc(p, otn_idx, fp_list->next);
 3168 
 3169         }
 3170         else
 3171         {
 3172             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3173                         "Pattern match failed\n"););
 3174         }
 3175 
 3176         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3177                     "Stepping to next content keyword\n"););
 3178 
 3179     sizetoosmall:
 3180 
 3181         idx = idx->next;
 3182     }
 3183 
 3184     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
 3185                 "No more keywords, exiting... \n"););
 3186 
 3187     return 0;
 3188 }
 3189 #endif
 3190