1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2002-2013 Sourcefire, Inc.
5 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
6 **
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  ********************************************************************/
SetupPatternMatch(void)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 
PayloadSearchInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchUri(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchProtected(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 }
PayloadSearchHttpMethod(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpUri(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpHeader(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpCookie(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpBody(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpRawUri(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHttpRawHeader(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 }
PayloadSearchHttpRawCookie(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 }
PayloadSearchHttpStatCode(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 }
PayloadSearchHttpStatMsg(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
GetCMF(PatternMatchData * pmd)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 
PayloadSearchOffset(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchDepth(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchDistance(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchWithin(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchNocase(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchRawbytes(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchFastPattern(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchHash(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
PayloadSearchLength(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)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 
HasFastPattern(OptTreeNode * otn,int list_type)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 
NewNode(OptTreeNode * otn,int type)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 
PatternMatchFree(void * d)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 
ParseInt(const char * data,const char * tag)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 */
GetLastPmdError(OptTreeNode * otn,int type,const char * option)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 */
GetLastPmd(OptTreeNode * otn,int type)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 
ValidateProtectedContentModifiers(struct _SnortConfig * sc,PatternMatchData * pmd)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 */
ValidateHttpContentModifiers(struct _SnortConfig * sc,PatternMatchData * pmd)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 */
MovePmdToUriDsList(OptTreeNode * otn,PatternMatchData * pmd)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  ********************************************************************/
PatternMatchHash(void * d)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 
PatternMatchCompare(void * l,void * r)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 */
FinalizeContentUniqueness(struct _SnortConfig * sc,OptTreeNode * otn)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 
ValidateFastPattern(OptTreeNode * otn)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 
make_precomp(PatternMatchData * idx)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 
PayloadExtractParameter(char * data,int * result_len)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() */
ValidateContent(struct _SnortConfig * sc,PatternMatchData * pmd,int type)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  ***************************************************************************/
GetMaxJumpSize(char * data,int data_len)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  ***************************************************************************/
ParsePattern(char * rule,OptTreeNode * otn,int type)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 
HexToNybble(char Chr,uint8_t * Val)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 
HexToByte(char * Str,uint8_t * Val)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  ***************************************************************************/
ParseProtectedPattern(char * rule,OptTreeNode * otn,int type)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  */
uniSearchHash(const char * data,int dlen,PatternMatchData * pmd)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 
uniSearch(const char * data,int dlen,PatternMatchData * pmd)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  */
uniSearchCI(const char * data,int dlen,PatternMatchData * pmd)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  */
uniSearchReal(const char * data,int dlen,PatternMatchData * pmd,int nocase)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 
CheckANDPatternMatch(void * option_data,Packet * p)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 
CheckUriPatternMatch(void * option_data,Packet * p)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 
PatternMatchDuplicatePmd(void * src,PatternMatchData * pmd_dup)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 */
PatternMatchAdjustRelativeOffsets(PatternMatchData * orig_pmd,PatternMatchData * dup_pmd,const uint8_t * current_cursor,const uint8_t * orig_cursor)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 
3191